Skip to content

Commit 0b25a69

Browse files
committed
fix: adapt bottlecap to libdatadog v32.0.0 breaking changes
Adopts the new HttpClientTrait architecture from libdatadog v32.0.0 (PR DataDog/libdatadog#1555) and the restructured ObfuscationConfig. - Wraps the proxy/TLS-aware hyper client in a struct that implements libdd_capabilities::HttpClientTrait so it can be passed to SendData::send and other libdd-trace-utils APIs. - Replaces the removed stats_utils::send_stats_payload_with_client with an inline POST helper that reuses the configured client, preserving Lambda's pool_max_idle_per_host(0) tuning, proxy, and custom CA support. - Updates obfuscation_config::ObfuscationConfig construction for the new nested HttpConfig/MemcachedConfig/RedisConfig layout. - Adds libdd-capabilities and http as direct dependencies.
1 parent ac7f5c4 commit 0b25a69

6 files changed

Lines changed: 118 additions & 17 deletions

File tree

bottlecap/Cargo.lock

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

bottlecap/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ chrono = { version = "0.4", features = ["serde", "std", "now"], default-features
1212
cookie = { version = "0.18", default-features = false }
1313
figment = { version = "0.10", default-features = false, features = ["yaml", "env"] }
1414
fnv = { version = "1.0", default-features = false }
15+
http = { version = "1" }
1516
hyper = { version = "1.6", default-features = false, features = ["server"] }
1617
hyper-util = { version = "0.1.16", features = ["http1", "client", "client-legacy"] }
1718
http-body = { version = "1", default-features = false }
@@ -73,6 +74,7 @@ indexmap = {version = "2.11.0", default-features = false}
7374
# be found in the clippy.toml file adjacent to this Cargo.toml.
7475
datadog-protos = { version = "0.1.0", default-features = false, git = "https://github.com/DataDog/saluki/", rev = "f863626dbfe3c59bb390985fa6530b0621c2a0a2"}
7576
ddsketch-agent = { version = "0.1.0", default-features = false, git = "https://github.com/DataDog/saluki/", rev = "f863626dbfe3c59bb390985fa6530b0621c2a0a2"}
77+
libdd-capabilities = { git = "https://github.com/DataDog/libdatadog", rev = "989e11a2bfe68ae669493d726262c424e2cc04a9" }
7678
libdd-common = { git = "https://github.com/DataDog/libdatadog", rev = "989e11a2bfe68ae669493d726262c424e2cc04a9" }
7779
libdd-trace-protobuf = { git = "https://github.com/DataDog/libdatadog", rev = "989e11a2bfe68ae669493d726262c424e2cc04a9" }
7880
libdd-trace-utils = { git = "https://github.com/DataDog/libdatadog", rev = "989e11a2bfe68ae669493d726262c424e2cc04a9" , features = ["mini_agent"] }

bottlecap/LICENSE-3rdparty.csv

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ bit-set,https://github.com/contain-rs/bit-set,Apache-2.0 OR MIT,Alexis Beingessn
1919
bit-vec,https://github.com/contain-rs/bit-vec,Apache-2.0 OR MIT,Alexis Beingessner <a.beingessner@gmail.com>
2020
bitflags,https://github.com/bitflags/bitflags,MIT OR Apache-2.0,The Rust Project Developers
2121
block-buffer,https://github.com/RustCrypto/utils,MIT OR Apache-2.0,RustCrypto Developers
22+
borrow-or-share,https://github.com/yescallop/borrow-or-share,MIT-0,Scallop Ye <yescallop@gmail.com>
2223
buf_redux,https://github.com/abonander/buf_redux,MIT OR Apache-2.0,Austin Bonander <austin.bonander@gmail.com>
2324
bumpalo,https://github.com/fitzgen/bumpalo,MIT OR Apache-2.0,Nick Fitzgerald <fitzgen@gmail.com>
2425
bytemuck,https://github.com/Lokathor/bytemuck,Zlib OR Apache-2.0 OR MIT,Lokathor <zefria@gmail.com>
@@ -57,6 +58,7 @@ figment,https://github.com/SergioBenitez/Figment,MIT OR Apache-2.0,Sergio Benite
5758
find-msvc-tools,https://github.com/rust-lang/cc-rs,MIT OR Apache-2.0,The find-msvc-tools Authors
5859
flate2,https://github.com/rust-lang/flate2-rs,MIT OR Apache-2.0,"Alex Crichton <alex@alexcrichton.com>, Josh Triplett <josh@joshtriplett.org>"
5960
float-cmp,https://github.com/mikedilger/float-cmp,MIT,Mike Dilger <mike@mikedilger.com>
61+
fluent-uri,https://github.com/yescallop/fluent-uri-rs,MIT,Scallop Ye <yescallop@gmail.com>
6062
fnv,https://github.com/servo/rust-fnv,Apache-2.0 OR MIT,Alex Crichton <alex@alexcrichton.com>
6163
foldhash,https://github.com/orlp/foldhash,Zlib,Orson Peters <orsonpeters@gmail.com>
6264
form_urlencoded,https://github.com/servo/rust-url,MIT OR Apache-2.0,The rust-url developers
@@ -109,10 +111,13 @@ js-sys,https://github.com/wasm-bindgen/wasm-bindgen/tree/master/crates/js-sys,MI
109111
lazy_static,https://github.com/rust-lang-nursery/lazy-static.rs,MIT OR Apache-2.0,Marvin Löbel <loebel.marvin@gmail.com>
110112
leb128fmt,https://github.com/bluk/leb128fmt,MIT OR Apache-2.0,Bryant Luk <code@bryantluk.com>
111113
libc,https://github.com/rust-lang/libc,MIT OR Apache-2.0,The Rust Project Developers
114+
libdd-capabilities,https://github.com/DataDog/libdatadog/tree/main/libdd-capabilities,Apache-2.0,The libdd-capabilities Authors
115+
libdd-capabilities-impl,https://github.com/DataDog/libdatadog/tree/main/libdd-capabilities-impl,Apache-2.0,The libdd-capabilities-impl Authors
112116
libdd-common,https://github.com/DataDog/libdatadog/tree/main/datadog-common,Apache-2.0,The libdd-common Authors
113117
libdd-data-pipeline,https://github.com/DataDog/libdatadog/tree/main/libdd-data-pipeline,Apache-2.0,The libdd-data-pipeline Authors
114118
libdd-ddsketch,https://github.com/DataDog/libdatadog/tree/main/libdd-ddsketch,Apache-2.0,The libdd-ddsketch Authors
115119
libdd-dogstatsd-client,https://github.com/DataDog/libdatadog/tree/main/libdd-dogstatsd-client,Apache-2.0,The libdd-dogstatsd-client Authors
120+
libdd-shared-runtime,https://github.com/DataDog/libdatadog/tree/main/libdd-shared-runtime,Apache-2.0,The libdd-shared-runtime Authors
116121
libdd-telemetry,https://github.com/DataDog/libdatadog/tree/main/libdd-telemetry,Apache-2.0,The libdd-telemetry Authors
117122
libdd-tinybytes,https://github.com/DataDog/libdatadog/tree/main/libdd-tinybytes,Apache-2.0,The libdd-tinybytes Authors
118123
libdd-trace-normalization,https://github.com/DataDog/libdatadog/tree/main/libdd-trace-normalization,Apache-2.0,David Lee <david.lee@datadoghq.com>
@@ -179,6 +184,8 @@ rand_chacha,https://github.com/rust-random/rand,MIT OR Apache-2.0,"The Rand Proj
179184
rand_core,https://github.com/rust-random/rand,MIT OR Apache-2.0,"The Rand Project Developers, The Rust Project Developers"
180185
rand_xorshift,https://github.com/rust-random/rngs,MIT OR Apache-2.0,"The Rand Project Developers, The Rust Project Developers"
181186
redox_syscall,https://gitlab.redox-os.org/redox-os/syscall,MIT,Jeremy Soller <jackpot51@gmail.com>
187+
ref-cast,https://github.com/dtolnay/ref-cast,MIT OR Apache-2.0,David Tolnay <dtolnay@gmail.com>
188+
ref-cast-impl,https://github.com/dtolnay/ref-cast,MIT OR Apache-2.0,David Tolnay <dtolnay@gmail.com>
182189
regex,https://github.com/rust-lang/regex,MIT OR Apache-2.0,"The Rust Project Developers, Andrew Gallant <jamslam@gmail.com>"
183190
regex-automata,https://github.com/rust-lang/regex,MIT OR Apache-2.0,"The Rust Project Developers, Andrew Gallant <jamslam@gmail.com>"
184191
regex-syntax,https://github.com/rust-lang/regex,MIT OR Apache-2.0,"The Rust Project Developers, Andrew Gallant <jamslam@gmail.com>"

bottlecap/src/bin/bottlecap/main.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1148,11 +1148,11 @@ fn start_trace_agent(
11481148

11491149
let obfuscation_config = obfuscation_config::ObfuscationConfig {
11501150
tag_replace_rules: config.apm_replace_tags.clone(),
1151-
http_remove_path_digits: config.apm_config_obfuscation_http_remove_paths_with_digits,
1152-
http_remove_query_string: config.apm_config_obfuscation_http_remove_query_string,
1153-
obfuscate_memcached: false,
1154-
obfuscation_redis_enabled: false,
1155-
obfuscation_redis_remove_all_args: false,
1151+
http: obfuscation_config::HttpConfig {
1152+
remove_paths_with_digits: config.apm_config_obfuscation_http_remove_paths_with_digits,
1153+
remove_query_string: config.apm_config_obfuscation_http_remove_query_string,
1154+
},
1155+
..Default::default()
11561156
};
11571157

11581158
let trace_processor = Arc::new(trace_processor::ServerlessTraceProcessor {

bottlecap/src/traces/http_client.rs

Lines changed: 67 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,23 +6,79 @@
66
//! This module provides the HTTP client type required by `libdd_trace_utils`
77
//! for sending traces and stats to Datadog intake endpoints.
88
9+
use http_body_util::BodyExt;
910
use hyper_http_proxy;
1011
use hyper_rustls::HttpsConnectorBuilder;
11-
use libdd_common::{GenericHttpClient, http_common};
12+
use libdd_capabilities::{
13+
MaybeSend,
14+
http::{HttpClientTrait, HttpError},
15+
};
16+
use libdd_common::http_common::{self, Body, GenericHttpClient};
1217
use rustls::RootCertStore;
1318
use rustls_pki_types::CertificateDer;
1419
use std::error::Error;
1520
use std::fs::File;
21+
use std::future::Future;
1622
use std::io::BufReader;
1723
use std::sync::{Arc, LazyLock};
1824
use tracing::debug;
1925

20-
/// Type alias for the HTTP client used by trace and stats flushers.
21-
///
22-
/// This is the client type expected by `libdd_trace_utils::SendData::send()`.
23-
pub type HttpClient =
26+
type InnerClient =
2427
GenericHttpClient<hyper_http_proxy::ProxyConnector<libdd_common::connector::Connector>>;
2528

29+
/// HTTP client used by trace and stats flushers.
30+
///
31+
/// Wraps a hyper client preconfigured with optional proxy and TLS settings, and
32+
/// implements [`HttpClientTrait`] so it can be passed to `libdd_trace_utils`
33+
/// senders such as `SendData::send`.
34+
#[derive(Clone, Debug)]
35+
pub struct HttpClient {
36+
inner: InnerClient,
37+
}
38+
39+
impl HttpClient {
40+
fn new(inner: InnerClient) -> Self {
41+
Self { inner }
42+
}
43+
}
44+
45+
impl HttpClientTrait for HttpClient {
46+
fn new_client() -> Self {
47+
// Used by libdd APIs that construct a default client when no
48+
// pre-configured one is supplied. Bottlecap's production code paths
49+
// build the client via `create_client` so this fallback only matches
50+
// libdatadog's `new_default_client` shape.
51+
let connector = libdd_common::connector::Connector::default();
52+
let proxy_connector = hyper_http_proxy::ProxyConnector::new(connector)
53+
.expect("failed to build default proxy connector");
54+
let inner = http_common::client_builder()
55+
.pool_max_idle_per_host(0)
56+
.build(proxy_connector);
57+
HttpClient { inner }
58+
}
59+
60+
fn request(
61+
&self,
62+
req: http::Request<bytes::Bytes>,
63+
) -> impl Future<Output = Result<http::Response<bytes::Bytes>, HttpError>> + MaybeSend {
64+
let client = self.inner.clone();
65+
async move {
66+
let hyper_req = req.map(Body::from_bytes);
67+
let response = client
68+
.request(hyper_req)
69+
.await
70+
.map_err(|e| HttpError::Network(e.into()))?;
71+
let (parts, body) = response.into_parts();
72+
let collected = body
73+
.collect()
74+
.await
75+
.map_err(|e| HttpError::ResponseBody(e.into()))?
76+
.to_bytes();
77+
Ok(http::Response::from_parts(parts, collected))
78+
}
79+
}
80+
}
81+
2682
/// Initialize the crypto provider needed for setting custom root certificates.
2783
fn ensure_crypto_provider_initialized() {
2884
static INIT_CRYPTO_PROVIDER: LazyLock<()> = LazyLock::new(|| {
@@ -185,13 +241,15 @@ pub fn create_client(
185241
"HTTP_CLIENT | Proxy connector created with proxy: {:?}",
186242
proxy_https
187243
);
188-
Ok(client)
244+
Ok(HttpClient::new(client))
189245
} else {
190246
let proxy_connector = hyper_http_proxy::ProxyConnector::new(connector)?;
191247
// Disable connection pooling to avoid stale connections after Lambda freeze/resume.
192248
// See comment above for detailed explanation.
193-
Ok(http_common::client_builder()
194-
.pool_max_idle_per_host(0)
195-
.build(proxy_connector))
249+
Ok(HttpClient::new(
250+
http_common::client_builder()
251+
.pool_max_idle_per_host(0)
252+
.build(proxy_connector),
253+
))
196254
}
197255
}

bottlecap/src/traces/stats_flusher.rs

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@ use crate::config;
1111
use crate::lifecycle::invocation::processor::S_TO_MS;
1212
use crate::traces::http_client::HttpClient;
1313
use crate::traces::stats_aggregator::StatsAggregator;
14+
use bytes::Bytes;
1415
use dogstatsd::api_key::ApiKeyFactory;
16+
use libdd_capabilities::http::HttpClientTrait;
1517
use libdd_common::Endpoint;
1618
use libdd_trace_protobuf::pb;
1719
use libdd_trace_utils::{config_utils::trace_stats_url, stats_utils};
@@ -96,11 +98,11 @@ impl StatsFlusher {
9698

9799
for attempt in 1..=FLUSH_RETRY_COUNT {
98100
let start = std::time::Instant::now();
99-
let resp = stats_utils::send_stats_payload_with_client(
100-
serialized_stats_payload.clone(),
101+
let resp = send_stats_payload(
102+
&self.http_client,
101103
endpoint,
102104
api_key.as_str(),
103-
Some(&self.http_client),
105+
serialized_stats_payload.clone(),
104106
)
105107
.await;
106108
let elapsed = start.elapsed();
@@ -167,3 +169,33 @@ impl StatsFlusher {
167169
}
168170
}
169171
}
172+
173+
/// Posts a serialized stats payload using the supplied client.
174+
///
175+
/// Equivalent to libdatadog's `stats_utils::send_stats_payload`, but uses the
176+
/// caller-provided client so bottlecap's proxy/TLS configuration is preserved.
177+
async fn send_stats_payload(
178+
client: &HttpClient,
179+
target: &Endpoint,
180+
api_key: &str,
181+
data: Vec<u8>,
182+
) -> anyhow::Result<()> {
183+
let req = http::Request::builder()
184+
.method(http::Method::POST)
185+
.uri(target.url.clone())
186+
.header("Content-Type", "application/msgpack")
187+
.header("Content-Encoding", "gzip")
188+
.header("DD-API-KEY", api_key)
189+
.body(Bytes::from(data))?;
190+
191+
let response = client
192+
.request(req)
193+
.await
194+
.map_err(|e| anyhow::anyhow!("Failed to send trace stats: {e}"))?;
195+
196+
if response.status() != http::StatusCode::ACCEPTED {
197+
let response_body = String::from_utf8(response.into_body().to_vec()).unwrap_or_default();
198+
anyhow::bail!("Server did not accept trace stats: {response_body}");
199+
}
200+
Ok(())
201+
}

0 commit comments

Comments
 (0)