Skip to content

Commit 55a3b5d

Browse files
authored
Aj/migrate trace agent to axum (#719)
1 parent 2f2607d commit 55a3b5d

3 files changed

Lines changed: 381 additions & 444 deletions

File tree

bottlecap/src/bin/bottlecap/main.rs

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -460,7 +460,13 @@ async fn extension_loop_active(
460460
)));
461461

462462
let trace_aggregator = Arc::new(TokioMutex::new(trace_aggregator::TraceAggregator::default()));
463-
let (trace_agent_channel, trace_flusher, trace_processor, stats_flusher) = start_trace_agent(
463+
let (
464+
trace_agent_channel,
465+
trace_flusher,
466+
trace_processor,
467+
stats_flusher,
468+
trace_agent_shutdown_token,
469+
) = start_trace_agent(
464470
config,
465471
resolved_api_key.clone(),
466472
&tags_provider,
@@ -688,6 +694,7 @@ async fn extension_loop_active(
688694
if let Some(otlp_shutdown_token) = otlp_shutdown_token {
689695
otlp_shutdown_token.cancel();
690696
}
697+
trace_agent_shutdown_token.cancel();
691698
dogstatsd_cancel_token.cancel();
692699
telemetry_listener_cancel_token.cancel();
693700

@@ -966,6 +973,7 @@ fn start_trace_agent(
966973
Arc<trace_flusher::ServerlessTraceFlusher>,
967974
Arc<trace_processor::ServerlessTraceProcessor>,
968975
Arc<stats_flusher::ServerlessStatsFlusher>,
976+
tokio_util::sync::CancellationToken,
969977
) {
970978
// Stats
971979
let stats_aggregator = Arc::new(TokioMutex::new(StatsAggregator::default()));
@@ -997,7 +1005,7 @@ fn start_trace_agent(
9971005
resolved_api_key: resolved_api_key.clone(),
9981006
});
9991007

1000-
let trace_agent = Box::new(trace_agent::TraceAgent::new(
1008+
let trace_agent = trace_agent::TraceAgent::new(
10011009
Arc::clone(config),
10021010
trace_aggregator,
10031011
trace_processor.clone(),
@@ -1006,8 +1014,9 @@ fn start_trace_agent(
10061014
invocation_processor,
10071015
Arc::clone(tags_provider),
10081016
resolved_api_key,
1009-
));
1017+
);
10101018
let trace_agent_channel = trace_agent.get_sender_copy();
1019+
let shutdown_token = trace_agent.shutdown_token();
10111020

10121021
tokio::spawn(async move {
10131022
let res = trace_agent.start().await;
@@ -1021,6 +1030,7 @@ fn start_trace_agent(
10211030
trace_flusher,
10221031
trace_processor,
10231032
stats_flusher,
1033+
shutdown_token,
10241034
)
10251035
}
10261036

bottlecap/src/traces/stats_processor.rs

Lines changed: 52 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -4,26 +4,30 @@
44
use std::time::{SystemTime, UNIX_EPOCH};
55

66
use async_trait::async_trait;
7-
use ddcommon::hyper_migration;
8-
use hyper::{http, StatusCode};
7+
use axum::{
8+
extract::Request,
9+
http::StatusCode,
10+
response::{IntoResponse, Response},
11+
};
912
use tokio::sync::mpsc::Sender;
10-
use tracing::debug;
13+
use tracing::{debug, error};
1114

1215
use datadog_trace_protobuf::pb;
1316
use datadog_trace_utils::stats_utils;
17+
use ddcommon::hyper_migration;
1418

1519
use super::trace_agent::MAX_CONTENT_LENGTH;
16-
use datadog_trace_agent::http_utils::{self, log_and_create_http_response};
20+
use crate::http::extract_request_body;
1721

1822
#[async_trait]
1923
pub trait StatsProcessor {
20-
/// Deserializes trace stats from a hyper request body and sends them through
24+
/// Deserializes trace stats from a request body and sends them through
2125
/// the provided tokio mpsc Sender.
2226
async fn process_stats(
2327
&self,
24-
req: hyper_migration::HttpRequest,
28+
req: Request,
2529
tx: Sender<pb::ClientStatsPayload>,
26-
) -> http::Result<hyper_migration::HttpResponse>;
30+
) -> Result<Response, Box<dyn std::error::Error + Send + Sync>>;
2731
}
2832

2933
#[derive(Clone, Copy)]
@@ -34,30 +38,43 @@ pub struct ServerlessStatsProcessor {}
3438
impl StatsProcessor for ServerlessStatsProcessor {
3539
async fn process_stats(
3640
&self,
37-
req: hyper_migration::HttpRequest,
41+
req: Request,
3842
tx: Sender<pb::ClientStatsPayload>,
39-
) -> http::Result<hyper_migration::HttpResponse> {
43+
) -> Result<Response, Box<dyn std::error::Error + Send + Sync>> {
4044
debug!("Received trace stats to process");
41-
let (parts, body) = req.into_parts();
45+
let (parts, body) = match extract_request_body(req).await {
46+
Ok(r) => r,
47+
Err(e) => {
48+
let error_msg = format!("Error extracting request body: {e}");
49+
error!("{}", error_msg);
50+
return Ok((StatusCode::BAD_REQUEST, error_msg).into_response());
51+
}
52+
};
4253

43-
if let Some(response) = http_utils::verify_request_content_length(
44-
&parts.headers,
45-
MAX_CONTENT_LENGTH,
46-
"Error processing trace stats",
47-
) {
48-
return response;
54+
if let Some(content_length) = parts.headers.get("content-length") {
55+
if let Ok(length_str) = content_length.to_str() {
56+
if let Ok(length) = length_str.parse::<usize>() {
57+
if length > MAX_CONTENT_LENGTH {
58+
let error_msg = format!("Content-Length {length} exceeds maximum allowed size {MAX_CONTENT_LENGTH}");
59+
error!("{}", error_msg);
60+
return Ok((StatusCode::PAYLOAD_TOO_LARGE, error_msg).into_response());
61+
}
62+
}
63+
}
4964
}
5065

5166
// deserialize trace stats from the request body, convert to protobuf structs (see
5267
// trace-protobuf crate)
5368
let mut stats: pb::ClientStatsPayload =
54-
match stats_utils::get_stats_from_request_body(body).await {
69+
match stats_utils::get_stats_from_request_body(hyper_migration::Body::from_bytes(body))
70+
.await
71+
{
5572
Ok(result) => result,
5673
Err(err) => {
57-
return log_and_create_http_response(
58-
&format!("Error deserializing trace stats from request body: {err}"),
59-
StatusCode::INTERNAL_SERVER_ERROR,
60-
);
74+
let error_msg =
75+
format!("Error deserializing trace stats from request body: {err}");
76+
error!("{}", error_msg);
77+
return Ok((StatusCode::INTERNAL_SERVER_ERROR, error_msg).into_response());
6178
}
6279
};
6380

@@ -66,29 +83,28 @@ impl StatsProcessor for ServerlessStatsProcessor {
6683
.duration_since(UNIX_EPOCH)
6784
.unwrap_or_default()
6885
.as_nanos();
69-
stats.stats[0].start = match u64::try_from(timestamp) {
70-
Ok(result) => result,
71-
Err(_) => {
72-
return log_and_create_http_response(
73-
"Error converting timestamp to u64",
74-
StatusCode::INTERNAL_SERVER_ERROR,
75-
);
76-
}
86+
stats.stats[0].start = if let Ok(result) = u64::try_from(timestamp) {
87+
result
88+
} else {
89+
let error_msg = "Error converting timestamp to u64";
90+
error!("{}", error_msg);
91+
return Ok((StatusCode::INTERNAL_SERVER_ERROR, error_msg).into_response());
7792
};
7893

7994
// send trace payload to our trace flusher
8095
match tx.send(stats).await {
8196
Ok(()) => {
82-
return log_and_create_http_response(
83-
"Successfully buffered stats to be flushed.",
97+
debug!("Successfully buffered stats to be flushed.");
98+
Ok((
8499
StatusCode::ACCEPTED,
85-
);
100+
"Successfully buffered stats to be flushed.",
101+
)
102+
.into_response())
86103
}
87104
Err(err) => {
88-
return log_and_create_http_response(
89-
&format!("Error sending stats to the stats flusher: {err}"),
90-
StatusCode::INTERNAL_SERVER_ERROR,
91-
);
105+
let error_msg = format!("Error sending stats to the stats flusher: {err}");
106+
error!("{}", error_msg);
107+
Ok((StatusCode::INTERNAL_SERVER_ERROR, error_msg).into_response())
92108
}
93109
}
94110
}

0 commit comments

Comments
 (0)