From f73e8c934cd5e6bbef24f1e6e2314c3591661d21 Mon Sep 17 00:00:00 2001 From: Julio Date: Wed, 11 Mar 2026 11:02:24 +0100 Subject: [PATCH 1/8] fix(libdd-crashtracker): avoid leaking Endpoint through the public API --- .../src/collector/datatypes.rs | 43 +++-- libdd-crashtracker/src/collector/api.rs | 146 ++++++++--------- .../src/collector/crash_handler.rs | 14 +- libdd-crashtracker/src/lib.rs | 3 +- libdd-crashtracker/src/receiver/mod.rs | 24 +-- .../src/shared/configuration/builder.rs | 149 ++++++++++++++++++ .../mod.rs} | 59 +------ 7 files changed, 254 insertions(+), 184 deletions(-) create mode 100644 libdd-crashtracker/src/shared/configuration/builder.rs rename libdd-crashtracker/src/shared/{configuration.rs => configuration/mod.rs} (79%) diff --git a/libdd-crashtracker-ffi/src/collector/datatypes.rs b/libdd-crashtracker-ffi/src/collector/datatypes.rs index 8d6509c826..3f0e550c15 100644 --- a/libdd-crashtracker-ffi/src/collector/datatypes.rs +++ b/libdd-crashtracker-ffi/src/collector/datatypes.rs @@ -1,7 +1,6 @@ // Copyright 2024-Present Datadog, Inc. https://www.datadoghq.com/ // SPDX-License-Identifier: Apache-2.0 -use libdd_common::Endpoint; use libdd_common_ffi::slice::{AsBytes, CharSlice}; use libdd_common_ffi::{Error, Slice}; pub use libdd_crashtracker::{OpTypes, StacktraceCollection}; @@ -61,7 +60,7 @@ pub struct Config<'a> { pub demangle_names: bool, /// The endpoint to send the crash report to (can be a file://). /// If None, the crashtracker will infer the agent host from env variables. - pub endpoint: Option<&'a Endpoint>, + pub endpoint: CharSlice<'a>, /// Optional filename for a unix domain socket if the receiver is used asynchonously pub optional_unix_socket_filename: CharSlice<'a>, pub resolve_frames: StacktraceCollection, @@ -88,29 +87,23 @@ impl<'a> TryFrom> for libdd_crashtracker::CrashtrackerConfiguration { } vec }; - let create_alt_stack = value.create_alt_stack; - let use_alt_stack = value.use_alt_stack; - let endpoint = value.endpoint.cloned(); - let resolve_frames = value.resolve_frames; - let signals = value.signals.iter().copied().collect(); - let timeout = if value.timeout_ms == 0 { - None - } else { - Some(Duration::from_millis(value.timeout_ms as u64)) - }; - let unix_socket_path = value.optional_unix_socket_filename.try_to_string_option()?; - let demangle_names = value.demangle_names; - Self::new( - additional_files, - create_alt_stack, - use_alt_stack, - endpoint, - resolve_frames, - signals, - timeout, - unix_socket_path, - demangle_names, - ) + let mut builder = Self::builder() + .additional_files(additional_files) + .create_alt_stack(value.create_alt_stack) + .use_alt_stack(value.use_alt_stack) + .resolve_frames(value.resolve_frames) + .signals(value.signals.iter().copied().collect()) + .demangle_names(value.demangle_names); + if let Some(url) = value.endpoint.try_to_string_option()? { + builder = builder.endpoint_url(&url); + } + if value.timeout_ms != 0 { + builder = builder.timeout(Duration::from_millis(value.timeout_ms as u64)); + } + if let Some(path) = value.optional_unix_socket_filename.try_to_string_option()? { + builder = builder.unix_socket_path(path); + } + builder.build() } } diff --git a/libdd-crashtracker/src/collector/api.rs b/libdd-crashtracker/src/collector/api.rs index d20697b523..f7b14c4ef7 100644 --- a/libdd-crashtracker/src/collector/api.rs +++ b/libdd-crashtracker/src/collector/api.rs @@ -115,10 +115,11 @@ pub fn reconfigure( #[cfg(test)] mod tests { use super::*; - use crate::{begin_op, insert_span, insert_trace, StacktraceCollection}; + use crate::{ + begin_op, insert_span, insert_trace, CrashtrackerConfigurationBuilder, StacktraceCollection, + }; use chrono::Utc; use libdd_common::tag; - use libdd_common::Endpoint; use std::time::Duration; // We can't run this in the main test runner because it (deliberately) crashes, // and would make all following tests unrunable. @@ -133,7 +134,7 @@ mod tests { let dir = "/tmp/crashreports/"; let output_url = format!("file://{dir}{time}.txt"); - let endpoint = Some(Endpoint::from_slice(&output_url)); + let endpoint_url = output_url.as_str(); let path_to_receiver_binary = "/tmp/libdatadog/bin/libdatadog-crashtracking-receiver".to_string(); @@ -151,18 +152,16 @@ mod tests { stdout_filename, ) .unwrap(); - let config = CrashtrackerConfiguration::new( - vec![], - create_alt_stack, - use_alt_stack, - endpoint, - resolve_frames, - default_signals(), - Some(timeout), - None, - true, - ) - .unwrap(); + let config = CrashtrackerConfigurationBuilder::default() + .create_alt_stack(create_alt_stack) + .use_alt_stack(use_alt_stack) + .endpoint_url(endpoint_url) + .resolve_frames(resolve_frames) + .signals(default_signals()) + .timeout(timeout) + .demangle_names(true) + .build() + .unwrap(); let metadata = Metadata::new( "libname".to_string(), "version".to_string(), @@ -198,7 +197,7 @@ mod tests { let dir = "/tmp/crashreports/"; let output_url = format!("file://{dir}{time}.txt"); - let endpoint = Some(Endpoint::from_slice(&output_url)); + let endpoint_url = output_url.as_str(); let create_alt_stack = true; let use_alt_stack = false; @@ -206,17 +205,14 @@ mod tests { let timeout = Duration::from_secs(10); // This should return an error, because we're creating an altstack without using it - let config = CrashtrackerConfiguration::new( - vec![], - create_alt_stack, - use_alt_stack, - endpoint, - resolve_frames, - default_signals(), - Some(timeout), - None, - true, - ); + let config = CrashtrackerConfigurationBuilder::default() + .create_alt_stack(create_alt_stack) + .use_alt_stack(use_alt_stack) + .endpoint_url(endpoint_url) + .resolve_frames(resolve_frames) + .timeout(timeout) + .demangle_names(true) + .build(); // This is slightly over-tuned to the language of the error message, but it'd require some // novel engineering just for this test in order to tighten this up. @@ -254,7 +250,7 @@ mod tests { let dir = "/tmp/crashreports/"; let output_url = format!("file://{dir}{time}.txt"); - let endpoint = Some(Endpoint::from_slice(&output_url)); + let endpoint_url = output_url.as_str(); let path_to_receiver_binary = "/tmp/libdatadog/bin/libdatadog-crashtracking-receiver".to_string(); @@ -273,18 +269,16 @@ mod tests { stdout_filename, ) .unwrap(); - let config = CrashtrackerConfiguration::new( - vec![], - create_alt_stack, - use_alt_stack, - endpoint, - resolve_frames, - signals, - Some(timeout), - None, - true, - ) - .unwrap(); + let config = CrashtrackerConfigurationBuilder::default() + .create_alt_stack(create_alt_stack) + .use_alt_stack(use_alt_stack) + .endpoint_url(endpoint_url) + .resolve_frames(resolve_frames) + .signals(signals) + .timeout(timeout) + .demangle_names(true) + .build() + .unwrap(); let metadata = Metadata::new( "libname".to_string(), "version".to_string(), @@ -376,7 +370,7 @@ mod tests { let dir = "/tmp/crashreports/"; let output_url = format!("file://{dir}{time}.txt"); - let endpoint = Some(Endpoint::from_slice(&output_url)); + let endpoint_url = output_url.as_str(); let path_to_receiver_binary = "/tmp/libdatadog/bin/libdatadog-crashtracking-receiver".to_string(); @@ -395,18 +389,16 @@ mod tests { stdout_filename, ) .unwrap(); - let config = CrashtrackerConfiguration::new( - vec![], - create_alt_stack, - use_alt_stack, - endpoint, - resolve_frames, - signals, - Some(timeout), - None, - true, - ) - .unwrap(); + let config = CrashtrackerConfigurationBuilder::default() + .create_alt_stack(create_alt_stack) + .use_alt_stack(use_alt_stack) + .endpoint_url(endpoint_url) + .resolve_frames(resolve_frames) + .signals(signals) + .timeout(timeout) + .demangle_names(true) + .build() + .unwrap(); let metadata = Metadata::new( "libname".to_string(), "version".to_string(), @@ -504,7 +496,7 @@ mod tests { let dir = "/tmp/crashreports/"; let output_url = format!("file://{dir}{time}.txt"); - let endpoint = Some(Endpoint::from_slice(&output_url)); + let endpoint_url = output_url.as_str(); let path_to_receiver_binary = "/tmp/libdatadog/bin/libdatadog-crashtracking-receiver".to_string(); @@ -523,18 +515,16 @@ mod tests { stdout_filename, ) .unwrap(); - let config = CrashtrackerConfiguration::new( - vec![], - create_alt_stack, - use_alt_stack, - endpoint, - resolve_frames, - signals, - Some(timeout), - None, - true, - ) - .unwrap(); + let config = CrashtrackerConfigurationBuilder::default() + .create_alt_stack(create_alt_stack) + .use_alt_stack(use_alt_stack) + .endpoint_url(endpoint_url) + .resolve_frames(resolve_frames) + .signals(signals) + .timeout(timeout) + .demangle_names(true) + .build() + .unwrap(); let metadata = Metadata::new( "libname".to_string(), "version".to_string(), @@ -667,7 +657,7 @@ mod tests { let dir = "/tmp/crashreports/"; let output_url = format!("file://{dir}{time}.txt"); - let endpoint = Some(Endpoint::from_slice(&output_url)); + let endpoint_url = output_url.as_str(); let path_to_receiver_binary = "/tmp/libdatadog/bin/libdatadog-crashtracking-receiver".to_string(); @@ -686,18 +676,16 @@ mod tests { stdout_filename, ) .unwrap(); - let config = CrashtrackerConfiguration::new( - vec![], - create_alt_stack, - use_alt_stack, - endpoint, - resolve_frames, - signals, - Some(timeout), - None, - true, - ) - .unwrap(); + let config = CrashtrackerConfigurationBuilder::default() + .create_alt_stack(create_alt_stack) + .use_alt_stack(use_alt_stack) + .endpoint_url(endpoint_url) + .resolve_frames(resolve_frames) + .signals(signals) + .timeout(timeout) + .demangle_names(true) + .build() + .unwrap(); let metadata = Metadata::new( "libname".to_string(), diff --git a/libdd-crashtracker/src/collector/crash_handler.rs b/libdd-crashtracker/src/collector/crash_handler.rs index cc53eefc7b..3a51f0d9ba 100644 --- a/libdd-crashtracker/src/collector/crash_handler.rs +++ b/libdd-crashtracker/src/collector/crash_handler.rs @@ -454,18 +454,8 @@ mod tests { } fn make_test_config() -> CrashtrackerConfiguration { - CrashtrackerConfiguration::new( - vec![], // additional_files - false, // create_alt_stack - false, // use_alt_stack - None, // endpoint - crate::StacktraceCollection::Disabled, - vec![], // signals - Some(Duration::from_secs(1)), // timeout - None, // unix_socket_path - false, // demangle_names - ) - .unwrap() + let builder = CrashtrackerConfiguration::builder(); + builder.timeout(Duration::from_secs(1)).build().unwrap() } /// Clears METADATA global, properly freeing any existing Box diff --git a/libdd-crashtracker/src/lib.rs b/libdd-crashtracker/src/lib.rs index 28a43109ff..5654f3444b 100644 --- a/libdd-crashtracker/src/lib.rs +++ b/libdd-crashtracker/src/lib.rs @@ -94,7 +94,8 @@ pub use receiver::{ #[cfg(all(unix, any(feature = "collector", feature = "receiver")))] pub use shared::configuration::{ - CrashtrackerConfiguration, CrashtrackerReceiverConfig, StacktraceCollection, + CrashtrackerConfiguration, CrashtrackerConfigurationBuilder, CrashtrackerReceiverConfig, + StacktraceCollection, }; #[cfg(all(unix, feature = "benchmarking"))] diff --git a/libdd-crashtracker/src/receiver/mod.rs b/libdd-crashtracker/src/receiver/mod.rs index 05cfeb773a..036663f0f5 100644 --- a/libdd-crashtracker/src/receiver/mod.rs +++ b/libdd-crashtracker/src/receiver/mod.rs @@ -18,7 +18,7 @@ mod tests { use crate::collector::default_signals; use crate::crash_info::{SiCodes, SigInfo, SignalNames}; use crate::shared::constants::*; - use crate::{CrashtrackerConfiguration, ErrorKind, StacktraceCollection}; + use crate::{CrashtrackerConfiguration, ErrorKind}; use std::time::Duration; use tokio::io::{AsyncWriteExt, BufReader}; use tokio::net::UnixStream; @@ -54,21 +54,13 @@ mod tests { to_socket(sender, DD_CRASHTRACK_END_KIND).await?; to_socket(sender, DD_CRASHTRACK_BEGIN_CONFIG).await?; - to_socket( - sender, - serde_json::to_string(&CrashtrackerConfiguration::new( - vec![], - false, - false, - None, - StacktraceCollection::Disabled, - default_signals(), - Some(Duration::from_secs(3)), - None, - true, - )?)?, - ) - .await?; + let builder = CrashtrackerConfiguration::builder(); + let config = builder + .signals(default_signals()) + .timeout(Duration::from_secs(3)) + .use_alt_stack(true) + .build()?; + to_socket(sender, serde_json::to_string(&config)?).await?; to_socket(sender, DD_CRASHTRACK_END_CONFIG).await?; tokio::time::sleep(delay).await; to_socket(sender, DD_CRASHTRACK_DONE).await?; diff --git a/libdd-crashtracker/src/shared/configuration/builder.rs b/libdd-crashtracker/src/shared/configuration/builder.rs new file mode 100644 index 0000000000..313f5e4f74 --- /dev/null +++ b/libdd-crashtracker/src/shared/configuration/builder.rs @@ -0,0 +1,149 @@ +// Copyright 2023-Present Datadog, Inc. https://www.datadoghq.com/ +// SPDX-License-Identifier: Apache-2.0 +use crate::{default_signals, shared::constants, signal_from_signum}; +use libdd_common::Endpoint; +use std::borrow::Cow; +use std::time::Duration; + +use super::{CrashtrackerConfiguration, StacktraceCollection}; + +#[derive(Debug, Default)] +pub struct CrashtrackerConfigurationBuilder { + additional_files: Vec, + create_alt_stack: bool, + demangle_names: bool, + endpoint_url: Option, + endpoint_api_key: Option, + endpoint_timeout_ms: Option, + endpoint_test_token: Option, + endpoint_use_system_resolver: bool, + resolve_frames: StacktraceCollection, + signals: Vec, + timeout: Option, + unix_socket_path: Option, + use_alt_stack: bool, +} + +impl CrashtrackerConfigurationBuilder { + pub fn additional_files(mut self, files: Vec) -> Self { + self.additional_files = files; + self + } + + pub fn create_alt_stack(mut self, create: bool) -> Self { + self.create_alt_stack = create; + self + } + + pub fn use_alt_stack(mut self, use_it: bool) -> Self { + self.use_alt_stack = use_it; + self + } + + pub fn demangle_names(mut self, demangle: bool) -> Self { + self.demangle_names = demangle; + self + } + + pub fn endpoint_url(mut self, url: &str) -> Self { + self.endpoint_url = Some(url.to_string()); + self + } + + pub fn endpoint_api_key(mut self, api_key: &str) -> Self { + self.endpoint_api_key = Some(api_key.to_string()); + self + } + + pub fn endpoint_timeout_ms(mut self, timeout_ms: u64) -> Self { + self.endpoint_timeout_ms = Some(timeout_ms); + self + } + + pub fn endpoint_test_token(mut self, test_token: &str) -> Self { + self.endpoint_test_token = Some(test_token.to_string()); + self + } + + pub fn endpoint_use_system_resolver(mut self, use_system_resolver: bool) -> Self { + self.endpoint_use_system_resolver = use_system_resolver; + self + } + + pub fn resolve_frames(mut self, resolve: StacktraceCollection) -> Self { + self.resolve_frames = resolve; + self + } + + pub fn signals(mut self, signals: Vec) -> Self { + self.signals = signals; + self + } + + pub fn timeout(mut self, timeout: Duration) -> Self { + self.timeout = Some(timeout); + self + } + + pub fn unix_socket_path(mut self, path: String) -> Self { + self.unix_socket_path = Some(path); + self + } + + pub fn build(self) -> anyhow::Result { + // Requesting to create, but not use, the altstack is considered paradoxical. + anyhow::ensure!( + !self.create_alt_stack || self.use_alt_stack, + "Cannot create an altstack without using it" + ); + let timeout = self + .timeout + .unwrap_or(constants::DD_CRASHTRACK_DEFAULT_TIMEOUT); + let endpoint = self + .endpoint_url + .map(|url| { + Ok::(Endpoint { + url: libdd_common::parse_uri(&url)?, + api_key: self.endpoint_api_key.map(Cow::Owned), + timeout_ms: self + .endpoint_timeout_ms + .unwrap_or(Endpoint::DEFAULT_TIMEOUT), + test_token: self.endpoint_test_token.map(Cow::Owned), + use_system_resolver: self.endpoint_use_system_resolver, + }) + }) + .transpose()?; + + let mut signals = self.signals; + if signals.is_empty() { + signals = default_signals(); + } else { + // Ensure we don't have double elements in the signals list. + let before_len = signals.len(); + signals.sort(); + signals.dedup(); + anyhow::ensure!( + before_len == signals.len(), + "Signals contained duplicate elements" + ); + // Ensure that all signal values translate to a valid signum + signals + .iter() + .try_for_each(|x| signal_from_signum(*x).map(|_| ()))?; + } + + // Note: don't check the receiver socket upfront, since a configuration can be interned + // before the receiver is started when using an async-receiver. + Ok(CrashtrackerConfiguration { + additional_files: self.additional_files, + create_alt_stack: self.create_alt_stack, + use_alt_stack: self.use_alt_stack, + endpoint, + resolve_frames: self.resolve_frames, + signals, + timeout, + unix_socket_path: self.unix_socket_path, + demangle_names: self.demangle_names, + }) + } +} diff --git a/libdd-crashtracker/src/shared/configuration.rs b/libdd-crashtracker/src/shared/configuration/mod.rs similarity index 79% rename from libdd-crashtracker/src/shared/configuration.rs rename to libdd-crashtracker/src/shared/configuration/mod.rs index 8eed5246ce..a5b2971c7d 100644 --- a/libdd-crashtracker/src/shared/configuration.rs +++ b/libdd-crashtracker/src/shared/configuration/mod.rs @@ -1,6 +1,8 @@ // Copyright 2023-Present Datadog, Inc. https://www.datadoghq.com/ // SPDX-License-Identifier: Apache-2.0 -use crate::{default_signals, shared::constants, signal_from_signum}; +// +mod builder; +pub use builder::CrashtrackerConfigurationBuilder; use libdd_common::Endpoint; use serde::{Deserialize, Serialize}; use std::time::Duration; @@ -11,8 +13,9 @@ use std::time::Duration; /// We recommend fully enabling stacktrace collection, but having an environment /// variable to allow downgrading the collector. #[repr(C)] -#[derive(Debug, Copy, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, Serialize, Deserialize, Default)] pub enum StacktraceCollection { + #[default] Disabled, WithoutSymbols, /// This option uses `backtrace::resolve_frame_unsynchronized()` to gather symbol information @@ -73,54 +76,8 @@ impl CrashtrackerReceiverConfig { } impl CrashtrackerConfiguration { - #[allow(clippy::too_many_arguments)] - pub fn new( - additional_files: Vec, - create_alt_stack: bool, - use_alt_stack: bool, - endpoint: Option, - resolve_frames: StacktraceCollection, - mut signals: Vec, - timeout: Option, - unix_socket_path: Option, - demangle_names: bool, - ) -> anyhow::Result { - // Requesting to create, but not use, the altstack is considered paradoxical. - anyhow::ensure!( - !create_alt_stack || use_alt_stack, - "Cannot create an altstack without using it" - ); - let timeout = timeout.unwrap_or(constants::DD_CRASHTRACK_DEFAULT_TIMEOUT); - if signals.is_empty() { - signals = default_signals(); - } else { - // Ensure we don't have double elements in the signals list. - let before_len = signals.len(); - signals.sort(); - signals.dedup(); - anyhow::ensure!( - before_len == signals.len(), - "Signals contained duplicate elements" - ); - // Ensure that all signal values translate to a valid signum - signals - .iter() - .try_for_each(|x| signal_from_signum(*x).map(|_| ()))?; - } - - // Note: don't check the receiver socket upfront, since a configuration can be interned - // before the receiver is started when using an async-receiver. - Ok(Self { - additional_files, - create_alt_stack, - use_alt_stack, - endpoint, - resolve_frames, - signals, - timeout, - unix_socket_path, - demangle_names, - }) + pub fn builder() -> CrashtrackerConfigurationBuilder { + CrashtrackerConfigurationBuilder::default() } pub fn additional_files(&self) -> &Vec { @@ -135,7 +92,7 @@ impl CrashtrackerConfiguration { self.use_alt_stack } - pub fn endpoint(&self) -> &Option { + pub(crate) fn endpoint(&self) -> &Option { &self.endpoint } From 913c7d969afaa64ebbf101e4d90e8d9321c69c15 Mon Sep 17 00:00:00 2001 From: Julio Date: Wed, 11 Mar 2026 18:42:36 +0100 Subject: [PATCH 2/8] chore(datadog-sidecar): use crastracker configuration builder --- datadog-sidecar/src/unix.rs | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/datadog-sidecar/src/unix.rs b/datadog-sidecar/src/unix.rs index 61ce695a7f..7eff3314e5 100644 --- a/datadog-sidecar/src/unix.rs +++ b/datadog-sidecar/src/unix.rs @@ -220,18 +220,25 @@ fn init_crashtracker(dependency_paths: *const *const libc::c_char) -> anyhow::Re LogMethod::Disabled => None, }; + let mut config_builder = CrashtrackerConfiguration::builder() + .create_alt_stack(true) + .use_alt_stack(true) + .resolve_frames(StacktraceCollection::EnabledWithSymbolsInReceiver) + .demangle_names(true); + if let Some(ep) = Config::get().crashtracker_endpoint.as_ref() { + config_builder = config_builder.endpoint_url(&ep.url.to_string()); + if let Some(api_key) = ep.api_key.as_deref() { + config_builder = config_builder.endpoint_api_key(api_key); + } + config_builder = config_builder + .endpoint_timeout_ms(ep.timeout_ms) + .endpoint_use_system_resolver(ep.use_system_resolver); + if let Some(test_token) = ep.test_token.as_deref() { + config_builder = config_builder.endpoint_test_token(test_token); + } + } libdd_crashtracker::init( - CrashtrackerConfiguration::new( - vec![], - true, - true, - Config::get().crashtracker_endpoint.clone(), - StacktraceCollection::EnabledWithSymbolsInReceiver, - vec![], - None, - None, - true, - )?, + config_builder.build()?, CrashtrackerReceiverConfig::new( receiver_args, vec![], From ff68810bfd2135923a0a63e52e32e8bfe8cb2cf6 Mon Sep 17 00:00:00 2001 From: Julio Date: Wed, 11 Mar 2026 19:19:08 +0100 Subject: [PATCH 3/8] fix: don't build option if url is empty so Endpoint is not instantiated. --- libdd-crashtracker/src/shared/configuration/builder.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libdd-crashtracker/src/shared/configuration/builder.rs b/libdd-crashtracker/src/shared/configuration/builder.rs index 313f5e4f74..bf0dfd1e01 100644 --- a/libdd-crashtracker/src/shared/configuration/builder.rs +++ b/libdd-crashtracker/src/shared/configuration/builder.rs @@ -46,7 +46,9 @@ impl CrashtrackerConfigurationBuilder { } pub fn endpoint_url(mut self, url: &str) -> Self { - self.endpoint_url = Some(url.to_string()); + if !url.is_empty() { + self.endpoint_url = Some(url.to_string()); + } self } From b74e52a8bbae296263c6793fcf11d158fb37f26d Mon Sep 17 00:00:00 2001 From: Julio Date: Wed, 11 Mar 2026 19:20:14 +0100 Subject: [PATCH 4/8] chore(bin-tests): use builder --- bin_tests/src/bin/crashing_test_app.rs | 26 +++++++++---------- bin_tests/src/bin/crashtracker_bin_test.rs | 29 ++++++++-------------- bin_tests/tests/crashtracker_bin_test.rs | 22 ++++++++-------- 3 files changed, 34 insertions(+), 43 deletions(-) diff --git a/bin_tests/src/bin/crashing_test_app.rs b/bin_tests/src/bin/crashing_test_app.rs index 6789d51bc6..441a02fd8b 100644 --- a/bin_tests/src/bin/crashing_test_app.rs +++ b/bin_tests/src/bin/crashing_test_app.rs @@ -18,7 +18,7 @@ mod unix { use std::sync::Arc; use std::time::Duration; - use libdd_common::{tag, Endpoint}; + use libdd_common::tag; use libdd_crashtracker::{ self as crashtracker, CrashtrackerConfiguration, CrashtrackerReceiverConfig, Metadata, }; @@ -91,19 +91,17 @@ mod unix { let stdout_filename = format!("{output_dir}/out.stdout"); ensure!(!output_url.is_empty(), "output_url must not be empty"); - let endpoint = Some(Endpoint::from_slice(&output_url)); - - let config = CrashtrackerConfiguration::new( - vec![], // additional_files - true, // create_alt_stack - true, // use_alt_stack - endpoint, - crashtracker::StacktraceCollection::EnabledWithSymbolsInReceiver, - crashtracker::default_signals(), - Some(TEST_COLLECTOR_TIMEOUT), - Some("".to_string()), // unix_socket_path - true, // demangle_names - )?; + + let config = CrashtrackerConfiguration::builder() + .create_alt_stack(true) + .use_alt_stack(true) + .endpoint_url(&output_url) + .resolve_frames(crashtracker::StacktraceCollection::EnabledWithSymbolsInReceiver) + .signals(crashtracker::default_signals()) + .timeout(TEST_COLLECTOR_TIMEOUT) + .unix_socket_path("".to_string()) + .demangle_names(true) + .build()?; let metadata = Metadata { library_name: "libdatadog".to_owned(), diff --git a/bin_tests/src/bin/crashtracker_bin_test.rs b/bin_tests/src/bin/crashtracker_bin_test.rs index a9c3f379db..af0c73b37b 100644 --- a/bin_tests/src/bin/crashtracker_bin_test.rs +++ b/bin_tests/src/bin/crashtracker_bin_test.rs @@ -22,7 +22,7 @@ mod unix { use std::process; use std::time::Duration; - use libdd_common::{tag, Endpoint}; + use libdd_common::tag; use libdd_crashtracker::{ self as crashtracker, CrashtrackerConfiguration, CrashtrackerReceiverConfig, Metadata, StackFrame, StackTrace, @@ -73,12 +73,6 @@ mod unix { let stdout_filename = format!("{output_dir}/out.stdout"); let output_dir: &Path = output_dir.as_ref(); - let endpoint = if output_url.is_empty() { - None - } else { - Some(Endpoint::from_slice(output_url)) - }; - // The configuration can be modified by a Behavior (testing plan), so it is mut here. // Unlike a normal harness, in this harness tests are run in individual processes, so race // issues are avoided. @@ -97,17 +91,16 @@ mod unix { Err(_) => crashtracker::StacktraceCollection::WithoutSymbols, }; - let mut config = CrashtrackerConfiguration::new( - vec![], - true, - true, - endpoint, - stacktrace_collection, - crashtracker::default_signals(), - Some(TEST_COLLECTOR_TIMEOUT), - Some("".to_string()), - true, - )?; + let mut config = CrashtrackerConfiguration::builder() + .create_alt_stack(true) + .demangle_names(true) + .endpoint_url(output_url) + .resolve_frames(stacktrace_collection) + .signals(crashtracker::default_signals()) + .timeout(TEST_COLLECTOR_TIMEOUT) + .unix_socket_path("".to_string()) + .use_alt_stack(true) + .build()?; let metadata = Metadata { library_name: "libdatadog".to_owned(), diff --git a/bin_tests/tests/crashtracker_bin_test.rs b/bin_tests/tests/crashtracker_bin_test.rs index 8611a4d81d..88f2a8a5e5 100644 --- a/bin_tests/tests/crashtracker_bin_test.rs +++ b/bin_tests/tests/crashtracker_bin_test.rs @@ -1331,23 +1331,23 @@ fn crash_tracking_empty_endpoint() { #[cfg_attr(miri, ignore)] #[cfg(unix)] fn test_receiver_emits_debug_logs_on_receiver_issue() -> anyhow::Result<()> { + use std::time::Duration; + let receiver = artifacts::crashtracker_receiver(BuildProfile::Debug); let artifacts = build_artifacts(&[&receiver])?; let fixtures = bin_tests::test_runner::TestFixtures::new()?; let missing_file = fixtures.output_dir.join("missing_additional_file.txt"); - let config = CrashtrackerConfiguration::new( - vec![missing_file.display().to_string()], - true, - true, - None, - StacktraceCollection::WithoutSymbols, - libdd_crashtracker::default_signals(), - Some(std::time::Duration::from_millis(500)), - None, - true, - )?; + let config = CrashtrackerConfiguration::builder() + .additional_files(vec![missing_file.display().to_string()]) + .create_alt_stack(true) + .demangle_names(true) + .resolve_frames(StacktraceCollection::WithoutSymbols) + .signals(libdd_crashtracker::default_signals()) + .timeout(Duration::from_millis(500)) + .use_alt_stack(true) + .build()?; let metadata = Metadata { library_name: "libdatadog".to_owned(), From 312a29cbf2673236c84562f5c37b73a6047c7122 Mon Sep 17 00:00:00 2001 From: Julio Date: Thu, 12 Mar 2026 10:03:04 +0100 Subject: [PATCH 5/8] fix(libdd-crashtracker): use builder on benches --- libdd-crashtracker/benches/receiver_bench.rs | 24 ++++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/libdd-crashtracker/benches/receiver_bench.rs b/libdd-crashtracker/benches/receiver_bench.rs index b431d81da8..d71a38c494 100644 --- a/libdd-crashtracker/benches/receiver_bench.rs +++ b/libdd-crashtracker/benches/receiver_bench.rs @@ -37,18 +37,18 @@ fn add_proc_info(report: &mut String) { fn add_config(report: &mut String) { writeln!(report, "{DD_CRASHTRACK_BEGIN_CONFIG}") .expect("Failed to write DD_CRASHTRACK_BEGIN_CONFIG"); - let config = CrashtrackerConfiguration::new( - vec![], // additional_files - true, // create_alt_stack - true, // use_alt_stack - None, - StacktraceCollection::EnabledWithSymbolsInReceiver, - default_signals(), - Some(Duration::from_secs(10)), - Some("".to_string()), // unix_socket_path - true, // demangle_names - ) - .expect("Failed to create crashtracker configuration"); + + let config = CrashtrackerConfiguration::builder() + .create_alt_stack(true) + .use_alt_stack(true) + .resolve_frames(StacktraceCollection::EnabledWithSymbolsInReceiver) + .signals(default_signals()) + .timeout(Duration::from_secs(10)) + .unix_socket_path("".to_string()) + .demangle_names(true) + .build() + .expect("Failed to create crashtracker configuration"); + let config_str = serde_json::to_string(&config).expect("Failed to serialize crashtracker configuration"); writeln!(report, "{config_str}").expect("Failed to write crashtracker configuration"); From f510db7ef6db0fc5573d96c0977343862a0085d5 Mon Sep 17 00:00:00 2001 From: Julio Date: Thu, 12 Mar 2026 12:23:47 +0100 Subject: [PATCH 6/8] fix: pass charslice to crashtracker configuration on ffi layer --- examples/ffi/crashtracking.c | 14 ++++++-------- examples/ffi/crashtracking_unhandled_exception.c | 9 +++++---- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/examples/ffi/crashtracking.c b/examples/ffi/crashtracking.c index 447f38039c..a1ba757e12 100644 --- a/examples/ffi/crashtracking.c +++ b/examples/ffi/crashtracking.c @@ -8,6 +8,7 @@ #include #include +#define MAX_FILE_PATH 512 #define INIT_FROM_SLICE(s) \ { .ptr = s.ptr, .len = s.len } @@ -51,10 +52,10 @@ int main(int argc, char **argv) { } // Build output file paths - char report_path[512]; - char stderr_path[512]; - char stdout_path[512]; - snprintf(report_path, sizeof(report_path), "%s/crashreport.json", output_dir); + char report_path[MAX_FILE_PATH]; + char stderr_path[MAX_FILE_PATH]; + char stdout_path[MAX_FILE_PATH]; + snprintf(report_path, sizeof(report_path), "file://%s/crashreport.json", output_dir); snprintf(stderr_path, sizeof(stderr_path), "%s/stderr.txt", output_dir); snprintf(stdout_path, sizeof(stdout_path), "%s/stdout.txt", output_dir); @@ -82,13 +83,11 @@ int main(int argc, char **argv) { .optional_stdout_filename = slice(stdout_path), }; - struct ddog_Endpoint *endpoint = ddog_endpoint_from_filename(slice(report_path)); - // Get the default signals and explicitly use them. struct ddog_crasht_Slice_CInt signals = ddog_crasht_default_signals(); ddog_crasht_Config config = { .create_alt_stack = false, - .endpoint = endpoint, + .endpoint = slice(report_path), .resolve_frames = DDOG_CRASHT_STACKTRACE_COLLECTION_ENABLED_WITH_INPROCESS_SYMBOLS, .signals = INIT_FROM_SLICE(signals), }; @@ -101,7 +100,6 @@ int main(int argc, char **argv) { }; handle_result(ddog_crasht_init(config, receiver_config, metadata)); - ddog_endpoint_drop(endpoint); handle_result(ddog_crasht_begin_op(DDOG_CRASHT_OP_TYPES_PROFILER_COLLECTING_SAMPLE)); handle_uintptr_t_result(ddog_crasht_insert_span_id(0, 42)); diff --git a/examples/ffi/crashtracking_unhandled_exception.c b/examples/ffi/crashtracking_unhandled_exception.c index fab38d5e10..dc80b839ad 100644 --- a/examples/ffi/crashtracking_unhandled_exception.c +++ b/examples/ffi/crashtracking_unhandled_exception.c @@ -20,6 +20,8 @@ #include #include +#define MAX_FILE_PATH 512 + static ddog_CharSlice slice(const char *s) { return (ddog_CharSlice){.ptr = s, .len = strlen(s)}; } @@ -110,13 +112,13 @@ int main(int argc, char **argv) { .env = env_slice, }; - struct ddog_Endpoint *endpoint = - ddog_endpoint_from_filename(slice(output_file)); + char endpoint[MAX_FILE_PATH]; + snprintf(endpoint, sizeof(endpoint), "file://%s", output_file); struct ddog_crasht_Slice_CInt signals = ddog_crasht_default_signals(); ddog_crasht_Config config = { .create_alt_stack = false, - .endpoint = endpoint, + .endpoint = slice(endpoint), .resolve_frames = DDOG_CRASHT_STACKTRACE_COLLECTION_DISABLED, .signals = {.ptr = signals.ptr, .len = signals.len}, }; @@ -130,7 +132,6 @@ int main(int argc, char **argv) { handle_void(ddog_crasht_init(config, receiver_config, metadata), "ddog_crasht_init"); - ddog_endpoint_drop(endpoint); // Build a runtime StackTrace with two synthetic frames. ddog_crasht_StackTrace_NewResult tr = ddog_crasht_StackTrace_new(); From a15aa94c2c781a81656755a09375627079c60784 Mon Sep 17 00:00:00 2001 From: Julio Date: Thu, 12 Mar 2026 13:15:42 +0100 Subject: [PATCH 7/8] chore(libdd-crashtracker): add builder unit tests --- .../src/shared/configuration/builder.rs | 226 ++++++++++++++++++ 1 file changed, 226 insertions(+) diff --git a/libdd-crashtracker/src/shared/configuration/builder.rs b/libdd-crashtracker/src/shared/configuration/builder.rs index bf0dfd1e01..c0ad491cfb 100644 --- a/libdd-crashtracker/src/shared/configuration/builder.rs +++ b/libdd-crashtracker/src/shared/configuration/builder.rs @@ -149,3 +149,229 @@ impl CrashtrackerConfigurationBuilder { }) } } + +#[cfg(test)] +mod tests { + use super::*; + use crate::{default_signals, shared::constants}; + use std::time::Duration; + + #[test] + fn test_build_defaults() -> anyhow::Result<()> { + let config = CrashtrackerConfiguration::builder().build()?; + assert!(config.additional_files().is_empty()); + assert!(!config.create_alt_stack()); + assert!(!config.use_alt_stack()); + assert!(!config.demangle_names()); + assert!(config.endpoint().is_none()); + assert_eq!(config.resolve_frames(), StacktraceCollection::Disabled); + assert_eq!(config.signals(), &default_signals()); + assert_eq!(config.timeout(), constants::DD_CRASHTRACK_DEFAULT_TIMEOUT); + assert!(config.unix_socket_path().is_none()); + Ok(()) + } + + #[test] + fn test_create_alt_stack_without_use_fails() { + let result = CrashtrackerConfiguration::builder() + .create_alt_stack(true) + .use_alt_stack(false) + .build(); + assert!(result.is_err()); + } + + #[test] + fn test_create_and_use_alt_stack_succeeds() -> anyhow::Result<()> { + let config = CrashtrackerConfiguration::builder() + .create_alt_stack(true) + .use_alt_stack(true) + .build()?; + assert!(config.create_alt_stack()); + assert!(config.use_alt_stack()); + Ok(()) + } + + #[test] + fn test_endpoint_empty_url() -> anyhow::Result<()> { + let config = CrashtrackerConfiguration::builder() + .endpoint_url("") + .build()?; + assert!(config.endpoint().is_none()); + Ok(()) + } + + #[test] + fn test_endpoint_file_url() -> anyhow::Result<()> { + let config = CrashtrackerConfiguration::builder() + .endpoint_url("file:///tmp/crashreport.json") + .build()?; + let endpoint = config.endpoint().as_ref().expect("endpoint should be set"); + assert_eq!(endpoint.url.scheme_str(), Some("file")); + Ok(()) + } + + #[test] + fn test_endpoint_http_url() -> anyhow::Result<()> { + let config = CrashtrackerConfiguration::builder() + .endpoint_url("http://localhost:8126/api/v2/profile") + .build()?; + let endpoint = config.endpoint().as_ref().expect("endpoint should be set"); + assert_eq!(endpoint.url.scheme_str(), Some("http")); + assert_eq!(endpoint.url.port().unwrap().as_u16(), 8126); + assert_eq!(endpoint.url.host(), Some("localhost")); + Ok(()) + } + + #[test] + fn test_endpoint_default_timeout_ms() -> anyhow::Result<()> { + let config = CrashtrackerConfiguration::builder() + .endpoint_url("http://localhost:8126") + .build()?; + let endpoint = config.endpoint().as_ref().expect("endpoint should be set"); + assert_eq!(endpoint.url.port().unwrap().as_u16(), 8126); + assert_eq!(endpoint.timeout_ms, Endpoint::DEFAULT_TIMEOUT); + Ok(()) + } + + #[test] + fn test_endpoint_custom_timeout_ms() -> anyhow::Result<()> { + let config = CrashtrackerConfiguration::builder() + .endpoint_url("http://localhost:8126") + .endpoint_timeout_ms(1234) + .build()?; + let endpoint = config.endpoint().as_ref().expect("endpoint should be set"); + assert_eq!(endpoint.timeout_ms, 1234); + Ok(()) + } + + #[test] + fn test_endpoint_with_api_key() -> anyhow::Result<()> { + let config = CrashtrackerConfiguration::builder() + .endpoint_url("http://localhost:8126") + .endpoint_api_key("my-api-key") + .build()?; + let endpoint = config.endpoint().as_ref().expect("endpoint should be set"); + assert_eq!(endpoint.api_key.as_deref(), Some("my-api-key")); + Ok(()) + } + + #[test] + fn test_endpoint_with_test_token() -> anyhow::Result<()> { + let config = CrashtrackerConfiguration::builder() + .endpoint_url("http://localhost:8126") + .endpoint_test_token("test-token") + .build()?; + let endpoint = config.endpoint().as_ref().expect("endpoint should be set"); + assert_eq!(endpoint.test_token.as_deref(), Some("test-token")); + Ok(()) + } + + #[test] + fn test_endpoint_with_system_resolver() -> anyhow::Result<()> { + let config = CrashtrackerConfiguration::builder() + .endpoint_url("http://localhost:8126") + .endpoint_use_system_resolver(true) + .build()?; + let endpoint = config.endpoint().as_ref().expect("endpoint should be set"); + assert!(endpoint.use_system_resolver); + Ok(()) + } + + #[test] + fn test_signals_default() -> anyhow::Result<()> { + let config = CrashtrackerConfiguration::builder().build()?; + assert_eq!(config.signals(), &default_signals()); + Ok(()) + } + + #[test] + fn test_signals_custom() -> anyhow::Result<()> { + let signals = vec![libc::SIGSEGV, libc::SIGBUS]; + let config = CrashtrackerConfiguration::builder() + .signals(signals.clone()) + .build()?; + let mut expected = signals; + expected.sort(); + assert_eq!(config.signals(), &expected); + Ok(()) + } + + #[test] + fn test_signals_duplicates_fail() { + let result = CrashtrackerConfiguration::builder() + .signals(vec![libc::SIGSEGV, libc::SIGSEGV]) + .build(); + assert!(result.is_err()); + } + + #[test] + fn test_signals_invalid_fail() { + let result = CrashtrackerConfiguration::builder() + .signals(vec![9999]) + .build(); + assert!(result.is_err()); + } + + #[test] + fn test_timeout_default() -> anyhow::Result<()> { + let config = CrashtrackerConfiguration::builder().build()?; + assert_eq!(config.timeout(), constants::DD_CRASHTRACK_DEFAULT_TIMEOUT); + Ok(()) + } + + #[test] + fn test_timeout_custom() -> anyhow::Result<()> { + let config = CrashtrackerConfiguration::builder() + .timeout(Duration::from_secs(10)) + .build()?; + assert_eq!(config.timeout(), Duration::from_secs(10)); + Ok(()) + } + + #[test] + fn test_additional_files() -> anyhow::Result<()> { + let files = vec!["/tmp/file1.txt".to_string(), "/tmp/file2.txt".to_string()]; + let config = CrashtrackerConfiguration::builder() + .additional_files(files.clone()) + .build()?; + assert_eq!(config.additional_files(), &files); + Ok(()) + } + + #[test] + fn test_demangle_names() -> anyhow::Result<()> { + let config = CrashtrackerConfiguration::builder() + .demangle_names(true) + .build()?; + assert!(config.demangle_names()); + Ok(()) + } + + #[test] + fn test_resolve_frames() -> anyhow::Result<()> { + for variant in [ + StacktraceCollection::Disabled, + StacktraceCollection::WithoutSymbols, + StacktraceCollection::EnabledWithInprocessSymbols, + StacktraceCollection::EnabledWithSymbolsInReceiver, + ] { + let config = CrashtrackerConfiguration::builder() + .resolve_frames(variant) + .build()?; + assert_eq!(config.resolve_frames(), variant); + } + Ok(()) + } + + #[test] + fn test_unix_socket_path() -> anyhow::Result<()> { + let config = CrashtrackerConfiguration::builder() + .unix_socket_path("/tmp/crashtracker.sock".to_string()) + .build()?; + assert_eq!( + config.unix_socket_path(), + &Some("/tmp/crashtracker.sock".to_string()) + ); + Ok(()) + } +} From f1e7d1110fd842c611de94f0eacb9f42868e0e9c Mon Sep 17 00:00:00 2001 From: Julio Date: Fri, 13 Mar 2026 12:14:36 +0100 Subject: [PATCH 8/8] chore: solve PR comments --- .../src/collector/datatypes.rs | 4 +- libdd-crashtracker/src/collector/api.rs | 159 ++++++------------ 2 files changed, 50 insertions(+), 113 deletions(-) diff --git a/libdd-crashtracker-ffi/src/collector/datatypes.rs b/libdd-crashtracker-ffi/src/collector/datatypes.rs index 3f0e550c15..3897167475 100644 --- a/libdd-crashtracker-ffi/src/collector/datatypes.rs +++ b/libdd-crashtracker-ffi/src/collector/datatypes.rs @@ -90,10 +90,10 @@ impl<'a> TryFrom> for libdd_crashtracker::CrashtrackerConfiguration { let mut builder = Self::builder() .additional_files(additional_files) .create_alt_stack(value.create_alt_stack) - .use_alt_stack(value.use_alt_stack) + .demangle_names(value.demangle_names) .resolve_frames(value.resolve_frames) .signals(value.signals.iter().copied().collect()) - .demangle_names(value.demangle_names); + .use_alt_stack(value.use_alt_stack); if let Some(url) = value.endpoint.try_to_string_option()? { builder = builder.endpoint_url(&url); } diff --git a/libdd-crashtracker/src/collector/api.rs b/libdd-crashtracker/src/collector/api.rs index f7b14c4ef7..3817843dbc 100644 --- a/libdd-crashtracker/src/collector/api.rs +++ b/libdd-crashtracker/src/collector/api.rs @@ -121,6 +121,8 @@ mod tests { use chrono::Utc; use libdd_common::tag; use std::time::Duration; + + const PATH_TO_RECEIVER: &str = "/tmp/libdatadog/bin/libdatadog-crashtracking-receiver"; // We can't run this in the main test runner because it (deliberately) crashes, // and would make all following tests unrunable. // To run this test, @@ -134,32 +136,22 @@ mod tests { let dir = "/tmp/crashreports/"; let output_url = format!("file://{dir}{time}.txt"); - let endpoint_url = output_url.as_str(); - - let path_to_receiver_binary = - "/tmp/libdatadog/bin/libdatadog-crashtracking-receiver".to_string(); - let create_alt_stack = true; - let use_alt_stack = true; - let resolve_frames = StacktraceCollection::EnabledWithInprocessSymbols; - let stderr_filename = Some(format!("{dir}/stderr_{time}.txt")); - let stdout_filename = Some(format!("{dir}/stdout_{time}.txt")); - let timeout = Duration::from_secs(10); let receiver_config = CrashtrackerReceiverConfig::new( vec![], vec![], - path_to_receiver_binary, - stderr_filename, - stdout_filename, + PATH_TO_RECEIVER.to_string(), + Some(format!("{dir}/stderr_{time}.txt")), + Some(format!("{dir}/stdout_{time}.txt")), ) .unwrap(); let config = CrashtrackerConfigurationBuilder::default() - .create_alt_stack(create_alt_stack) - .use_alt_stack(use_alt_stack) - .endpoint_url(endpoint_url) - .resolve_frames(resolve_frames) - .signals(default_signals()) - .timeout(timeout) + .create_alt_stack(true) .demangle_names(true) + .endpoint_url(output_url.as_str()) + .resolve_frames(StacktraceCollection::EnabledWithInprocessSymbols) + .signals(default_signals()) + .timeout(Duration::from_secs(10)) + .use_alt_stack(true) .build() .unwrap(); let metadata = Metadata::new( @@ -197,21 +189,13 @@ mod tests { let dir = "/tmp/crashreports/"; let output_url = format!("file://{dir}{time}.txt"); - let endpoint_url = output_url.as_str(); - - let create_alt_stack = true; - let use_alt_stack = false; - let resolve_frames = StacktraceCollection::EnabledWithInprocessSymbols; - let timeout = Duration::from_secs(10); - // This should return an error, because we're creating an altstack without using it let config = CrashtrackerConfigurationBuilder::default() - .create_alt_stack(create_alt_stack) - .use_alt_stack(use_alt_stack) - .endpoint_url(endpoint_url) - .resolve_frames(resolve_frames) - .timeout(timeout) + .create_alt_stack(true) .demangle_names(true) + .endpoint_url(output_url.as_str()) + .resolve_frames(StacktraceCollection::EnabledWithInprocessSymbols) + .timeout(Duration::from_secs(10)) .build(); // This is slightly over-tuned to the language of the error message, but it'd require some @@ -250,32 +234,21 @@ mod tests { let dir = "/tmp/crashreports/"; let output_url = format!("file://{dir}{time}.txt"); - let endpoint_url = output_url.as_str(); - - let path_to_receiver_binary = - "/tmp/libdatadog/bin/libdatadog-crashtracking-receiver".to_string(); - let create_alt_stack = true; - let use_alt_stack = true; - let resolve_frames = StacktraceCollection::EnabledWithInprocessSymbols; - let stderr_filename = Some(format!("{dir}/stderr_{time}.txt")); - let stdout_filename = Some(format!("{dir}/stdout_{time}.txt")); - let signals = default_signals(); - let timeout = Duration::from_secs(10); let receiver_config = CrashtrackerReceiverConfig::new( vec![], vec![], - path_to_receiver_binary, - stderr_filename, - stdout_filename, + PATH_TO_RECEIVER.to_string(), + Some(format!("{dir}/stderr_{time}.txt")), + Some(format!("{dir}/stdout_{time}.txt")), ) .unwrap(); let config = CrashtrackerConfigurationBuilder::default() - .create_alt_stack(create_alt_stack) - .use_alt_stack(use_alt_stack) - .endpoint_url(endpoint_url) - .resolve_frames(resolve_frames) - .signals(signals) - .timeout(timeout) + .create_alt_stack(true) + .use_alt_stack(true) + .endpoint_url(output_url.as_str()) + .resolve_frames(StacktraceCollection::EnabledWithInprocessSymbols) + .signals(default_signals()) + .timeout(Duration::from_secs(10)) .demangle_names(true) .build() .unwrap(); @@ -370,32 +343,20 @@ mod tests { let dir = "/tmp/crashreports/"; let output_url = format!("file://{dir}{time}.txt"); - let endpoint_url = output_url.as_str(); - - let path_to_receiver_binary = - "/tmp/libdatadog/bin/libdatadog-crashtracking-receiver".to_string(); - let create_alt_stack = false; // Use, but do _not_ create - let use_alt_stack = true; - let resolve_frames = StacktraceCollection::EnabledWithInprocessSymbols; - let stderr_filename = Some(format!("{dir}/stderr_{time}.txt")); - let stdout_filename = Some(format!("{dir}/stdout_{time}.txt")); - let signals = default_signals(); - let timeout = Duration::from_secs(10); let receiver_config = CrashtrackerReceiverConfig::new( vec![], vec![], - path_to_receiver_binary, - stderr_filename, - stdout_filename, + PATH_TO_RECEIVER.to_string(), + Some(format!("{dir}/stderr_{time}.txt")), + Some(format!("{dir}/stdout_{time}.txt")), ) .unwrap(); let config = CrashtrackerConfigurationBuilder::default() - .create_alt_stack(create_alt_stack) - .use_alt_stack(use_alt_stack) - .endpoint_url(endpoint_url) - .resolve_frames(resolve_frames) - .signals(signals) - .timeout(timeout) + .use_alt_stack(true) + .endpoint_url(output_url.as_str()) + .resolve_frames(StacktraceCollection::EnabledWithInprocessSymbols) + .signals(default_signals()) + .timeout(Duration::from_secs(10)) .demangle_names(true) .build() .unwrap(); @@ -496,33 +457,20 @@ mod tests { let dir = "/tmp/crashreports/"; let output_url = format!("file://{dir}{time}.txt"); - let endpoint_url = output_url.as_str(); - - let path_to_receiver_binary = - "/tmp/libdatadog/bin/libdatadog-crashtracking-receiver".to_string(); - let create_alt_stack = false; - let use_alt_stack = false; - let resolve_frames = StacktraceCollection::EnabledWithInprocessSymbols; - let stderr_filename = Some(format!("{dir}/stderr_{time}.txt")); - let stdout_filename = Some(format!("{dir}/stdout_{time}.txt")); - let signals = default_signals(); - let timeout = Duration::from_secs(10); let receiver_config = CrashtrackerReceiverConfig::new( vec![], vec![], - path_to_receiver_binary, - stderr_filename, - stdout_filename, + PATH_TO_RECEIVER.to_string(), + Some(format!("{dir}/stderr_{time}.txt")), + Some(format!("{dir}/stdout_{time}.txt")), ) .unwrap(); let config = CrashtrackerConfigurationBuilder::default() - .create_alt_stack(create_alt_stack) - .use_alt_stack(use_alt_stack) - .endpoint_url(endpoint_url) - .resolve_frames(resolve_frames) - .signals(signals) - .timeout(timeout) .demangle_names(true) + .endpoint_url(output_url.as_str()) + .resolve_frames(StacktraceCollection::EnabledWithInprocessSymbols) + .signals(default_signals()) + .timeout(Duration::from_secs(10)) .build() .unwrap(); let metadata = Metadata::new( @@ -657,33 +605,22 @@ mod tests { let dir = "/tmp/crashreports/"; let output_url = format!("file://{dir}{time}.txt"); - let endpoint_url = output_url.as_str(); - - let path_to_receiver_binary = - "/tmp/libdatadog/bin/libdatadog-crashtracking-receiver".to_string(); - let create_alt_stack = true; // doesn't matter, but most runtimes use it, so take it - let use_alt_stack = true; - let resolve_frames = StacktraceCollection::EnabledWithInprocessSymbols; - let stderr_filename = Some(format!("{dir}/stderr_{time}.txt")); - let stdout_filename = Some(format!("{dir}/stdout_{time}.txt")); - let signals = default_signals(); - let timeout = Duration::from_secs(10); let receiver_config = CrashtrackerReceiverConfig::new( vec![], vec![], - path_to_receiver_binary, - stderr_filename, - stdout_filename, + PATH_TO_RECEIVER.to_string(), + Some(format!("{dir}/stderr_{time}.txt")), + Some(format!("{dir}/stdout_{time}.txt")), ) .unwrap(); let config = CrashtrackerConfigurationBuilder::default() - .create_alt_stack(create_alt_stack) - .use_alt_stack(use_alt_stack) - .endpoint_url(endpoint_url) - .resolve_frames(resolve_frames) - .signals(signals) - .timeout(timeout) + .create_alt_stack(true) .demangle_names(true) + .endpoint_url(output_url.as_str()) + .resolve_frames(StacktraceCollection::EnabledWithInprocessSymbols) + .signals(default_signals()) + .timeout(Duration::from_secs(10)) + .use_alt_stack(true) .build() .unwrap();