Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
a9251df
feat(telemetry): make telemetry stuff wasm capable for traceexporter
Aaalibaba42 Jun 29, 2026
800823d
revert: crashtracker is native, use tokio timeout again instead of ca…
Aaalibaba42 Jul 1, 2026
fa53c71
fix(trace_exporter): log if telemetry fails instead of just silencing it
Aaalibaba42 Jul 1, 2026
2f63fe1
chore: move 'use' statements to top of the file
Aaalibaba42 Jul 1, 2026
cb8ddeb
docs: unclutter
Aaalibaba42 Jul 2, 2026
c5b608f
chore: remove from wasm codepath that was never actually utilized
Aaalibaba42 Jul 2, 2026
05b4735
feat: shutdown is not really used by wasm, so we may gate it out
Aaalibaba42 Jul 2, 2026
74adfb8
revert: old way of shutdown workers for native, keep new way for wasm
Aaalibaba42 Jul 2, 2026
9b6dbd9
Merge branch 'main' into jwiriath/telemetry-wasm
Aaalibaba42 Jul 2, 2026
b7acc91
feat(css): enabled for wasm
Aaalibaba42 Jun 29, 2026
96930b6
docs: useless doc
Aaalibaba42 Jul 2, 2026
d7aa577
feat(css)!: enabled for wasm (#2173)
Aaalibaba42 Jul 2, 2026
b3aef55
fix: init in the async block only for file://
Aaalibaba42 Jul 3, 2026
f6cecb9
docs: shorten and straighter to the point
Aaalibaba42 Jul 6, 2026
cf5b876
feat(shutdown_workers): both targets use FuturesUnordered instead of …
Aaalibaba42 Jul 6, 2026
7846115
Merge branch 'main' into jwiriath/telemetry-wasm
Aaalibaba42 Jul 6, 2026
ef5395e
Merge branch 'main' into jwiriath/telemetry-wasm
ekump Jul 18, 2026
bc57217
set force-unwind-table to avoid infinite loop in backtrace unwinder
ekump Jul 18, 2026
19987a1
fix clippy warnings
ekump Jul 18, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 20 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions LICENSE-3rdparty.csv
Original file line number Diff line number Diff line change
Expand Up @@ -498,6 +498,7 @@ wasm-bindgen-macro,https://github.com/rustwasm/wasm-bindgen/tree/master/crates/m
wasm-bindgen-macro-support,https://github.com/rustwasm/wasm-bindgen/tree/master/crates/macro-support,MIT OR Apache-2.0,The wasm-bindgen Developers
wasm-bindgen-shared,https://github.com/rustwasm/wasm-bindgen/tree/master/crates/shared,MIT OR Apache-2.0,The wasm-bindgen Developers
web-sys,https://github.com/rustwasm/wasm-bindgen/tree/master/crates/web-sys,MIT OR Apache-2.0,The wasm-bindgen Developers
web-time,https://github.com/daxpedda/web-time,MIT OR Apache-2.0,The web-time Authors
webpki-root-certs,https://github.com/rustls/webpki-roots,CDLA-Permissive-2.0,The webpki-root-certs Authors
webpki-roots,https://github.com/rustls/webpki-roots,CDLA-Permissive-2.0,The webpki-roots Authors
widestring,https://github.com/VoidStarKat/widestring-rs,MIT OR Apache-2.0,The widestring Authors
Expand Down
13 changes: 11 additions & 2 deletions bin_tests/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,11 +136,20 @@ fn cargo_build_artifact(c: &ArtifactsBuild) -> anyhow::Result<PathBuf> {
};

if c.panic_abort == Some(true) {
// `-C panic=abort` suppresses `.eh_frame` unwind tables, which the aarch64
// backtrace unwinder relies on; without them `RUST_BACKTRACE` can loop forever
// on certain binary layouts (rust-lang/rust#123733), hanging the test until the
// runner OOMs. Force the tables back on so backtraces terminate. This is
// layout-sensitive, so it can appear/disappear across unrelated changes; keep
// until #123733 (fix: rust-lang/rust#143613) ships in a stable toolchain.
let existing_rustflags = std::env::var("RUSTFLAGS").unwrap_or_default();
let new_rustflags = if existing_rustflags.is_empty() {
"-C panic=abort".to_string()
"-C panic=abort -C force-unwind-tables=yes".to_string()
} else {
format!("{} -C panic=abort", existing_rustflags)
format!(
"{} -C panic=abort -C force-unwind-tables=yes",
existing_rustflags
)
};
build_cmd.env("RUSTFLAGS", new_rustflags);
}
Expand Down
11 changes: 7 additions & 4 deletions datadog-sidecar/src/self_telemetry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,15 @@ use crate::config::Config;
use crate::log;
use crate::service::SidecarServer;
use crate::watchdog::WatchdogHandle;
use libdd_capabilities_impl::NativeCapabilities;
use libdd_common::{tag, tag::Tag, MutexExt};
use libdd_telemetry::data::metrics::{MetricNamespace, MetricType};
use libdd_telemetry::metrics::ContextKey;
use libdd_telemetry::worker::{
LifecycleAction, TelemetryActions, TelemetryWorkerBuilder, TelemetryWorkerHandle,
};
use libdd_telemetry::worker::{LifecycleAction, TelemetryActions, TelemetryWorkerBuilder};

/// The sidecar runs the telemetry worker on native, so its handle is pinned to
/// [`NativeCapabilities`].
type TelemetryWorkerHandle = libdd_telemetry::worker::TelemetryWorkerHandle<NativeCapabilities>;
use manual_future::ManualFuture;
use std::sync::atomic::{AtomicU64, Ordering};
use std::time::Duration;
Expand Down Expand Up @@ -205,7 +208,7 @@ impl SelfTelemetry {
crate::sidecar_version!().to_string(),
);
builder.config = self.config.clone();
let (worker, join_handle) = builder.spawn();
let (worker, join_handle) = builder.spawn::<NativeCapabilities>();

let metrics = MetricData {
worker: &worker,
Expand Down
4 changes: 3 additions & 1 deletion datadog-sidecar/src/service/stats_flusher.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@ use http::uri::PathAndQuery;
use libdd_capabilities_impl::{HttpClientCapability, NativeCapabilities};
use libdd_common::{Endpoint, MutexExt};
use libdd_telemetry::config::Config;
use libdd_telemetry::worker::TelemetryWorkerHandle;
/// Sidecar's telemetry worker is native-only, so its handle is pinned to
/// [`NativeCapabilities`].
type TelemetryWorkerHandle = libdd_telemetry::worker::TelemetryWorkerHandle<NativeCapabilities>;
use libdd_trace_stats::stats_exporter::{StatsExporter, StatsMetadata};
use std::collections::HashMap;
use std::ffi::CString;
Expand Down
7 changes: 6 additions & 1 deletion datadog-sidecar/src/service/telemetry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ use std::time::{Duration, Instant};
use tokio::task::JoinHandle;
use zwohash::ZwoHasher;

use libdd_capabilities_impl::NativeCapabilities;
use libdd_common::tag::Tag;
use libdd_telemetry::worker::TelemetryWorkerBuilder;
use serde::{Deserialize, Serialize};
Expand All @@ -33,7 +34,11 @@ use std::time::SystemTime;
use libdd_telemetry::config::Config;
use libdd_telemetry::data::{self, Integration};
use libdd_telemetry::metrics::{ContextKey, MetricContext};
use libdd_telemetry::worker::{LifecycleAction, TelemetryActions, TelemetryWorkerHandle};
use libdd_telemetry::worker::{LifecycleAction, TelemetryActions};

/// Sidecar's telemetry worker is native-only, so its handle is pinned to
/// [`NativeCapabilities`].
type TelemetryWorkerHandle = libdd_telemetry::worker::TelemetryWorkerHandle<NativeCapabilities>;
use manual_future::ManualFuture;
use serde_with::{serde_as, VecSkipError};
use tokio::time::{sleep, sleep_until, Instant as TokioInstant};
Expand Down
35 changes: 34 additions & 1 deletion libdd-capabilities-impl/src/http.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
//! Native HTTP client implementation backed by hyper.

mod native {
use std::fs::OpenOptions;
use std::io::Write;
use std::sync::{Arc, OnceLock};

use libdd_capabilities::http::{HttpClientCapability, HttpError};
Expand All @@ -26,6 +28,30 @@ mod native {
}
}

/// Write `body` as a newline-terminated record to the file referenced by `uri` (which must
/// have a `file://` scheme), then return a synthetic 202 response.
fn write_to_file_endpoint(
uri: &http::Uri,
body: bytes::Bytes,
) -> Result<http::Response<bytes::Bytes>, HttpError> {
let path = libdd_common::decode_uri_path_in_authority(uri)
.map_err(|e| HttpError::Other(anyhow::anyhow!("invalid file:// URI: {e}")))?;
let mut file = OpenOptions::new()
.create(true)
.append(true)
.open(&path)
.map_err(|e| HttpError::Other(anyhow::anyhow!("opening {path:?}: {e}")))?;
let mut record = body.to_vec();
record.push(b'\n');
file.write_all(&record)
.map_err(|e| HttpError::Other(anyhow::anyhow!("writing {path:?}: {e}")))?;

http::Response::builder()
.status(http::StatusCode::ACCEPTED)
.body(bytes::Bytes::new())
.map_err(|e| HttpError::Other(e.into()))
}

impl HttpClientCapability for NativeHttpClient {
fn new_client() -> Self {
Self {
Expand All @@ -39,8 +65,15 @@ mod native {
req: http::Request<bytes::Bytes>,
) -> impl std::future::Future<Output = Result<http::Response<bytes::Bytes>, HttpError>> + MaybeSend
{
let client = self.client.get_or_init(new_default_client).clone();
let client_lock = self.client.clone();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this should not be cloned, but just shared as a reference instead. This probably duplicate the OnceLock and thus always create a client from scratch

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's an Arc, so it shouldn't

async move {
// file:// URIs short-circuit to the on-disk recorder used by tests.
if req.uri().scheme_str() == Some("file") {
let (parts, body) = req.into_parts();
return write_to_file_endpoint(&parts.uri, body);
}
Comment thread
Aaalibaba42 marked this conversation as resolved.

let client = client_lock.get_or_init(new_default_client).clone();
let hyper_req = req.map(Body::from_bytes);

let response = client
Expand Down
2 changes: 2 additions & 0 deletions libdd-crashtracker/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ anyhow = "1.0"
chrono = {version = "0.4", default-features = false, features = ["std", "clock", "serde"]}
cxx = { version = "1.0", optional = true }
errno = "0.3"
libdd-capabilities = { version = "2.1.0", path = "../libdd-capabilities" }
libdd-capabilities-impl = { version = "3.0.0", path = "../libdd-capabilities-impl" }
libdd-common = { version = "5.1.0", path = "../libdd-common" }
libdd-telemetry = { version = "6.0.0", path = "../libdd-telemetry" }
http = "1.1"
Expand Down
33 changes: 18 additions & 15 deletions libdd-crashtracker/src/crash_info/telemetry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ use crate::{ErrorKind, SigInfo};
use super::{CrashInfo, Metadata, TARGET_TRIPLE};
use anyhow::Context;
use chrono::{DateTime, Utc};
use libdd_capabilities::HttpClientCapability;
use libdd_capabilities_impl::NativeCapabilities;
use libdd_common::Endpoint;
use libdd_telemetry::{
build_host,
Expand Down Expand Up @@ -355,9 +357,9 @@ impl TelemetryCrashUploader {
self.send_telemetry_payload(&payload).await
}

/// Helper to perform actual HTTP (or file) submission via configured telemetry client
/// Helper to perform actual HTTP submission via the native HTTP capability.
async fn send_telemetry_payload(&self, payload: &data::Telemetry<'_>) -> anyhow::Result<()> {
let client = libdd_telemetry::worker::http_client::from_config(&self.cfg);
let client = NativeCapabilities::new_client();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we properly propagate configuration from self.cfg to the HTTP client now? Not sure what can be there.

let req = request_builder(&self.cfg)?
.method(http::Method::POST)
.header(
Expand All @@ -372,19 +374,20 @@ impl TelemetryCrashUploader {
libdd_telemetry::worker::http_client::header::REQUEST_TYPE,
"logs",
)
.body(serde_json::to_string(&payload)?.into())?;

tokio::time::timeout(
core::time::Duration::from_millis({
if let Some(endp) = self.cfg.endpoint() {
endp.timeout_ms
} else {
Endpoint::DEFAULT_TIMEOUT
}
}),
client.request(req),
)
.await??;
.body(libdd_capabilities::Bytes::from(serde_json::to_vec(
&payload,
)?))?;

let timeout = core::time::Duration::from_millis({
if let Some(endp) = self.cfg.endpoint() {
endp.timeout_ms
} else {
Endpoint::DEFAULT_TIMEOUT
}
});
Comment on lines +381 to +387

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
let timeout = core::time::Duration::from_millis({
if let Some(endp) = self.cfg.endpoint() {
endp.timeout_ms
} else {
Endpoint::DEFAULT_TIMEOUT
}
});
let timeout = core::time::Duration::from_millis(
self.cfg
.endpoint()
.map(|endp| endp.timeout_ms)
.unwrap_or(Endpoint::DEFAULT_TIMEOUT));

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think I'd make another PR for styling like that, but it definitely would have been good

tokio::time::timeout(timeout, client.request(req))
.await
.map_err(|_| anyhow::anyhow!("Telemetry crash report timed out"))??;

Ok(())
}
Expand Down
2 changes: 2 additions & 0 deletions libdd-data-pipeline/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ serde_json = "1.0.127"
bytes = "1.11.1"
sha2 = "0.10"
either = "1.13.0"
futures = { version = "0.3", default-features = false, features = ["alloc"] }

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we use this for FuturesUnordered? Was the previous join not enough/wrong for some reason?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was not usable with wasm because it spawned threads

tokio = { version = "1.23", features = [
"rt",
"sync",
Expand All @@ -46,6 +47,7 @@ libdd-tinybytes = { version = "1.1.1", path = "../libdd-tinybytes", features = [
"bytes_string",
"serialization",
] }
web-time = "1"

[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
tokio = { version = "1.23", features = ["time", "test-util"], default-features = false }
Expand Down
3 changes: 2 additions & 1 deletion libdd-data-pipeline/src/otlp/metrics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,9 @@ use libdd_trace_utils::otlp_encoder::mapper::status_code;
use libdd_trace_utils::otlp_encoder::OtlpResourceInfo;
use serde_json::{json, Value};
use std::sync::{Arc, Mutex};
use std::time::{Duration, SystemTime};
use std::time::Duration;
use tracing::error;
use web_time::SystemTime;

const METRIC_NAME: &str = "traces.span.sdk.metrics.duration";
const NANOS_PER_SECOND: f64 = 1_000_000_000.0;
Expand Down
8 changes: 6 additions & 2 deletions libdd-data-pipeline/src/telemetry/metrics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// SPDX-License-Identifier: Apache-2.0

//! Provides an abstraction layer to hold metrics that comes from 'SendDataResult'.
use libdd_capabilities::{HttpClientCapability, MaybeSend, SleepCapability};
use libdd_common::tag;
use libdd_telemetry::data::metrics::{MetricNamespace, MetricType};
use libdd_telemetry::metrics::ContextKey;
Expand Down Expand Up @@ -146,7 +147,9 @@ impl Index<MetricKind> for Metrics {

impl Metrics {
/// Creates a new Metrics instance
pub fn new(worker: &TelemetryWorkerHandle) -> Self {
pub fn new<C: HttpClientCapability + SleepCapability + MaybeSend + Sync + 'static>(
worker: &TelemetryWorkerHandle<C>,
) -> Self {
let mut keys = Vec::new();
for metric in METRICS {
let key = worker.register_metric_context(
Expand All @@ -171,6 +174,7 @@ impl Metrics {
#[cfg(test)]
mod tests {
use super::*;
use libdd_capabilities_impl::NativeCapabilities;
use libdd_telemetry::worker::TelemetryWorkerBuilder;

#[cfg_attr(miri, ignore)]
Expand All @@ -182,7 +186,7 @@ mod tests {
"0.1".to_string(),
"1.0".to_string(),
)
.spawn();
.spawn::<NativeCapabilities>();

let metrics = Metrics::new(&worker);

Expand Down
Loading
Loading