From b83f47762dba1d5a2fdc7226e66863030b77a882 Mon Sep 17 00:00:00 2001 From: Daniel Schwartz-Narbonne Date: Wed, 24 Jul 2024 14:33:48 -0400 Subject: [PATCH 01/31] [crashtracker] Move FFI into its own library --- Cargo.lock | 10 ++++++ Cargo.toml | 1 + crashtracker-ffi/Cargo.toml | 24 +++++++++++++ crashtracker-ffi/build.rs | 10 ++++++ crashtracker-ffi/cbindgen.toml | 61 ++++++++++++++++++++++++++++++++++ crashtracker-ffi/src/lib.rs | 0 6 files changed, 106 insertions(+) create mode 100644 crashtracker-ffi/Cargo.toml create mode 100644 crashtracker-ffi/build.rs create mode 100644 crashtracker-ffi/cbindgen.toml create mode 100644 crashtracker-ffi/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 2e5585eb6..b60ea48d7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1119,6 +1119,16 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "crashtracker-ffi" +version = "11.0.0" +dependencies = [ + "anyhow", + "build_common", + "ddcommon", + "hyper 0.14.28", +] + [[package]] name = "crc32fast" version = "1.4.0" diff --git a/Cargo.toml b/Cargo.toml index b116cc7b7..5d9e83d21 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,6 +5,7 @@ members = [ "alloc", "crashtracker", + "crashtracker-ffi", "profiling", "profiling-ffi", "profiling-replayer", diff --git a/crashtracker-ffi/Cargo.toml b/crashtracker-ffi/Cargo.toml new file mode 100644 index 000000000..24fc954c1 --- /dev/null +++ b/crashtracker-ffi/Cargo.toml @@ -0,0 +1,24 @@ +# Copyright 2021-Present Datadog, Inc. https://www.datadoghq.com/ +# SPDX-License-Identifier: Apache-2.0 + +[package] +name = "crashtracker-ffi" +edition.workspace = true +version.workspace = true +rust-version.workspace = true +license.workspace = true + +[lib] +bench =false + +[features] +default = ["cbindgen"] +cbindgen = ["build_common/cbindgen"] + +[build-dependencies] +build_common = { path = "../build-common" } + +[dependencies] +ddcommon = { path = "../ddcommon" } +anyhow = "1.0" +hyper = {version = "0.14", default-features = false} diff --git a/crashtracker-ffi/build.rs b/crashtracker-ffi/build.rs new file mode 100644 index 000000000..d6ccc6ad6 --- /dev/null +++ b/crashtracker-ffi/build.rs @@ -0,0 +1,10 @@ +// Copyright 2021-Present Datadog, Inc. https://www.datadoghq.com/ +// SPDX-License-Identifier: Apache-2.0 +extern crate build_common; + +use build_common::generate_and_configure_header; + +fn main() { + let header_name = "crashtracker.h"; + generate_and_configure_header(header_name); +} diff --git a/crashtracker-ffi/cbindgen.toml b/crashtracker-ffi/cbindgen.toml new file mode 100644 index 000000000..0bb02a61f --- /dev/null +++ b/crashtracker-ffi/cbindgen.toml @@ -0,0 +1,61 @@ +# Copyright 2021-Present Datadog, Inc. https://www.datadoghq.com/ +# SPDX-License-Identifier: Apache-2.0 + +language = "C" +cpp_compat = true +tab_width = 2 +header = """// Copyright 2021-Present Datadog, Inc. https://www.datadoghq.com/ +// SPDX-License-Identifier: Apache-2.0 +""" +include_guard = "DDOG_CRASHTRACKER_H" +style = "both" +pragma_once = true + +no_includes = true +sys_includes = ["stdbool.h", "stddef.h", "stdint.h"] +includes = ["common.h"] + +[export] +prefix = "ddog_prof_" +renaming_overrides_prefixing = true + +[export.rename] +"ByteSlice" = "ddog_ByteSlice" +"CancellationToken" = "ddog_CancellationToken" +"CharSlice" = "ddog_CharSlice" +"Error" = "ddog_Error" +"HttpStatus" = "ddog_HttpStatus" +"Slice_CChar" = "ddog_Slice_CChar" +"Slice_I64" = "ddog_Slice_I64" +"Slice_U8" = "ddog_Slice_U8" +"Tag" = "ddog_Tag" +"Timespec" = "ddog_Timespec" +"Vec_Tag" = "ddog_Vec_Tag" +"Vec_U8" = "ddog_Vec_U8" + +"ProfilingEndpoint" = "ddog_prof_Endpoint" +"ExporterNewResult" = "ddog_prof_Exporter_NewResult" +"File" = "ddog_prof_Exporter_File" +"ProfileExporter" = "ddog_prof_Exporter" +"ProfileNewResult" = "ddog_prof_Profile_NewResult" +"ProfileResult" = "ddog_prof_Profile_Result" +"Request" = "ddog_prof_Exporter_Request" +"RequestBuildResult" = "ddog_prof_Exporter_Request_BuildResult" +"SendResult" = "ddog_prof_Exporter_SendResult" +"SerializeResult" = "ddog_prof_Profile_SerializeResult" +"Slice_File" = "ddog_prof_Exporter_Slice_File" + +[export.mangle] +rename_types = "PascalCase" + +[enum] +prefix_with_name = true +rename_variants = "ScreamingSnakeCase" + +[fn] +must_use = "DDOG_CHECK_RETURN" + +[parse] +parse_deps = true +include = ["ddcommon", "ddcommon-ffi", "datadog-profiling", "datadog-crashtracker", "ux"] + diff --git a/crashtracker-ffi/src/lib.rs b/crashtracker-ffi/src/lib.rs new file mode 100644 index 000000000..e69de29bb From 35981b0cc17c00f0f82a4c5f1240d3a1581d50f1 Mon Sep 17 00:00:00 2001 From: Daniel Schwartz-Narbonne Date: Wed, 24 Jul 2024 15:12:57 -0400 Subject: [PATCH 02/31] crashtracker in its own ffi library --- Cargo.lock | 5 + LICENSE-3rdparty.yml | 2 +- crashtracker-ffi/Cargo.toml | 14 +- crashtracker-ffi/src/collector/counters.rs | 52 ++++ crashtracker-ffi/src/collector/datatypes.rs | 134 ++++++++++ crashtracker-ffi/src/collector/mod.rs | 97 +++++++ crashtracker-ffi/src/collector/spans.rs | 166 ++++++++++++ crashtracker-ffi/src/crash_info/datatypes.rs | 255 ++++++++++++++++++ crashtracker-ffi/src/crash_info/mod.rs | 256 +++++++++++++++++++ crashtracker-ffi/src/datatypes/mod.rs | 32 +++ crashtracker-ffi/src/demangler/datatypes.rs | 42 +++ crashtracker-ffi/src/demangler/mod.rs | 62 +++++ crashtracker-ffi/src/lib.rs | 18 ++ crashtracker-ffi/src/receiver.rs | 48 ++++ 14 files changed, 1180 insertions(+), 3 deletions(-) create mode 100644 crashtracker-ffi/src/collector/counters.rs create mode 100644 crashtracker-ffi/src/collector/datatypes.rs create mode 100644 crashtracker-ffi/src/collector/mod.rs create mode 100644 crashtracker-ffi/src/collector/spans.rs create mode 100644 crashtracker-ffi/src/crash_info/datatypes.rs create mode 100644 crashtracker-ffi/src/crash_info/mod.rs create mode 100644 crashtracker-ffi/src/datatypes/mod.rs create mode 100644 crashtracker-ffi/src/demangler/datatypes.rs create mode 100644 crashtracker-ffi/src/demangler/mod.rs create mode 100644 crashtracker-ffi/src/receiver.rs diff --git a/Cargo.lock b/Cargo.lock index b60ea48d7..11de9874e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1125,8 +1125,13 @@ version = "11.0.0" dependencies = [ "anyhow", "build_common", + "chrono", + "datadog-crashtracker", "ddcommon", + "ddcommon-ffi", "hyper 0.14.28", + "symbolic-common", + "symbolic-demangle", ] [[package]] diff --git a/LICENSE-3rdparty.yml b/LICENSE-3rdparty.yml index 02092bb0e..7ad0631a6 100644 --- a/LICENSE-3rdparty.yml +++ b/LICENSE-3rdparty.yml @@ -1,4 +1,4 @@ -root_name: datadog-alloc, datadog-crashtracker, ddcommon, ddtelemetry, datadog-ddsketch, datadog-profiling, datadog-profiling-ffi, data-pipeline-ffi, data-pipeline, datadog-trace-normalization, datadog-trace-protobuf, datadog-trace-utils, ddcommon-ffi, build_common, ddtelemetry-ffi, symbolizer-ffi, datadog-profiling-replayer, tools, datadog-ipc, datadog-ipc-macros, tarpc, tarpc-plugins, spawn_worker, cc_utils, datadog-sidecar, datadog-sidecar-macros, datadog-sidecar-ffi, sidecar_mockgen, datadog-trace-obfuscation, test_spawn_from_lib, datadog-serverless-trace-mini-agent, datadog-trace-mini-agent +root_name: datadog-alloc, datadog-crashtracker, ddcommon, ddtelemetry, datadog-ddsketch, crashtracker-ffi, ddcommon-ffi, build_common, datadog-profiling, datadog-profiling-ffi, data-pipeline-ffi, data-pipeline, datadog-trace-normalization, datadog-trace-protobuf, datadog-trace-utils, ddtelemetry-ffi, symbolizer-ffi, datadog-profiling-replayer, tools, datadog-ipc, datadog-ipc-macros, tarpc, tarpc-plugins, spawn_worker, cc_utils, datadog-sidecar, datadog-sidecar-macros, datadog-sidecar-ffi, sidecar_mockgen, datadog-trace-obfuscation, test_spawn_from_lib, datadog-serverless-trace-mini-agent, datadog-trace-mini-agent third_party_libraries: - package_name: addr2line package_version: 0.21.0 diff --git a/crashtracker-ffi/Cargo.toml b/crashtracker-ffi/Cargo.toml index 24fc954c1..cfa38f680 100644 --- a/crashtracker-ffi/Cargo.toml +++ b/crashtracker-ffi/Cargo.toml @@ -9,16 +9,26 @@ rust-version.workspace = true license.workspace = true [lib] +#FIXME: should this be like profiling-ffi or like ddcommon-ffi? bench =false [features] -default = ["cbindgen"] +default = ["cbindgen", "collector", "receiver"] cbindgen = ["build_common/cbindgen"] +# Enables the in-process collection of crash-info +collector = [] +# Enables the use of this library to receiver crash-info from a suitable collector +receiver = [] [build-dependencies] build_common = { path = "../build-common" } [dependencies] -ddcommon = { path = "../ddcommon" } anyhow = "1.0" +chrono = {version = "0.4", default-features = false } +datadog-crashtracker = { path = "../crashtracker" } +ddcommon = { path = "../ddcommon" } +ddcommon-ffi = { path = "../ddcommon-ffi", default-features = false } hyper = {version = "0.14", default-features = false} +symbolic-demangle = { version = "12.8.0", default-features = false, features = ["rust", "cpp", "msvc"] } +symbolic-common = "12.8.0" diff --git a/crashtracker-ffi/src/collector/counters.rs b/crashtracker-ffi/src/collector/counters.rs new file mode 100644 index 000000000..8581af4ea --- /dev/null +++ b/crashtracker-ffi/src/collector/counters.rs @@ -0,0 +1,52 @@ +// Copyright 2024-Present Datadog, Inc. https://www.datadoghq.com/ +// SPDX-License-Identifier: Apache-2.0 + +use super::datatypes::ProfilingOpTypes; +use crate::CrashtrackerResult; +use anyhow::Context; + +/// Resets all counters to 0. +/// Expected to be used after a fork, to reset the counters on the child +/// ATOMICITY: +/// This is NOT ATOMIC. +/// Should only be used when no conflicting updates can occur, +/// e.g. after a fork but before profiling ops start on the child. +/// # Safety +/// No safety concerns. +#[no_mangle] +#[must_use] +pub unsafe extern "C" fn ddog_prof_Crashtracker_reset_counters() -> CrashtrackerResult { + datadog_crashtracker::reset_counters() + .context("ddog_prof_Crashtracker_begin_profiling_op failed") + .into() +} + +#[no_mangle] +#[must_use] +/// Atomically increments the count associated with `op`. +/// Useful for tracking what operations were occuring when a crash occurred. +/// +/// # Safety +/// No safety concerns. +pub unsafe extern "C" fn ddog_prof_Crashtracker_begin_profiling_op( + op: ProfilingOpTypes, +) -> CrashtrackerResult { + datadog_crashtracker::begin_profiling_op(op) + .context("ddog_prof_Crashtracker_begin_profiling_op failed") + .into() +} + +#[no_mangle] +#[must_use] +/// Atomically decrements the count associated with `op`. +/// Useful for tracking what operations were occuring when a crash occurred. +/// +/// # Safety +/// No safety concerns. +pub unsafe extern "C" fn ddog_prof_Crashtracker_end_profiling_op( + op: ProfilingOpTypes, +) -> CrashtrackerResult { + datadog_crashtracker::end_profiling_op(op) + .context("ddog_prof_Crashtracker_end_profiling_op failed") + .into() +} diff --git a/crashtracker-ffi/src/collector/datatypes.rs b/crashtracker-ffi/src/collector/datatypes.rs new file mode 100644 index 000000000..25a182626 --- /dev/null +++ b/crashtracker-ffi/src/collector/datatypes.rs @@ -0,0 +1,134 @@ +// Copyright 2024-Present Datadog, Inc. https://www.datadoghq.com/ +// SPDX-License-Identifier: Apache-2.0 + +//use crate::exporter::{self, ProfilingEndpoint}; +use crate::{option_from_char_slice, ProfilingEndpoint}; +pub use datadog_crashtracker::{ProfilingOpTypes, StacktraceCollection}; +use ddcommon_ffi::slice::{AsBytes, CharSlice}; +use ddcommon_ffi::{Error, Slice}; + +#[repr(C)] +pub struct EnvVar<'a> { + key: CharSlice<'a>, + val: CharSlice<'a>, +} + +#[repr(C)] +pub struct CrashtrackerReceiverConfig<'a> { + pub args: Slice<'a, CharSlice<'a>>, + pub env: Slice<'a, EnvVar<'a>>, + pub path_to_receiver_binary: CharSlice<'a>, + /// Optional filename to forward stderr to (useful for logging/debugging) + pub optional_stderr_filename: CharSlice<'a>, + /// Optional filename to forward stdout to (useful for logging/debugging) + pub optional_stdout_filename: CharSlice<'a>, +} + +impl<'a> TryFrom> + for datadog_crashtracker::CrashtrackerReceiverConfig +{ + type Error = anyhow::Error; + fn try_from(value: CrashtrackerReceiverConfig<'a>) -> anyhow::Result { + let args = { + let mut vec = Vec::with_capacity(value.args.len()); + for x in value.args.iter() { + vec.push(x.try_to_utf8()?.to_string()); + } + vec + }; + let env = { + let mut vec = Vec::with_capacity(value.env.len()); + for x in value.env.iter() { + vec.push(( + x.key.try_to_utf8()?.to_string(), + x.val.try_to_utf8()?.to_string(), + )); + } + vec + }; + let path_to_receiver_binary = value.path_to_receiver_binary.try_to_utf8()?.to_string(); + let stderr_filename = option_from_char_slice(value.optional_stderr_filename)?; + let stdout_filename = option_from_char_slice(value.optional_stdout_filename)?; + Self::new( + args, + env, + path_to_receiver_binary, + stderr_filename, + stdout_filename, + ) + } +} + +#[repr(C)] +pub struct CrashtrackerConfiguration<'a> { + pub additional_files: Slice<'a, CharSlice<'a>>, + pub create_alt_stack: bool, + /// The endpoint to send the crash report to (can be a file://) + /// + /// If ProfilingEndpoint is left to a zero value (enum value for Agent + empty charslice), + /// the crashtracker will infer the agent host from env variables. + pub endpoint: ProfilingEndpoint<'a>, + pub resolve_frames: StacktraceCollection, + pub timeout_secs: u64, + pub wait_for_receiver: bool, +} + +impl<'a> TryFrom> + for datadog_crashtracker::CrashtrackerConfiguration +{ + type Error = anyhow::Error; + fn try_from(value: CrashtrackerConfiguration<'a>) -> anyhow::Result { + let additional_files = { + let mut vec = Vec::with_capacity(value.additional_files.len()); + for x in value.additional_files.iter() { + vec.push(x.try_to_utf8()?.to_string()); + } + vec + }; + let create_alt_stack = value.create_alt_stack; + let endpoint = None; // DSNunsafe { exporter::try_to_endpoint(value.endpoint).ok() }; + let resolve_frames = value.resolve_frames; + let wait_for_receiver = value.wait_for_receiver; + Self::new( + additional_files, + create_alt_stack, + endpoint, + resolve_frames, + wait_for_receiver, + ) + } +} + +#[repr(C)] +pub enum CrashtrackerUsizeResult { + Ok(usize), + #[allow(dead_code)] + Err(Error), +} + +impl From> for CrashtrackerUsizeResult { + fn from(value: anyhow::Result) -> Self { + match value { + Ok(x) => Self::Ok(x), + Err(err) => Self::Err(err.into()), + } + } +} + +#[repr(C)] +pub enum CrashtrackerGetCountersResult { + Ok([i64; ProfilingOpTypes::SIZE as usize]), + #[allow(dead_code)] + Err(Error), +} + +impl From> + for CrashtrackerGetCountersResult +{ + fn from(value: anyhow::Result<[i64; ProfilingOpTypes::SIZE as usize]>) -> Self { + match value { + Ok(x) => Self::Ok(x), + Err(err) => Self::Err(err.into()), + } + } +} diff --git a/crashtracker-ffi/src/collector/mod.rs b/crashtracker-ffi/src/collector/mod.rs new file mode 100644 index 000000000..d2a11f662 --- /dev/null +++ b/crashtracker-ffi/src/collector/mod.rs @@ -0,0 +1,97 @@ +// Copyright 2021-Present Datadog, Inc. https://www.datadoghq.com/ +// SPDX-License-Identifier: Apache-2.0 +mod counters; +mod datatypes; +mod spans; + +use super::crash_info::CrashtrackerMetadata; +use crate::CrashtrackerResult; +use anyhow::Context; +pub use counters::*; +pub use datatypes::*; +pub use spans::*; + +#[no_mangle] +#[must_use] +/// Cleans up after the crash-tracker: +/// Unregister the crash handler, restore the previous handler (if any), and +/// shut down the receiver. Note that the use of this function is optional: +/// the receiver will automatically shutdown when the pipe is closed on program +/// exit. +/// +/// # Preconditions +/// This function assumes that the crash-tracker has previously been +/// initialized. +/// # Safety +/// Crash-tracking functions are not reentrant. +/// No other crash-handler functions should be called concurrently. +/// # Atomicity +/// This function is not atomic. A crash during its execution may lead to +/// unexpected crash-handling behaviour. +pub unsafe extern "C" fn ddog_prof_Crashtracker_shutdown() -> CrashtrackerResult { + datadog_crashtracker::shutdown_crash_handler() + .context("ddog_prof_Crashtracker_shutdown failed") + .into() +} + +#[no_mangle] +#[must_use] +/// Reinitialize the crash-tracking infrastructure after a fork. +/// This should be one of the first things done after a fork, to minimize the +/// chance that a crash occurs between the fork, and this call. +/// In particular, reset the counters that track the profiler state machine, +/// and start a new receiver to collect data from this fork. +/// NOTE: An alternative design would be to have a 1:many sidecar listening on a +/// socket instead of 1:1 receiver listening on a pipe, but the only real +/// advantage would be to have fewer processes in `ps -a`. +/// +/// # Preconditions +/// This function assumes that the crash-tracker has previously been +/// initialized. +/// # Safety +/// Crash-tracking functions are not reentrant. +/// No other crash-handler functions should be called concurrently. +/// # Atomicity +/// This function is not atomic. A crash during its execution may lead to +/// unexpected crash-handling behaviour. +pub unsafe extern "C" fn ddog_prof_Crashtracker_update_on_fork( + config: CrashtrackerConfiguration, + receiver_config: CrashtrackerReceiverConfig, + metadata: CrashtrackerMetadata, +) -> CrashtrackerResult { + (|| { + let config = config.try_into()?; + let receiver_config = receiver_config.try_into()?; + let metadata = metadata.try_into()?; + datadog_crashtracker::on_fork(config, receiver_config, metadata) + })() + .context("ddog_prof_Crashtracker_update_on_fork failed") + .into() +} + +#[no_mangle] +#[must_use] +/// Initialize the crash-tracking infrastructure. +/// +/// # Preconditions +/// None. +/// # Safety +/// Crash-tracking functions are not reentrant. +/// No other crash-handler functions should be called concurrently. +/// # Atomicity +/// This function is not atomic. A crash during its execution may lead to +/// unexpected crash-handling behaviour. +pub unsafe extern "C" fn ddog_prof_Crashtracker_init_with_receiver( + config: CrashtrackerConfiguration, + receiver_config: CrashtrackerReceiverConfig, + metadata: CrashtrackerMetadata, +) -> CrashtrackerResult { + (|| { + let config = config.try_into()?; + let receiver_config = receiver_config.try_into()?; + let metadata = metadata.try_into()?; + datadog_crashtracker::init_with_receiver(config, receiver_config, metadata) + })() + .context("ddog_prof_Crashtracker_init failed") + .into() +} diff --git a/crashtracker-ffi/src/collector/spans.rs b/crashtracker-ffi/src/collector/spans.rs new file mode 100644 index 000000000..063573a96 --- /dev/null +++ b/crashtracker-ffi/src/collector/spans.rs @@ -0,0 +1,166 @@ +// Copyright 2024-Present Datadog, Inc. https://www.datadoghq.com/ +// SPDX-License-Identifier: Apache-2.0 + +use crate::{CrashtrackerResult, CrashtrackerUsizeResult}; +use anyhow::Context; + +/// Resets all stored spans to 0. +/// Expected to be used after a fork, to reset the spans on the child +/// ATOMICITY: +/// This is NOT ATOMIC. +/// Should only be used when no conflicting updates can occur, +/// e.g. after a fork but before profiling ops start on the child. +/// # Safety +/// No safety concerns. +#[no_mangle] +#[must_use] +pub unsafe extern "C" fn ddog_prof_Crashtracker_clear_span_ids() -> CrashtrackerResult { + datadog_crashtracker::clear_spans() + .context("ddog_prof_Crashtracker_clear_span_ids failed") + .into() +} + +/// Resets all stored traces to 0. +/// Expected to be used after a fork, to reset the traces on the child +/// ATOMICITY: +/// This is NOT ATOMIC. +/// Should only be used when no conflicting updates can occur, +/// e.g. after a fork but before profiling ops start on the child. +/// # Safety +/// No safety concerns. +#[no_mangle] +#[must_use] +pub unsafe extern "C" fn ddog_prof_Crashtracker_clear_trace_ids() -> CrashtrackerResult { + datadog_crashtracker::clear_traces() + .context("ddog_prof_Crashtracker_clear_trace_ids failed") + .into() +} + +#[no_mangle] +#[must_use] +/// Atomically registers an active traceId. +/// Useful for tracking what operations were occurring when a crash occurred. +/// 0 is reserved for "NoId" +/// The set does not check for duplicates. Adding the same id twice is an error. +/// +/// Inputs: +/// id: the 128 bit id, broken into 2 64 bit chunks (see note) +/// +/// Returns: +/// Ok(handle) on success. The handle is needed to later remove the id; +/// Err() on failure. The most likely cause of failure is that the underlying set is full. +/// +/// Note: 128 bit ints in FFI were not stabilized until Rust 1.77 +/// https://blog.rust-lang.org/2024/03/30/i128-layout-update.html +/// We're currently locked into 1.71, have to do an ugly workaround involving 2 64 bit ints +/// until we can upgrade. +/// +/// # Safety +/// No safety concerns. +pub unsafe extern "C" fn ddog_prof_Crashtracker_insert_trace_id( + id_high: u64, + id_low: u64, +) -> CrashtrackerUsizeResult { + let id: u128 = (id_high as u128) << 64 | (id_low as u128); + datadog_crashtracker::insert_trace(id) + .context("ddog_prof_Crashtracker_insert_trace_id failed") + .into() +} + +#[no_mangle] +#[must_use] +/// Atomically registers an active SpanId. +/// Useful for tracking what operations were occurring when a crash occurred. +/// 0 is reserved for "NoId". +/// The set does not check for duplicates. Adding the same id twice is an error. +/// +/// Inputs: +/// id: the 128 bit id, broken into 2 64 bit chunks (see note) +/// +/// Returns: +/// Ok(handle) on success. The handle is needed to later remove the id; +/// Err() on failure. The most likely cause of failure is that the underlying set is full. +/// +/// Note: 128 bit ints in FFI were not stabilized until Rust 1.77 +/// https://blog.rust-lang.org/2024/03/30/i128-layout-update.html +/// We're currently locked into 1.71, have to do an ugly workaround involving 2 64 bit ints +/// until we can upgrade. + +/// +/// # Safety +/// No safety concerns. +pub unsafe extern "C" fn ddog_prof_Crashtracker_insert_span_id( + id_high: u64, + id_low: u64, +) -> CrashtrackerUsizeResult { + let id: u128 = (id_high as u128) << 64 | (id_low as u128); + datadog_crashtracker::insert_span(id) + .context("ddog_prof_Crashtracker_insert_span_id failed") + .into() +} + +#[no_mangle] +#[must_use] +/// Atomically removes a completed SpanId. +/// Useful for tracking what operations were occurring when a crash occurred. +/// 0 is reserved for "NoId" +/// +/// Inputs: +/// id: the 128 bit id, broken into 2 64 bit chunks (see note) +/// idx: The handle for the id, from a previous successful call to `insert_span_id`. +/// Attempting to remove the same element twice is an error. +/// Returns: +/// `Ok` on success. +/// `Err` on failure. If `id` is not found at `idx`, `Err` will be returned and the set will not +/// be modified. +/// +/// Note: 128 bit ints in FFI were not stabilized until Rust 1.77 +/// https://blog.rust-lang.org/2024/03/30/i128-layout-update.html +/// We're currently locked into 1.71, have to do an ugly workaround involving 2 64 bit ints +/// until we can upgrade. +/// +/// # Safety +/// No safety concerns. +pub unsafe extern "C" fn ddog_prof_Crashtracker_remove_span_id( + id_high: u64, + id_low: u64, + idx: usize, +) -> CrashtrackerResult { + let id: u128 = (id_high as u128) << 64 | (id_low as u128); + datadog_crashtracker::remove_span(id, idx) + .context("ddog_prof_Crashtracker_remove_span_id failed") + .into() +} + +#[no_mangle] +#[must_use] +/// Atomically removes a completed TraceId. +/// Useful for tracking what operations were occurring when a crash occurred. +/// 0 is reserved for "NoId" +/// +/// Inputs: +/// id: the 128 bit id, broken into 2 64 bit chunks (see note) +/// idx: The handle for the id, from a previous successful call to `insert_span_id`. +/// Attempting to remove the same element twice is an error. +/// Returns: +/// `Ok` on success. +/// `Err` on failure. If `id` is not found at `idx`, `Err` will be returned and the set will not +/// be modified. +/// +/// Note: 128 bit ints in FFI were not stabilized until Rust 1.77 +/// https://blog.rust-lang.org/2024/03/30/i128-layout-update.html +/// We're currently locked into 1.71, have to do an ugly workaround involving 2 64 bit ints +/// until we can upgrade. +/// +/// # Safety +/// No safety concerns. +pub unsafe extern "C" fn ddog_prof_Crashtracker_remove_trace_id( + id_high: u64, + id_low: u64, + idx: usize, +) -> CrashtrackerResult { + let id: u128 = (id_high as u128) << 64 | (id_low as u128); + datadog_crashtracker::remove_trace(id, idx) + .context("ddog_prof_Crashtracker_remove_trace_id failed") + .into() +} diff --git a/crashtracker-ffi/src/crash_info/datatypes.rs b/crashtracker-ffi/src/crash_info/datatypes.rs new file mode 100644 index 000000000..5f75a1537 --- /dev/null +++ b/crashtracker-ffi/src/crash_info/datatypes.rs @@ -0,0 +1,255 @@ +// Copyright 2024-Present Datadog, Inc. https://www.datadoghq.com/ +// SPDX-License-Identifier: Apache-2.0 + +use crate::option_from_char_slice; +use ddcommon::tag::Tag; +use ddcommon_ffi::{ + slice::{AsBytes, ByteSlice}, + CharSlice, Error, Slice, +}; + +/// Represents a CrashInfo. Do not access its member for any reason, only use +/// the C API functions on this struct. +#[repr(C)] +pub struct CrashInfo { + // This may be null, but if not it will point to a valid CrashInfo. + inner: *mut datadog_crashtracker::CrashInfo, +} + +impl CrashInfo { + pub(super) fn new(crash_info: datadog_crashtracker::CrashInfo) -> Self { + CrashInfo { + inner: Box::into_raw(Box::new(crash_info)), + } + } + + pub(super) fn take(&mut self) -> Option> { + // Leaving a null will help with double-free issues that can + // arise in C. Of course, it's best to never get there in the + // first place! + let raw = std::mem::replace(&mut self.inner, std::ptr::null_mut()); + + if raw.is_null() { + None + } else { + Some(unsafe { Box::from_raw(raw) }) + } + } +} + +impl Drop for CrashInfo { + fn drop(&mut self) { + drop(self.take()) + } +} + +pub(crate) unsafe fn crashinfo_ptr_to_inner<'a>( + crashinfo_ptr: *mut CrashInfo, +) -> anyhow::Result<&'a mut datadog_crashtracker::CrashInfo> { + match crashinfo_ptr.as_mut() { + None => anyhow::bail!("crashinfo pointer was null"), + Some(inner_ptr) => match inner_ptr.inner.as_mut() { + Some(crashinfo) => Ok(crashinfo), + None => anyhow::bail!("crashinfo's inner pointer was null (indicates use-after-free)"), + }, + } +} + +/// Returned by [ddog_prof_Profile_new]. +#[repr(C)] +pub enum CrashInfoNewResult { + Ok(CrashInfo), + #[allow(dead_code)] + Err(Error), +} + +#[repr(C)] +#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)] +pub enum NormalizedAddressTypes { + // Make None 0 so that default construction gives none + None = 0, + Elf, +} + +#[repr(C)] +pub struct NormalizedAddress<'a> { + file_offset: u64, + build_id: ByteSlice<'a>, + path: CharSlice<'a>, + typ: NormalizedAddressTypes, +} + +impl<'a> TryFrom> for Option { + type Error = anyhow::Error; + + fn try_from(value: NormalizedAddress<'a>) -> Result { + Self::try_from(&value) + } +} + +impl<'a> TryFrom<&NormalizedAddress<'a>> for Option { + type Error = anyhow::Error; + + fn try_from(value: &NormalizedAddress<'a>) -> Result { + if value.typ == NormalizedAddressTypes::None { + Ok(None) + } else { + Ok(Some(value.try_into()?)) + } + } +} + +impl<'a> TryFrom> for datadog_crashtracker::NormalizedAddress { + type Error = anyhow::Error; + + fn try_from(value: NormalizedAddress<'a>) -> Result { + Self::try_from(&value) + } +} + +impl<'a> TryFrom<&NormalizedAddress<'a>> for datadog_crashtracker::NormalizedAddress { + type Error = anyhow::Error; + + fn try_from(value: &NormalizedAddress<'a>) -> Result { + match &value.typ { + NormalizedAddressTypes::Elf => { + let build_id = if value.build_id.is_empty() { + None + } else { + Some(Vec::from(value.build_id.as_bytes())) + }; + let path = value.path.try_to_utf8()?.into(); + let meta = datadog_crashtracker::NormalizedAddressMeta::Elf { build_id, path }; + Ok(Self { + file_offset: value.file_offset, + meta, + }) + } + _ => anyhow::bail!("Unsupported normalized address type {:?}", value.typ), + } + } +} + +#[repr(C)] +pub struct StackFrameNames<'a> { + colno: ddcommon_ffi::Option, + filename: CharSlice<'a>, + lineno: ddcommon_ffi::Option, + name: CharSlice<'a>, +} + +impl<'a> TryFrom> for datadog_crashtracker::StackFrameNames { + type Error = anyhow::Error; + + fn try_from(value: StackFrameNames<'a>) -> Result { + Self::try_from(&value) + } +} + +impl<'a> TryFrom<&StackFrameNames<'a>> for datadog_crashtracker::StackFrameNames { + type Error = anyhow::Error; + + fn try_from(value: &StackFrameNames<'a>) -> Result { + let colno = (&value.colno).into(); + let filename = option_from_char_slice(value.filename)?; + let lineno = (&value.lineno).into(); + let name = option_from_char_slice(value.name)?; + Ok(Self { + colno, + filename, + lineno, + name, + }) + } +} + +#[repr(C)] +pub struct StackFrame<'a> { + build_id: CharSlice<'a>, + ip: usize, + module_base_address: usize, + names: Slice<'a, StackFrameNames<'a>>, + normalized_ip: NormalizedAddress<'a>, + sp: usize, + symbol_address: usize, +} + +impl<'a> TryFrom<&StackFrame<'a>> for datadog_crashtracker::StackFrame { + type Error = anyhow::Error; + + fn try_from(value: &StackFrame<'a>) -> Result { + fn to_hex(v: usize) -> Option { + if v == 0 { + None + } else { + Some(format!("{v:#X}")) + } + } + let ip = to_hex(value.ip); + let module_base_address = to_hex(value.module_base_address); + let names = if value.names.is_empty() { + None + } else { + let mut vec = Vec::with_capacity(value.names.len()); + for x in value.names.iter() { + vec.push(x.try_into()?); + } + Some(vec) + }; + let normalized_ip = (&value.normalized_ip).try_into()?; + let sp = to_hex(value.sp); + let symbol_address = to_hex(value.symbol_address); + Ok(Self { + ip, + module_base_address, + names, + normalized_ip, + sp, + symbol_address, + }) + } +} + +#[repr(C)] +pub struct SigInfo<'a> { + pub signum: u64, + pub signame: CharSlice<'a>, +} + +impl<'a> TryFrom> for datadog_crashtracker::SigInfo { + type Error = anyhow::Error; + + fn try_from(value: SigInfo<'a>) -> Result { + let signum = value.signum; + let signame = option_from_char_slice(value.signame)?; + Ok(Self { signum, signame }) + } +} + +#[repr(C)] +pub struct CrashtrackerMetadata<'a> { + pub profiling_library_name: CharSlice<'a>, + pub profiling_library_version: CharSlice<'a>, + pub family: CharSlice<'a>, + /// Should include "service", "environment", etc + pub tags: Option<&'a ddcommon_ffi::Vec>, +} + +impl<'a> TryFrom> for datadog_crashtracker::CrashtrackerMetadata { + type Error = anyhow::Error; + fn try_from(value: CrashtrackerMetadata<'a>) -> anyhow::Result { + let profiling_library_name = value.profiling_library_name.try_to_utf8()?.to_string(); + let profiling_library_version = value.profiling_library_version.try_to_utf8()?.to_string(); + let family = value.family.try_to_utf8()?.to_string(); + let tags = value + .tags + .map(|tags| tags.iter().cloned().collect()) + .unwrap_or_default(); + Ok(Self::new( + profiling_library_name, + profiling_library_version, + family, + tags, + )) + } +} diff --git a/crashtracker-ffi/src/crash_info/mod.rs b/crashtracker-ffi/src/crash_info/mod.rs new file mode 100644 index 000000000..19632f86b --- /dev/null +++ b/crashtracker-ffi/src/crash_info/mod.rs @@ -0,0 +1,256 @@ +// Copyright 2021-Present Datadog, Inc. https://www.datadoghq.com/ +// SPDX-License-Identifier: Apache-2.0 + +mod datatypes; +pub use datatypes::*; + +//DSN +#[repr(C)] +pub struct ProfilingEndpoint<'a> { + _nonempty: bool, + _pd: std::marker::PhantomData<&'a bool> +} + +use crate::{option_from_char_slice, CrashtrackerResult}; +use anyhow::Context; +use chrono::DateTime; +use ddcommon_ffi::{slice::AsBytes, CharSlice, Slice}; + +/// Create a new crashinfo, and returns an opaque reference to it. +/// # Safety +/// No safety issues. +#[no_mangle] +#[must_use] +pub unsafe extern "C" fn ddog_crashinfo_new() -> CrashInfoNewResult { + CrashInfoNewResult::Ok(CrashInfo::new(datadog_crashtracker::CrashInfo::new())) +} + +/// # Safety +/// The `crash_info` can be null, but if non-null it must point to a CrashInfo +/// made by this module, which has not previously been dropped. +#[no_mangle] +pub unsafe extern "C" fn ddog_crashinfo_drop(crashinfo: *mut CrashInfo) { + // Technically, this function has been designed so if it's double-dropped + // then it's okay, but it's not something that should be relied on. + if !crashinfo.is_null() { + drop((*crashinfo).take()) + } +} + +/// Best effort attempt to normalize all `ip` on the stacktrace. +/// `pid` must be the pid of the currently active process where the ips came from. +/// +/// # Safety +/// `crashinfo` must be a valid pointer to a `CrashInfo` object. +#[cfg(unix)] +#[no_mangle] +#[must_use] +pub unsafe extern "C" fn ddog_crashinfo_normalize_ips( + crashinfo: *mut CrashInfo, + pid: u32, +) -> CrashtrackerResult { + (|| { + let crashinfo = crashinfo_ptr_to_inner(crashinfo)?; + crashinfo.normalize_ips(pid) + })() + .context("ddog_crashinfo_normalize_ips failed") + .into() +} + +/// Adds a "counter" variable, with the given value. Useful for determining if +/// "interesting" operations were occurring when the crash did. +/// +/// # Safety +/// `crashinfo` must be a valid pointer to a `CrashInfo` object. +/// `name` should be a valid reference to a utf8 encoded String. +/// The string is copied into the crashinfo, so it does not need to outlive this +/// call. +#[no_mangle] +#[must_use] +pub unsafe extern "C" fn ddog_crashinfo_add_counter( + crashinfo: *mut CrashInfo, + name: CharSlice, + val: i64, +) -> CrashtrackerResult { + (|| { + let crashinfo = crashinfo_ptr_to_inner(crashinfo)?; + let name = name.to_utf8_lossy(); + crashinfo.add_counter(&name, val) + })() + .context("ddog_crashinfo_add_counter failed") + .into() +} + +/// Adds the contents of "file" to the crashinfo +/// +/// # Safety +/// `crashinfo` must be a valid pointer to a `CrashInfo` object. +/// `name` should be a valid reference to a utf8 encoded String. +/// The string is copied into the crashinfo, so it does not need to outlive this +/// call. +#[no_mangle] +#[must_use] +pub unsafe extern "C" fn ddog_crashinfo_add_file( + crashinfo: *mut CrashInfo, + name: CharSlice, +) -> CrashtrackerResult { + (|| { + let crashinfo = crashinfo_ptr_to_inner(crashinfo)?; + let name = name.to_utf8_lossy(); + crashinfo.add_file(&name) + })() + .context("ddog_crashinfo_add_file failed") + .into() +} + +/// Adds the tag with given "key" and "value" to the crashinfo +/// +/// # Safety +/// `crashinfo` must be a valid pointer to a `CrashInfo` object. +/// `key` should be a valid reference to a utf8 encoded String. +/// `value` should be a valid reference to a utf8 encoded String. +/// The string is copied into the crashinfo, so it does not need to outlive this +/// call. +#[no_mangle] +#[must_use] +pub unsafe extern "C" fn ddog_crashinfo_add_tag( + crashinfo: *mut CrashInfo, + key: CharSlice, + value: CharSlice, +) -> CrashtrackerResult { + (|| { + let crashinfo = crashinfo_ptr_to_inner(crashinfo)?; + let key = key.to_utf8_lossy().to_string(); + let value = value.to_utf8_lossy().to_string(); + crashinfo.add_tag(key, value) + })() + .context("ddog_crashinfo_add_tag failed") + .into() +} + +/// Sets the crashinfo metadata +/// +/// # Safety +/// `crashinfo` must be a valid pointer to a `CrashInfo` object. +/// All references inside `metadata` must be valid. +/// Strings are copied into the crashinfo, and do not need to outlive this call. +#[no_mangle] +#[must_use] +pub unsafe extern "C" fn ddog_crashinfo_set_metadata( + crashinfo: *mut CrashInfo, + metadata: CrashtrackerMetadata, +) -> CrashtrackerResult { + (|| { + let crashinfo = crashinfo_ptr_to_inner(crashinfo)?; + let metadata = metadata.try_into()?; + crashinfo.set_metadata(metadata) + })() + .context("ddog_crashinfo_set_metadata failed") + .into() +} + +/// Sets the crashinfo siginfo +/// +/// # Safety +/// `crashinfo` must be a valid pointer to a `CrashInfo` object. +/// All references inside `metadata` must be valid. +/// Strings are copied into the crashinfo, and do not need to outlive this call. +#[no_mangle] +#[must_use] +pub unsafe extern "C" fn ddog_crashinfo_set_siginfo( + crashinfo: *mut CrashInfo, + siginfo: SigInfo, +) -> CrashtrackerResult { + (|| { + let crashinfo = crashinfo_ptr_to_inner(crashinfo)?; + let siginfo = siginfo.try_into()?; + crashinfo.set_siginfo(siginfo) + })() + .context("ddog_crashinfo_set_siginfo failed") + .into() +} + +/// If `thread_id` is empty, sets `stacktrace` as the default stacktrace. +/// Otherwise, adds an additional stacktrace with id "thread_id". +/// +/// # Safety +/// `crashinfo` must be a valid pointer to a `CrashInfo` object. +/// All references inside `stacktraces` must be valid. +/// Strings are copied into the crashinfo, and do not need to outlive this call. +#[no_mangle] +#[must_use] +pub unsafe extern "C" fn ddog_crashinfo_set_stacktrace( + crashinfo: *mut CrashInfo, + thread_id: CharSlice, + stacktrace: Slice, +) -> CrashtrackerResult { + (|| { + let crashinfo = crashinfo_ptr_to_inner(crashinfo)?; + let thread_id = option_from_char_slice(thread_id)?; + let mut stacktrace_vec = Vec::with_capacity(stacktrace.len()); + for s in stacktrace.iter() { + stacktrace_vec.push(s.try_into()?) + } + crashinfo.set_stacktrace(thread_id, stacktrace_vec) + })() + .context("ddog_crashinfo_set_stacktrace failed") + .into() +} + +/// Sets the timestamp to the given unix timestamp +/// +/// # Safety +/// `crashinfo` must be a valid pointer to a `CrashInfo` object. +#[no_mangle] +#[must_use] +pub unsafe extern "C" fn ddog_crashinfo_set_timestamp( + crashinfo: *mut CrashInfo, + secs: i64, + nsecs: u32, +) -> CrashtrackerResult { + (|| { + let crashinfo = crashinfo_ptr_to_inner(crashinfo)?; + let ts = DateTime::from_timestamp(secs, nsecs) + .with_context(|| format!("Invalid timestamp {secs} {nsecs}"))?; + crashinfo.set_timestamp(ts) + })() + .context("ddog_crashinfo_set_timestamp_to_now failed") + .into() +} + +/// Sets the timestamp to the current time +/// +/// # Safety +/// `crashinfo` must be a valid pointer to a `CrashInfo` object. +#[no_mangle] +#[must_use] +pub unsafe extern "C" fn ddog_crashinfo_set_timestamp_to_now( + crashinfo: *mut CrashInfo, +) -> CrashtrackerResult { + (|| { + let crashinfo = crashinfo_ptr_to_inner(crashinfo)?; + crashinfo.set_timestamp_to_now() + })() + .context("ddog_crashinfo_set_timestamp_to_now failed") + .into() +} + +/// Exports `crashinfo` to the backend at `endpoint` +/// Note that we support the "file://" endpoint for local file output. +/// # Safety +/// `crashinfo` must be a valid pointer to a `CrashInfo` object. +#[no_mangle] +#[must_use] +pub unsafe extern "C" fn ddog_crashinfo_upload_to_endpoint( + crashinfo: *mut CrashInfo, + _endpoint: ProfilingEndpoint, +) -> CrashtrackerResult { + (|| { + let crashinfo = crashinfo_ptr_to_inner(crashinfo)?; + // DSN + let endpoint = None; //Some(unsafe { crate::exporter::try_to_endpoint(endpoint)? }); + crashinfo.upload_to_endpoint(&endpoint) + })() + .context("ddog_crashinfo_upload_to_endpoint failed") + .into() +} diff --git a/crashtracker-ffi/src/datatypes/mod.rs b/crashtracker-ffi/src/datatypes/mod.rs new file mode 100644 index 000000000..ec7b51f7e --- /dev/null +++ b/crashtracker-ffi/src/datatypes/mod.rs @@ -0,0 +1,32 @@ +// Copyright 2021-Present Datadog, Inc. https://www.datadoghq.com/ +// SPDX-License-Identifier: Apache-2.0 + +use ddcommon_ffi::slice::{AsBytes, CharSlice}; +use ddcommon_ffi::Error; +use std::ops::Not; + +pub fn option_from_char_slice(s: CharSlice) -> anyhow::Result> { + let s = s.try_to_utf8()?.to_string(); + Ok(s.is_empty().not().then_some(s)) +} + +/// A generic result type for when a crashtracking operation may fail, +/// but there's nothing to return in the case of success. +#[repr(C)] +pub enum CrashtrackerResult { + Ok( + /// Do not use the value of Ok. This value only exists to overcome + /// Rust -> C code generation. + bool, + ), + Err(Error), +} + +impl From> for CrashtrackerResult { + fn from(value: anyhow::Result<()>) -> Self { + match value { + Ok(_) => Self::Ok(true), + Err(err) => Self::Err(err.into()), + } + } +} diff --git a/crashtracker-ffi/src/demangler/datatypes.rs b/crashtracker-ffi/src/demangler/datatypes.rs new file mode 100644 index 000000000..877bc1b9c --- /dev/null +++ b/crashtracker-ffi/src/demangler/datatypes.rs @@ -0,0 +1,42 @@ +// Copyright 2024-Present Datadog, Inc. https://www.datadoghq.com/ +// SPDX-License-Identifier: Apache-2.0 + +use ddcommon_ffi::{Error, StringWrapper}; + +#[repr(C)] +pub enum DemangleOptions { + Complete, + NameOnly, +} + +#[repr(C)] +pub enum StringWrapperResult { + Ok(StringWrapper), + #[allow(dead_code)] + Err(Error), +} + +// Useful for testing +impl StringWrapperResult { + pub fn unwrap(self) -> StringWrapper { + match self { + StringWrapperResult::Ok(s) => s, + StringWrapperResult::Err(e) => panic!("{e}"), + } + } +} + +impl From> for StringWrapperResult { + fn from(value: anyhow::Result) -> Self { + match value { + Ok(x) => Self::Ok(x.into()), + Err(err) => Self::Err(err.into()), + } + } +} + +impl From for StringWrapperResult { + fn from(value: String) -> Self { + Self::Ok(value.into()) + } +} diff --git a/crashtracker-ffi/src/demangler/mod.rs b/crashtracker-ffi/src/demangler/mod.rs new file mode 100644 index 000000000..3c1ed09bf --- /dev/null +++ b/crashtracker-ffi/src/demangler/mod.rs @@ -0,0 +1,62 @@ +// Copyright 2024-Present Datadog, Inc. https://www.datadoghq.com/ +// SPDX-License-Identifier: Apache-2.0 +mod datatypes; +pub use datatypes::*; + +use ddcommon_ffi::{slice::AsBytes, CharSlice}; +use symbolic_common::Name; +use symbolic_demangle::Demangle; + +/// Demangles the string "name". +/// If demangling fails, returns an empty string "" +/// +/// # Safety +/// `name` should be a valid reference to a utf8 encoded String. +/// The string is copied into the result, and does not need to outlive this call +#[no_mangle] +#[must_use] +pub unsafe extern "C" fn ddog_demangle( + name: CharSlice, + options: DemangleOptions, +) -> StringWrapperResult { + let name = name.to_utf8_lossy(); + let name = Name::from(name); + let options = match options { + DemangleOptions::Complete => symbolic_demangle::DemangleOptions::complete(), + DemangleOptions::NameOnly => symbolic_demangle::DemangleOptions::name_only(), + }; + StringWrapperResult::Ok(name.demangle(options).unwrap_or_default().into()) +} + +#[test] +fn test_demangle() { + let test_string = "_ZNSt28__atomic_futex_unsigned_base26_M_futex_wait_until_steadyEPjjbNSt6chrono8durationIlSt5ratioILl1ELl1EEEENS2_IlS3_ILl1ELl1000000000EEEE"; + let test_slice = CharSlice::from(test_string); + let result: String = unsafe { ddog_demangle(test_slice, DemangleOptions::Complete) } + .unwrap() + .into(); + assert_eq!(result, "std::__atomic_futex_unsigned_base::_M_futex_wait_until_steady(unsigned int*, unsigned int, bool, std::chrono::duration >, std::chrono::duration >)"); + + let result: String = unsafe { ddog_demangle(test_slice, DemangleOptions::NameOnly) } + .unwrap() + .into(); + assert_eq!( + result, + "std::__atomic_futex_unsigned_base::_M_futex_wait_until_steady" + ); +} + +#[test] +fn test_demangle_fails() { + let test_string = "_ZNSt28__fdf"; + let test_slice = CharSlice::from(test_string); + let result: String = unsafe { ddog_demangle(test_slice, DemangleOptions::Complete) } + .unwrap() + .into(); + assert_eq!(result, ""); + + let result: String = unsafe { ddog_demangle(test_slice, DemangleOptions::NameOnly) } + .unwrap() + .into(); + assert_eq!(result, ""); +} diff --git a/crashtracker-ffi/src/lib.rs b/crashtracker-ffi/src/lib.rs index e69de29bb..98d57dfe1 100644 --- a/crashtracker-ffi/src/lib.rs +++ b/crashtracker-ffi/src/lib.rs @@ -0,0 +1,18 @@ +// Copyright 2024-Present Datadog, Inc. https://www.datadoghq.com/ +// SPDX-License-Identifier: Apache-2.0 + +#[cfg(all(unix, feature = "collector"))] +mod collector; +mod crash_info; +mod datatypes; +mod demangler; +#[cfg(all(unix, feature = "receiver"))] +mod receiver; + +#[cfg(all(unix, feature = "collector"))] +pub use collector::*; +pub use crash_info::*; +pub use datatypes::*; +pub use demangler::*; +#[cfg(all(unix, feature = "receiver"))] +pub use receiver::*; diff --git a/crashtracker-ffi/src/receiver.rs b/crashtracker-ffi/src/receiver.rs new file mode 100644 index 000000000..c819b1e39 --- /dev/null +++ b/crashtracker-ffi/src/receiver.rs @@ -0,0 +1,48 @@ +// Copyright 2023-Present Datadog, Inc. https://www.datadoghq.com/ +// SPDX-License-Identifier: Apache-2.0 + +use crate::{CrashtrackerResult}; +use anyhow::Context; +use ddcommon_ffi::{slice::AsBytes, CharSlice}; +#[no_mangle] +#[must_use] +/// Receives data from a crash collector via a pipe on `stdin`, formats it into +/// `CrashInfo` json, and emits it to the endpoint/file defined in `config`. +/// +/// At a high-level, this exists because doing anything in a +/// signal handler is dangerous, so we fork a sidecar to do the stuff we aren't +/// allowed to do in the handler. +/// +/// See comments in [profiling/crashtracker/mod.rs] for a full architecture +/// description. +/// # Safety +/// No safety concerns +pub unsafe extern "C" fn ddog_prof_Crashtracker_receiver_entry_point_stdin() -> CrashtrackerResult { + datadog_crashtracker::receiver_entry_point_stdin() + .context("ddog_prof_Crashtracker_receiver_entry_point_stdin failed") + .into() +} + +#[no_mangle] +#[must_use] +/// Receives data from a crash collector via a pipe on `stdin`, formats it into +/// `CrashInfo` json, and emits it to the endpoint/file defined in `config`. +/// +/// At a high-level, this exists because doing anything in a +/// signal handler is dangerous, so we fork a sidecar to do the stuff we aren't +/// allowed to do in the handler. +/// +/// See comments in [profiling/crashtracker/mod.rs] for a full architecture +/// description. +/// # Safety +/// No safety concerns +pub unsafe extern "C" fn ddog_prof_Crashtracker_receiver_entry_point_unix_socket( + socket_path: CharSlice, +) -> CrashtrackerResult { + (|| { + let socket_path = socket_path.try_to_utf8()?; + datadog_crashtracker::reciever_entry_point_unix_socket(socket_path) + })() + .context("ddog_prof_Crashtracker_receiver_entry_point_unix_socket failed") + .into() +} From fc2aed23b6d621b15ff4facfa748f3f8fee923d6 Mon Sep 17 00:00:00 2001 From: Daniel Schwartz-Narbonne Date: Wed, 24 Jul 2024 15:15:09 -0400 Subject: [PATCH 03/31] ddcommon endpoint explicit --- ddcommon-ffi/src/endpoint.rs | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/ddcommon-ffi/src/endpoint.rs b/ddcommon-ffi/src/endpoint.rs index 6477e23d2..6ce12b677 100644 --- a/ddcommon-ffi/src/endpoint.rs +++ b/ddcommon-ffi/src/endpoint.rs @@ -3,16 +3,16 @@ use crate::slice::AsBytes; use crate::Error; -use ddcommon::{parse_uri, Endpoint}; +use ddcommon::{parse_uri}; use hyper::http::uri::{Authority, Parts}; use std::str::FromStr; #[no_mangle] #[must_use] -pub extern "C" fn ddog_endpoint_from_url(url: crate::CharSlice) -> Option> { +pub extern "C" fn ddog_endpoint_from_url(url: crate::CharSlice) -> Option> { parse_uri(url.to_utf8_lossy().as_ref()) .ok() - .map(|url| Box::new(Endpoint::from_url(url))) + .map(|url| Box::new(ddcommon::Endpoint::from_url(url))) } #[no_mangle] @@ -26,10 +26,10 @@ pub extern "C" fn ddog_endpoint_from_filename(filename: crate::CharSlice) -> Opt // own subdomains. #[no_mangle] #[must_use] -pub extern "C" fn ddog_endpoint_from_api_key(api_key: crate::CharSlice) -> Box { +pub extern "C" fn ddog_endpoint_from_api_key(api_key: crate::CharSlice) -> Box { let mut parts = Parts::default(); parts.authority = Some(Authority::from_static("datadoghq.com")); - Box::new(Endpoint { + Box::new(ddcommon::Endpoint { url: hyper::Uri::from_parts(parts).unwrap(), api_key: Some(api_key.to_utf8_lossy().to_string().into()), ..Default::default() @@ -43,14 +43,14 @@ pub extern "C" fn ddog_endpoint_from_api_key(api_key: crate::CharSlice) -> Box Option> { let mut parts = Parts::default(); parts.authority = Some(match Authority::from_str(&site.to_utf8_lossy()) { Ok(s) => s, Err(e) => return Some(Box::new(Error::from(e.to_string()))), }); - *endpoint = Box::into_raw(Box::new(Endpoint { + *endpoint = Box::into_raw(Box::new(ddcommon::Endpoint { url: hyper::Uri::from_parts(parts).unwrap(), api_key: Some(api_key.to_utf8_lossy().to_string().into()), ..Default::default() @@ -59,12 +59,12 @@ pub extern "C" fn ddog_endpoint_from_api_key_and_site( } #[no_mangle] -extern "C" fn ddog_endpoint_set_timeout(endpoint: &mut Endpoint, millis: u64) { +extern "C" fn ddog_endpoint_set_timeout(endpoint: &mut ddcommon::Endpoint, millis: u64) { endpoint.timeout_ms = millis; } #[no_mangle] -pub extern "C" fn ddog_endpoint_drop(_: Box) {} +pub extern "C" fn ddog_endpoint_drop(_: Box) {} #[cfg(test)] mod tests { @@ -96,14 +96,14 @@ mod tests { let mut endpoint = ddog_endpoint_from_url(url); assert_eq!( endpoint.as_ref().unwrap().timeout_ms, - Endpoint::DEFAULT_TIMEOUT + ddcommon::Endpoint::DEFAULT_TIMEOUT ); ddog_endpoint_set_timeout(endpoint.as_mut().unwrap(), 2000); assert_eq!(endpoint.unwrap().timeout_ms, 2000); let mut endpoint_api_key = ddog_endpoint_from_api_key(CharSlice::from("test-key")); - assert_eq!(endpoint_api_key.timeout_ms, Endpoint::DEFAULT_TIMEOUT); + assert_eq!(endpoint_api_key.timeout_ms, ddcommon::Endpoint::DEFAULT_TIMEOUT); ddog_endpoint_set_timeout(&mut endpoint_api_key, 2000); assert_eq!(endpoint_api_key.timeout_ms, 2000); From 930758b76b305223d9bab1535fc1a87faf5782aa Mon Sep 17 00:00:00 2001 From: Daniel Schwartz-Narbonne Date: Fri, 26 Jul 2024 14:43:28 -0400 Subject: [PATCH 04/31] use the common endpoint --- crashtracker-ffi/src/collector/datatypes.rs | 12 +++++------- crashtracker-ffi/src/crash_info/mod.rs | 2 +- crashtracker-ffi/src/receiver.rs | 2 +- ddcommon-ffi/src/endpoint.rs | 7 +++++-- .../src/crashtracker/collector/datatypes.rs | 6 ++---- 5 files changed, 14 insertions(+), 15 deletions(-) diff --git a/crashtracker-ffi/src/collector/datatypes.rs b/crashtracker-ffi/src/collector/datatypes.rs index 25a182626..1af121aed 100644 --- a/crashtracker-ffi/src/collector/datatypes.rs +++ b/crashtracker-ffi/src/collector/datatypes.rs @@ -1,9 +1,9 @@ // Copyright 2024-Present Datadog, Inc. https://www.datadoghq.com/ // SPDX-License-Identifier: Apache-2.0 -//use crate::exporter::{self, ProfilingEndpoint}; -use crate::{option_from_char_slice, ProfilingEndpoint}; +use crate::option_from_char_slice; pub use datadog_crashtracker::{ProfilingOpTypes, StacktraceCollection}; +use ddcommon::Endpoint; use ddcommon_ffi::slice::{AsBytes, CharSlice}; use ddcommon_ffi::{Error, Slice}; @@ -63,11 +63,9 @@ impl<'a> TryFrom> pub struct CrashtrackerConfiguration<'a> { pub additional_files: Slice<'a, CharSlice<'a>>, pub create_alt_stack: bool, - /// The endpoint to send the crash report to (can be a file://) - /// - /// If ProfilingEndpoint is left to a zero value (enum value for Agent + empty charslice), - /// the crashtracker will infer the agent host from env variables. - pub endpoint: ProfilingEndpoint<'a>, + /// 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 resolve_frames: StacktraceCollection, pub timeout_secs: u64, pub wait_for_receiver: bool, diff --git a/crashtracker-ffi/src/crash_info/mod.rs b/crashtracker-ffi/src/crash_info/mod.rs index 19632f86b..36a29907a 100644 --- a/crashtracker-ffi/src/crash_info/mod.rs +++ b/crashtracker-ffi/src/crash_info/mod.rs @@ -8,7 +8,7 @@ pub use datatypes::*; #[repr(C)] pub struct ProfilingEndpoint<'a> { _nonempty: bool, - _pd: std::marker::PhantomData<&'a bool> + _pd: std::marker::PhantomData<&'a bool>, } use crate::{option_from_char_slice, CrashtrackerResult}; diff --git a/crashtracker-ffi/src/receiver.rs b/crashtracker-ffi/src/receiver.rs index c819b1e39..e3d3ced24 100644 --- a/crashtracker-ffi/src/receiver.rs +++ b/crashtracker-ffi/src/receiver.rs @@ -1,7 +1,7 @@ // Copyright 2023-Present Datadog, Inc. https://www.datadoghq.com/ // SPDX-License-Identifier: Apache-2.0 -use crate::{CrashtrackerResult}; +use crate::CrashtrackerResult; use anyhow::Context; use ddcommon_ffi::{slice::AsBytes, CharSlice}; #[no_mangle] diff --git a/ddcommon-ffi/src/endpoint.rs b/ddcommon-ffi/src/endpoint.rs index 6ce12b677..34d317ed9 100644 --- a/ddcommon-ffi/src/endpoint.rs +++ b/ddcommon-ffi/src/endpoint.rs @@ -3,7 +3,7 @@ use crate::slice::AsBytes; use crate::Error; -use ddcommon::{parse_uri}; +use ddcommon::{parse_uri, Endpoint}; use hyper::http::uri::{Authority, Parts}; use std::str::FromStr; @@ -103,7 +103,10 @@ mod tests { assert_eq!(endpoint.unwrap().timeout_ms, 2000); let mut endpoint_api_key = ddog_endpoint_from_api_key(CharSlice::from("test-key")); - assert_eq!(endpoint_api_key.timeout_ms, ddcommon::Endpoint::DEFAULT_TIMEOUT); + assert_eq!( + endpoint_api_key.timeout_ms, + ddcommon::Endpoint::DEFAULT_TIMEOUT + ); ddog_endpoint_set_timeout(&mut endpoint_api_key, 2000); assert_eq!(endpoint_api_key.timeout_ms, 2000); diff --git a/profiling-ffi/src/crashtracker/collector/datatypes.rs b/profiling-ffi/src/crashtracker/collector/datatypes.rs index 4fe817e59..eb5dcea51 100644 --- a/profiling-ffi/src/crashtracker/collector/datatypes.rs +++ b/profiling-ffi/src/crashtracker/collector/datatypes.rs @@ -62,10 +62,8 @@ impl<'a> TryFrom> pub struct CrashtrackerConfiguration<'a> { pub additional_files: Slice<'a, CharSlice<'a>>, pub create_alt_stack: bool, - /// The endpoint to send the crash report to (can be a file://) - /// - /// If ProfilingEndpoint is left to a zero value (enum value for Agent + empty charslice), - /// the crashtracker will infer the agent host from env variables. + /// 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 ddcommon::Endpoint>, pub resolve_frames: StacktraceCollection, pub timeout_secs: u64, From 6d9c7d54e71e59779ea3485642804fa8342b88a4 Mon Sep 17 00:00:00 2001 From: Daniel Schwartz-Narbonne Date: Fri, 26 Jul 2024 15:17:15 -0400 Subject: [PATCH 05/31] builds as its own crate --- Cargo.lock | 2 +- build-profiling-ffi.sh | 2 +- crashtracker-ffi/cbindgen.toml | 14 +- .../libdatadog-crashtracking-receiver.c | 2 +- profiling-ffi/Cargo.toml | 7 +- .../src/crashtracker/collector/counters.rs | 52 ---- .../src/crashtracker/collector/datatypes.rs | 131 --------- .../src/crashtracker/collector/mod.rs | 97 ------- .../src/crashtracker/collector/spans.rs | 166 ------------ .../src/crashtracker/crash_info/datatypes.rs | 255 ------------------ .../src/crashtracker/crash_info/mod.rs | 251 ----------------- .../src/crashtracker/datatypes/mod.rs | 32 --- .../src/crashtracker/demangler/datatypes.rs | 42 --- .../src/crashtracker/demangler/mod.rs | 62 ----- profiling-ffi/src/crashtracker/mod.rs | 18 -- profiling-ffi/src/crashtracker/receiver.rs | 48 ---- profiling-ffi/src/lib.rs | 6 +- 17 files changed, 12 insertions(+), 1175 deletions(-) delete mode 100644 profiling-ffi/src/crashtracker/collector/counters.rs delete mode 100644 profiling-ffi/src/crashtracker/collector/datatypes.rs delete mode 100644 profiling-ffi/src/crashtracker/collector/mod.rs delete mode 100644 profiling-ffi/src/crashtracker/collector/spans.rs delete mode 100644 profiling-ffi/src/crashtracker/crash_info/datatypes.rs delete mode 100644 profiling-ffi/src/crashtracker/crash_info/mod.rs delete mode 100644 profiling-ffi/src/crashtracker/datatypes/mod.rs delete mode 100644 profiling-ffi/src/crashtracker/demangler/datatypes.rs delete mode 100644 profiling-ffi/src/crashtracker/demangler/mod.rs delete mode 100644 profiling-ffi/src/crashtracker/mod.rs delete mode 100644 profiling-ffi/src/crashtracker/receiver.rs diff --git a/Cargo.lock b/Cargo.lock index 11de9874e..cc2019a54 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1450,8 +1450,8 @@ dependencies = [ "anyhow", "build_common", "chrono", + "crashtracker-ffi", "data-pipeline-ffi", - "datadog-crashtracker", "datadog-profiling", "ddcommon", "ddcommon-ffi", diff --git a/build-profiling-ffi.sh b/build-profiling-ffi.sh index 637e31f7c..e71211464 100755 --- a/build-profiling-ffi.sh +++ b/build-profiling-ffi.sh @@ -211,7 +211,7 @@ DESTDIR=$destdir cargo build --package tools --bins echo "Generating $destdir/include/libdatadog headers..." # ADD headers based on selected features. -HEADERS="$destdir/include/datadog/common.h $destdir/include/datadog/profiling.h $destdir/include/datadog/telemetry.h" +HEADERS="$destdir/include/datadog/common.h $destdir/include/datadog/profiling.h $destdir/include/datadog/telemetry.h $destdir/include/datadog/crashtracker.h" case $ARG_FEATURES in *data-pipeline-ffi*) HEADERS="$HEADERS $destdir/include/datadog/data-pipeline.h" diff --git a/crashtracker-ffi/cbindgen.toml b/crashtracker-ffi/cbindgen.toml index 0bb02a61f..7402167c6 100644 --- a/crashtracker-ffi/cbindgen.toml +++ b/crashtracker-ffi/cbindgen.toml @@ -33,18 +33,6 @@ renaming_overrides_prefixing = true "Vec_Tag" = "ddog_Vec_Tag" "Vec_U8" = "ddog_Vec_U8" -"ProfilingEndpoint" = "ddog_prof_Endpoint" -"ExporterNewResult" = "ddog_prof_Exporter_NewResult" -"File" = "ddog_prof_Exporter_File" -"ProfileExporter" = "ddog_prof_Exporter" -"ProfileNewResult" = "ddog_prof_Profile_NewResult" -"ProfileResult" = "ddog_prof_Profile_Result" -"Request" = "ddog_prof_Exporter_Request" -"RequestBuildResult" = "ddog_prof_Exporter_Request_BuildResult" -"SendResult" = "ddog_prof_Exporter_SendResult" -"SerializeResult" = "ddog_prof_Profile_SerializeResult" -"Slice_File" = "ddog_prof_Exporter_Slice_File" - [export.mangle] rename_types = "PascalCase" @@ -57,5 +45,5 @@ must_use = "DDOG_CHECK_RETURN" [parse] parse_deps = true -include = ["ddcommon", "ddcommon-ffi", "datadog-profiling", "datadog-crashtracker", "ux"] +include = ["ddcommon", "ddcommon-ffi", "datadog-crashtracker", "ux"] diff --git a/crashtracker/libdatadog-crashtracking-receiver.c b/crashtracker/libdatadog-crashtracking-receiver.c index 3b23c58a7..f7a57fb9d 100644 --- a/crashtracker/libdatadog-crashtracking-receiver.c +++ b/crashtracker/libdatadog-crashtracking-receiver.c @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 #include -#include +#include #include #include diff --git a/profiling-ffi/Cargo.toml b/profiling-ffi/Cargo.toml index 535527f0f..33f04f4b3 100644 --- a/profiling-ffi/Cargo.toml +++ b/profiling-ffi/Cargo.toml @@ -20,10 +20,11 @@ cbindgen = ["build_common/cbindgen", "ddcommon-ffi/cbindgen"] ddtelemetry-ffi = ["dep:ddtelemetry-ffi"] symbolizer = ["symbolizer-ffi"] data-pipeline-ffi = ["dep:data-pipeline-ffi"] +crashtracker-ffi = ["dep:crashtracker-ffi"] # Enables the in-process collection of crash-info -crashtracker-collector = ["datadog-crashtracker/collector"] +crashtracker-collector = ["crashtracker-ffi", "crashtracker-ffi/collector"] # Enables the use of this library to receiver crash-info from a suitable collector -crashtracker-receiver = ["datadog-crashtracker/receiver"] +crashtracker-receiver = ["crashtracker-ffi", "crashtracker-ffi/receiver"] [build-dependencies] build_common = { path = "../build-common" } @@ -31,7 +32,7 @@ build_common = { path = "../build-common" } [dependencies] anyhow = "1.0" chrono = {version = "0.4", default-features = false } -datadog-crashtracker = { path = "../crashtracker" } +crashtracker-ffi = { path = "../crashtracker-ffi", default-features = false, optional = true} datadog-profiling = { path = "../profiling" } hyper = { version = "0.14", default-features = false } ddcommon = { path = "../ddcommon"} diff --git a/profiling-ffi/src/crashtracker/collector/counters.rs b/profiling-ffi/src/crashtracker/collector/counters.rs deleted file mode 100644 index e85cb8c34..000000000 --- a/profiling-ffi/src/crashtracker/collector/counters.rs +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright 2024-Present Datadog, Inc. https://www.datadoghq.com/ -// SPDX-License-Identifier: Apache-2.0 - -use super::datatypes::ProfilingOpTypes; -use crate::crashtracker::datatypes::*; -use anyhow::Context; - -/// Resets all counters to 0. -/// Expected to be used after a fork, to reset the counters on the child -/// ATOMICITY: -/// This is NOT ATOMIC. -/// Should only be used when no conflicting updates can occur, -/// e.g. after a fork but before profiling ops start on the child. -/// # Safety -/// No safety concerns. -#[no_mangle] -#[must_use] -pub unsafe extern "C" fn ddog_prof_Crashtracker_reset_counters() -> CrashtrackerResult { - datadog_crashtracker::reset_counters() - .context("ddog_prof_Crashtracker_begin_profiling_op failed") - .into() -} - -#[no_mangle] -#[must_use] -/// Atomically increments the count associated with `op`. -/// Useful for tracking what operations were occuring when a crash occurred. -/// -/// # Safety -/// No safety concerns. -pub unsafe extern "C" fn ddog_prof_Crashtracker_begin_profiling_op( - op: ProfilingOpTypes, -) -> CrashtrackerResult { - datadog_crashtracker::begin_profiling_op(op) - .context("ddog_prof_Crashtracker_begin_profiling_op failed") - .into() -} - -#[no_mangle] -#[must_use] -/// Atomically decrements the count associated with `op`. -/// Useful for tracking what operations were occuring when a crash occurred. -/// -/// # Safety -/// No safety concerns. -pub unsafe extern "C" fn ddog_prof_Crashtracker_end_profiling_op( - op: ProfilingOpTypes, -) -> CrashtrackerResult { - datadog_crashtracker::end_profiling_op(op) - .context("ddog_prof_Crashtracker_end_profiling_op failed") - .into() -} diff --git a/profiling-ffi/src/crashtracker/collector/datatypes.rs b/profiling-ffi/src/crashtracker/collector/datatypes.rs deleted file mode 100644 index eb5dcea51..000000000 --- a/profiling-ffi/src/crashtracker/collector/datatypes.rs +++ /dev/null @@ -1,131 +0,0 @@ -// Copyright 2024-Present Datadog, Inc. https://www.datadoghq.com/ -// SPDX-License-Identifier: Apache-2.0 - -use crate::option_from_char_slice; -pub use datadog_crashtracker::{ProfilingOpTypes, StacktraceCollection}; -use ddcommon_ffi::slice::{AsBytes, CharSlice}; -use ddcommon_ffi::{Error, Slice}; - -#[repr(C)] -pub struct EnvVar<'a> { - key: CharSlice<'a>, - val: CharSlice<'a>, -} - -#[repr(C)] -pub struct CrashtrackerReceiverConfig<'a> { - pub args: Slice<'a, CharSlice<'a>>, - pub env: Slice<'a, EnvVar<'a>>, - pub path_to_receiver_binary: CharSlice<'a>, - /// Optional filename to forward stderr to (useful for logging/debugging) - pub optional_stderr_filename: CharSlice<'a>, - /// Optional filename to forward stdout to (useful for logging/debugging) - pub optional_stdout_filename: CharSlice<'a>, -} - -impl<'a> TryFrom> - for datadog_crashtracker::CrashtrackerReceiverConfig -{ - type Error = anyhow::Error; - fn try_from(value: CrashtrackerReceiverConfig<'a>) -> anyhow::Result { - let args = { - let mut vec = Vec::with_capacity(value.args.len()); - for x in value.args.iter() { - vec.push(x.try_to_utf8()?.to_string()); - } - vec - }; - let env = { - let mut vec = Vec::with_capacity(value.env.len()); - for x in value.env.iter() { - vec.push(( - x.key.try_to_utf8()?.to_string(), - x.val.try_to_utf8()?.to_string(), - )); - } - vec - }; - let path_to_receiver_binary = value.path_to_receiver_binary.try_to_utf8()?.to_string(); - let stderr_filename = option_from_char_slice(value.optional_stderr_filename)?; - let stdout_filename = option_from_char_slice(value.optional_stdout_filename)?; - Self::new( - args, - env, - path_to_receiver_binary, - stderr_filename, - stdout_filename, - ) - } -} - -#[repr(C)] -pub struct CrashtrackerConfiguration<'a> { - pub additional_files: Slice<'a, CharSlice<'a>>, - pub create_alt_stack: 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 ddcommon::Endpoint>, - pub resolve_frames: StacktraceCollection, - pub timeout_secs: u64, - pub wait_for_receiver: bool, -} - -impl<'a> TryFrom> - for datadog_crashtracker::CrashtrackerConfiguration -{ - type Error = anyhow::Error; - fn try_from(value: CrashtrackerConfiguration<'a>) -> anyhow::Result { - let additional_files = { - let mut vec = Vec::with_capacity(value.additional_files.len()); - for x in value.additional_files.iter() { - vec.push(x.try_to_utf8()?.to_string()); - } - vec - }; - let create_alt_stack = value.create_alt_stack; - let endpoint = value.endpoint.cloned(); - let resolve_frames = value.resolve_frames; - let wait_for_receiver = value.wait_for_receiver; - Self::new( - additional_files, - create_alt_stack, - endpoint, - resolve_frames, - wait_for_receiver, - ) - } -} - -#[repr(C)] -pub enum CrashtrackerUsizeResult { - Ok(usize), - #[allow(dead_code)] - Err(Error), -} - -impl From> for CrashtrackerUsizeResult { - fn from(value: anyhow::Result) -> Self { - match value { - Ok(x) => Self::Ok(x), - Err(err) => Self::Err(err.into()), - } - } -} - -#[repr(C)] -pub enum CrashtrackerGetCountersResult { - Ok([i64; ProfilingOpTypes::SIZE as usize]), - #[allow(dead_code)] - Err(Error), -} - -impl From> - for CrashtrackerGetCountersResult -{ - fn from(value: anyhow::Result<[i64; ProfilingOpTypes::SIZE as usize]>) -> Self { - match value { - Ok(x) => Self::Ok(x), - Err(err) => Self::Err(err.into()), - } - } -} diff --git a/profiling-ffi/src/crashtracker/collector/mod.rs b/profiling-ffi/src/crashtracker/collector/mod.rs deleted file mode 100644 index a746ea467..000000000 --- a/profiling-ffi/src/crashtracker/collector/mod.rs +++ /dev/null @@ -1,97 +0,0 @@ -// Copyright 2021-Present Datadog, Inc. https://www.datadoghq.com/ -// SPDX-License-Identifier: Apache-2.0 -mod counters; -mod datatypes; -mod spans; - -use super::crash_info::CrashtrackerMetadata; -use crate::crashtracker::datatypes::*; -use anyhow::Context; -pub use counters::*; -pub use datatypes::*; -pub use spans::*; - -#[no_mangle] -#[must_use] -/// Cleans up after the crash-tracker: -/// Unregister the crash handler, restore the previous handler (if any), and -/// shut down the receiver. Note that the use of this function is optional: -/// the receiver will automatically shutdown when the pipe is closed on program -/// exit. -/// -/// # Preconditions -/// This function assumes that the crash-tracker has previously been -/// initialized. -/// # Safety -/// Crash-tracking functions are not reentrant. -/// No other crash-handler functions should be called concurrently. -/// # Atomicity -/// This function is not atomic. A crash during its execution may lead to -/// unexpected crash-handling behaviour. -pub unsafe extern "C" fn ddog_prof_Crashtracker_shutdown() -> CrashtrackerResult { - datadog_crashtracker::shutdown_crash_handler() - .context("ddog_prof_Crashtracker_shutdown failed") - .into() -} - -#[no_mangle] -#[must_use] -/// Reinitialize the crash-tracking infrastructure after a fork. -/// This should be one of the first things done after a fork, to minimize the -/// chance that a crash occurs between the fork, and this call. -/// In particular, reset the counters that track the profiler state machine, -/// and start a new receiver to collect data from this fork. -/// NOTE: An alternative design would be to have a 1:many sidecar listening on a -/// socket instead of 1:1 receiver listening on a pipe, but the only real -/// advantage would be to have fewer processes in `ps -a`. -/// -/// # Preconditions -/// This function assumes that the crash-tracker has previously been -/// initialized. -/// # Safety -/// Crash-tracking functions are not reentrant. -/// No other crash-handler functions should be called concurrently. -/// # Atomicity -/// This function is not atomic. A crash during its execution may lead to -/// unexpected crash-handling behaviour. -pub unsafe extern "C" fn ddog_prof_Crashtracker_update_on_fork( - config: CrashtrackerConfiguration, - receiver_config: CrashtrackerReceiverConfig, - metadata: CrashtrackerMetadata, -) -> CrashtrackerResult { - (|| { - let config = config.try_into()?; - let receiver_config = receiver_config.try_into()?; - let metadata = metadata.try_into()?; - datadog_crashtracker::on_fork(config, receiver_config, metadata) - })() - .context("ddog_prof_Crashtracker_update_on_fork failed") - .into() -} - -#[no_mangle] -#[must_use] -/// Initialize the crash-tracking infrastructure. -/// -/// # Preconditions -/// None. -/// # Safety -/// Crash-tracking functions are not reentrant. -/// No other crash-handler functions should be called concurrently. -/// # Atomicity -/// This function is not atomic. A crash during its execution may lead to -/// unexpected crash-handling behaviour. -pub unsafe extern "C" fn ddog_prof_Crashtracker_init_with_receiver( - config: CrashtrackerConfiguration, - receiver_config: CrashtrackerReceiverConfig, - metadata: CrashtrackerMetadata, -) -> CrashtrackerResult { - (|| { - let config = config.try_into()?; - let receiver_config = receiver_config.try_into()?; - let metadata = metadata.try_into()?; - datadog_crashtracker::init_with_receiver(config, receiver_config, metadata) - })() - .context("ddog_prof_Crashtracker_init failed") - .into() -} diff --git a/profiling-ffi/src/crashtracker/collector/spans.rs b/profiling-ffi/src/crashtracker/collector/spans.rs deleted file mode 100644 index f27b60e83..000000000 --- a/profiling-ffi/src/crashtracker/collector/spans.rs +++ /dev/null @@ -1,166 +0,0 @@ -// Copyright 2024-Present Datadog, Inc. https://www.datadoghq.com/ -// SPDX-License-Identifier: Apache-2.0 - -use crate::{crashtracker::datatypes::*, CrashtrackerUsizeResult}; -use anyhow::Context; - -/// Resets all stored spans to 0. -/// Expected to be used after a fork, to reset the spans on the child -/// ATOMICITY: -/// This is NOT ATOMIC. -/// Should only be used when no conflicting updates can occur, -/// e.g. after a fork but before profiling ops start on the child. -/// # Safety -/// No safety concerns. -#[no_mangle] -#[must_use] -pub unsafe extern "C" fn ddog_prof_Crashtracker_clear_span_ids() -> CrashtrackerResult { - datadog_crashtracker::clear_spans() - .context("ddog_prof_Crashtracker_clear_span_ids failed") - .into() -} - -/// Resets all stored traces to 0. -/// Expected to be used after a fork, to reset the traces on the child -/// ATOMICITY: -/// This is NOT ATOMIC. -/// Should only be used when no conflicting updates can occur, -/// e.g. after a fork but before profiling ops start on the child. -/// # Safety -/// No safety concerns. -#[no_mangle] -#[must_use] -pub unsafe extern "C" fn ddog_prof_Crashtracker_clear_trace_ids() -> CrashtrackerResult { - datadog_crashtracker::clear_traces() - .context("ddog_prof_Crashtracker_clear_trace_ids failed") - .into() -} - -#[no_mangle] -#[must_use] -/// Atomically registers an active traceId. -/// Useful for tracking what operations were occurring when a crash occurred. -/// 0 is reserved for "NoId" -/// The set does not check for duplicates. Adding the same id twice is an error. -/// -/// Inputs: -/// id: the 128 bit id, broken into 2 64 bit chunks (see note) -/// -/// Returns: -/// Ok(handle) on success. The handle is needed to later remove the id; -/// Err() on failure. The most likely cause of failure is that the underlying set is full. -/// -/// Note: 128 bit ints in FFI were not stabilized until Rust 1.77 -/// https://blog.rust-lang.org/2024/03/30/i128-layout-update.html -/// We're currently locked into 1.71, have to do an ugly workaround involving 2 64 bit ints -/// until we can upgrade. -/// -/// # Safety -/// No safety concerns. -pub unsafe extern "C" fn ddog_prof_Crashtracker_insert_trace_id( - id_high: u64, - id_low: u64, -) -> CrashtrackerUsizeResult { - let id: u128 = (id_high as u128) << 64 | (id_low as u128); - datadog_crashtracker::insert_trace(id) - .context("ddog_prof_Crashtracker_insert_trace_id failed") - .into() -} - -#[no_mangle] -#[must_use] -/// Atomically registers an active SpanId. -/// Useful for tracking what operations were occurring when a crash occurred. -/// 0 is reserved for "NoId". -/// The set does not check for duplicates. Adding the same id twice is an error. -/// -/// Inputs: -/// id: the 128 bit id, broken into 2 64 bit chunks (see note) -/// -/// Returns: -/// Ok(handle) on success. The handle is needed to later remove the id; -/// Err() on failure. The most likely cause of failure is that the underlying set is full. -/// -/// Note: 128 bit ints in FFI were not stabilized until Rust 1.77 -/// https://blog.rust-lang.org/2024/03/30/i128-layout-update.html -/// We're currently locked into 1.71, have to do an ugly workaround involving 2 64 bit ints -/// until we can upgrade. - -/// -/// # Safety -/// No safety concerns. -pub unsafe extern "C" fn ddog_prof_Crashtracker_insert_span_id( - id_high: u64, - id_low: u64, -) -> CrashtrackerUsizeResult { - let id: u128 = (id_high as u128) << 64 | (id_low as u128); - datadog_crashtracker::insert_span(id) - .context("ddog_prof_Crashtracker_insert_span_id failed") - .into() -} - -#[no_mangle] -#[must_use] -/// Atomically removes a completed SpanId. -/// Useful for tracking what operations were occurring when a crash occurred. -/// 0 is reserved for "NoId" -/// -/// Inputs: -/// id: the 128 bit id, broken into 2 64 bit chunks (see note) -/// idx: The handle for the id, from a previous successful call to `insert_span_id`. -/// Attempting to remove the same element twice is an error. -/// Returns: -/// `Ok` on success. -/// `Err` on failure. If `id` is not found at `idx`, `Err` will be returned and the set will not -/// be modified. -/// -/// Note: 128 bit ints in FFI were not stabilized until Rust 1.77 -/// https://blog.rust-lang.org/2024/03/30/i128-layout-update.html -/// We're currently locked into 1.71, have to do an ugly workaround involving 2 64 bit ints -/// until we can upgrade. -/// -/// # Safety -/// No safety concerns. -pub unsafe extern "C" fn ddog_prof_Crashtracker_remove_span_id( - id_high: u64, - id_low: u64, - idx: usize, -) -> CrashtrackerResult { - let id: u128 = (id_high as u128) << 64 | (id_low as u128); - datadog_crashtracker::remove_span(id, idx) - .context("ddog_prof_Crashtracker_remove_span_id failed") - .into() -} - -#[no_mangle] -#[must_use] -/// Atomically removes a completed TraceId. -/// Useful for tracking what operations were occurring when a crash occurred. -/// 0 is reserved for "NoId" -/// -/// Inputs: -/// id: the 128 bit id, broken into 2 64 bit chunks (see note) -/// idx: The handle for the id, from a previous successful call to `insert_span_id`. -/// Attempting to remove the same element twice is an error. -/// Returns: -/// `Ok` on success. -/// `Err` on failure. If `id` is not found at `idx`, `Err` will be returned and the set will not -/// be modified. -/// -/// Note: 128 bit ints in FFI were not stabilized until Rust 1.77 -/// https://blog.rust-lang.org/2024/03/30/i128-layout-update.html -/// We're currently locked into 1.71, have to do an ugly workaround involving 2 64 bit ints -/// until we can upgrade. -/// -/// # Safety -/// No safety concerns. -pub unsafe extern "C" fn ddog_prof_Crashtracker_remove_trace_id( - id_high: u64, - id_low: u64, - idx: usize, -) -> CrashtrackerResult { - let id: u128 = (id_high as u128) << 64 | (id_low as u128); - datadog_crashtracker::remove_trace(id, idx) - .context("ddog_prof_Crashtracker_remove_trace_id failed") - .into() -} diff --git a/profiling-ffi/src/crashtracker/crash_info/datatypes.rs b/profiling-ffi/src/crashtracker/crash_info/datatypes.rs deleted file mode 100644 index 5f75a1537..000000000 --- a/profiling-ffi/src/crashtracker/crash_info/datatypes.rs +++ /dev/null @@ -1,255 +0,0 @@ -// Copyright 2024-Present Datadog, Inc. https://www.datadoghq.com/ -// SPDX-License-Identifier: Apache-2.0 - -use crate::option_from_char_slice; -use ddcommon::tag::Tag; -use ddcommon_ffi::{ - slice::{AsBytes, ByteSlice}, - CharSlice, Error, Slice, -}; - -/// Represents a CrashInfo. Do not access its member for any reason, only use -/// the C API functions on this struct. -#[repr(C)] -pub struct CrashInfo { - // This may be null, but if not it will point to a valid CrashInfo. - inner: *mut datadog_crashtracker::CrashInfo, -} - -impl CrashInfo { - pub(super) fn new(crash_info: datadog_crashtracker::CrashInfo) -> Self { - CrashInfo { - inner: Box::into_raw(Box::new(crash_info)), - } - } - - pub(super) fn take(&mut self) -> Option> { - // Leaving a null will help with double-free issues that can - // arise in C. Of course, it's best to never get there in the - // first place! - let raw = std::mem::replace(&mut self.inner, std::ptr::null_mut()); - - if raw.is_null() { - None - } else { - Some(unsafe { Box::from_raw(raw) }) - } - } -} - -impl Drop for CrashInfo { - fn drop(&mut self) { - drop(self.take()) - } -} - -pub(crate) unsafe fn crashinfo_ptr_to_inner<'a>( - crashinfo_ptr: *mut CrashInfo, -) -> anyhow::Result<&'a mut datadog_crashtracker::CrashInfo> { - match crashinfo_ptr.as_mut() { - None => anyhow::bail!("crashinfo pointer was null"), - Some(inner_ptr) => match inner_ptr.inner.as_mut() { - Some(crashinfo) => Ok(crashinfo), - None => anyhow::bail!("crashinfo's inner pointer was null (indicates use-after-free)"), - }, - } -} - -/// Returned by [ddog_prof_Profile_new]. -#[repr(C)] -pub enum CrashInfoNewResult { - Ok(CrashInfo), - #[allow(dead_code)] - Err(Error), -} - -#[repr(C)] -#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)] -pub enum NormalizedAddressTypes { - // Make None 0 so that default construction gives none - None = 0, - Elf, -} - -#[repr(C)] -pub struct NormalizedAddress<'a> { - file_offset: u64, - build_id: ByteSlice<'a>, - path: CharSlice<'a>, - typ: NormalizedAddressTypes, -} - -impl<'a> TryFrom> for Option { - type Error = anyhow::Error; - - fn try_from(value: NormalizedAddress<'a>) -> Result { - Self::try_from(&value) - } -} - -impl<'a> TryFrom<&NormalizedAddress<'a>> for Option { - type Error = anyhow::Error; - - fn try_from(value: &NormalizedAddress<'a>) -> Result { - if value.typ == NormalizedAddressTypes::None { - Ok(None) - } else { - Ok(Some(value.try_into()?)) - } - } -} - -impl<'a> TryFrom> for datadog_crashtracker::NormalizedAddress { - type Error = anyhow::Error; - - fn try_from(value: NormalizedAddress<'a>) -> Result { - Self::try_from(&value) - } -} - -impl<'a> TryFrom<&NormalizedAddress<'a>> for datadog_crashtracker::NormalizedAddress { - type Error = anyhow::Error; - - fn try_from(value: &NormalizedAddress<'a>) -> Result { - match &value.typ { - NormalizedAddressTypes::Elf => { - let build_id = if value.build_id.is_empty() { - None - } else { - Some(Vec::from(value.build_id.as_bytes())) - }; - let path = value.path.try_to_utf8()?.into(); - let meta = datadog_crashtracker::NormalizedAddressMeta::Elf { build_id, path }; - Ok(Self { - file_offset: value.file_offset, - meta, - }) - } - _ => anyhow::bail!("Unsupported normalized address type {:?}", value.typ), - } - } -} - -#[repr(C)] -pub struct StackFrameNames<'a> { - colno: ddcommon_ffi::Option, - filename: CharSlice<'a>, - lineno: ddcommon_ffi::Option, - name: CharSlice<'a>, -} - -impl<'a> TryFrom> for datadog_crashtracker::StackFrameNames { - type Error = anyhow::Error; - - fn try_from(value: StackFrameNames<'a>) -> Result { - Self::try_from(&value) - } -} - -impl<'a> TryFrom<&StackFrameNames<'a>> for datadog_crashtracker::StackFrameNames { - type Error = anyhow::Error; - - fn try_from(value: &StackFrameNames<'a>) -> Result { - let colno = (&value.colno).into(); - let filename = option_from_char_slice(value.filename)?; - let lineno = (&value.lineno).into(); - let name = option_from_char_slice(value.name)?; - Ok(Self { - colno, - filename, - lineno, - name, - }) - } -} - -#[repr(C)] -pub struct StackFrame<'a> { - build_id: CharSlice<'a>, - ip: usize, - module_base_address: usize, - names: Slice<'a, StackFrameNames<'a>>, - normalized_ip: NormalizedAddress<'a>, - sp: usize, - symbol_address: usize, -} - -impl<'a> TryFrom<&StackFrame<'a>> for datadog_crashtracker::StackFrame { - type Error = anyhow::Error; - - fn try_from(value: &StackFrame<'a>) -> Result { - fn to_hex(v: usize) -> Option { - if v == 0 { - None - } else { - Some(format!("{v:#X}")) - } - } - let ip = to_hex(value.ip); - let module_base_address = to_hex(value.module_base_address); - let names = if value.names.is_empty() { - None - } else { - let mut vec = Vec::with_capacity(value.names.len()); - for x in value.names.iter() { - vec.push(x.try_into()?); - } - Some(vec) - }; - let normalized_ip = (&value.normalized_ip).try_into()?; - let sp = to_hex(value.sp); - let symbol_address = to_hex(value.symbol_address); - Ok(Self { - ip, - module_base_address, - names, - normalized_ip, - sp, - symbol_address, - }) - } -} - -#[repr(C)] -pub struct SigInfo<'a> { - pub signum: u64, - pub signame: CharSlice<'a>, -} - -impl<'a> TryFrom> for datadog_crashtracker::SigInfo { - type Error = anyhow::Error; - - fn try_from(value: SigInfo<'a>) -> Result { - let signum = value.signum; - let signame = option_from_char_slice(value.signame)?; - Ok(Self { signum, signame }) - } -} - -#[repr(C)] -pub struct CrashtrackerMetadata<'a> { - pub profiling_library_name: CharSlice<'a>, - pub profiling_library_version: CharSlice<'a>, - pub family: CharSlice<'a>, - /// Should include "service", "environment", etc - pub tags: Option<&'a ddcommon_ffi::Vec>, -} - -impl<'a> TryFrom> for datadog_crashtracker::CrashtrackerMetadata { - type Error = anyhow::Error; - fn try_from(value: CrashtrackerMetadata<'a>) -> anyhow::Result { - let profiling_library_name = value.profiling_library_name.try_to_utf8()?.to_string(); - let profiling_library_version = value.profiling_library_version.try_to_utf8()?.to_string(); - let family = value.family.try_to_utf8()?.to_string(); - let tags = value - .tags - .map(|tags| tags.iter().cloned().collect()) - .unwrap_or_default(); - Ok(Self::new( - profiling_library_name, - profiling_library_version, - family, - tags, - )) - } -} diff --git a/profiling-ffi/src/crashtracker/crash_info/mod.rs b/profiling-ffi/src/crashtracker/crash_info/mod.rs deleted file mode 100644 index 7c2ee0daa..000000000 --- a/profiling-ffi/src/crashtracker/crash_info/mod.rs +++ /dev/null @@ -1,251 +0,0 @@ -// Copyright 2021-Present Datadog, Inc. https://www.datadoghq.com/ -// SPDX-License-Identifier: Apache-2.0 - -mod datatypes; -pub use datatypes::*; - -use crate::{ - crashtracker::{option_from_char_slice, CrashtrackerResult}, - exporter::ProfilingEndpoint, -}; -use anyhow::Context; -use chrono::DateTime; -use ddcommon_ffi::{slice::AsBytes, CharSlice, Slice}; - -/// Create a new crashinfo, and returns an opaque reference to it. -/// # Safety -/// No safety issues. -#[no_mangle] -#[must_use] -pub unsafe extern "C" fn ddog_crashinfo_new() -> CrashInfoNewResult { - CrashInfoNewResult::Ok(CrashInfo::new(datadog_crashtracker::CrashInfo::new())) -} - -/// # Safety -/// The `crash_info` can be null, but if non-null it must point to a CrashInfo -/// made by this module, which has not previously been dropped. -#[no_mangle] -pub unsafe extern "C" fn ddog_crashinfo_drop(crashinfo: *mut CrashInfo) { - // Technically, this function has been designed so if it's double-dropped - // then it's okay, but it's not something that should be relied on. - if !crashinfo.is_null() { - drop((*crashinfo).take()) - } -} - -/// Best effort attempt to normalize all `ip` on the stacktrace. -/// `pid` must be the pid of the currently active process where the ips came from. -/// -/// # Safety -/// `crashinfo` must be a valid pointer to a `CrashInfo` object. -#[cfg(unix)] -#[no_mangle] -#[must_use] -pub unsafe extern "C" fn ddog_crashinfo_normalize_ips( - crashinfo: *mut CrashInfo, - pid: u32, -) -> CrashtrackerResult { - (|| { - let crashinfo = crashinfo_ptr_to_inner(crashinfo)?; - crashinfo.normalize_ips(pid) - })() - .context("ddog_crashinfo_normalize_ips failed") - .into() -} - -/// Adds a "counter" variable, with the given value. Useful for determining if -/// "interesting" operations were occurring when the crash did. -/// -/// # Safety -/// `crashinfo` must be a valid pointer to a `CrashInfo` object. -/// `name` should be a valid reference to a utf8 encoded String. -/// The string is copied into the crashinfo, so it does not need to outlive this -/// call. -#[no_mangle] -#[must_use] -pub unsafe extern "C" fn ddog_crashinfo_add_counter( - crashinfo: *mut CrashInfo, - name: CharSlice, - val: i64, -) -> CrashtrackerResult { - (|| { - let crashinfo = crashinfo_ptr_to_inner(crashinfo)?; - let name = name.to_utf8_lossy(); - crashinfo.add_counter(&name, val) - })() - .context("ddog_crashinfo_add_counter failed") - .into() -} - -/// Adds the contents of "file" to the crashinfo -/// -/// # Safety -/// `crashinfo` must be a valid pointer to a `CrashInfo` object. -/// `name` should be a valid reference to a utf8 encoded String. -/// The string is copied into the crashinfo, so it does not need to outlive this -/// call. -#[no_mangle] -#[must_use] -pub unsafe extern "C" fn ddog_crashinfo_add_file( - crashinfo: *mut CrashInfo, - name: CharSlice, -) -> CrashtrackerResult { - (|| { - let crashinfo = crashinfo_ptr_to_inner(crashinfo)?; - let name = name.to_utf8_lossy(); - crashinfo.add_file(&name) - })() - .context("ddog_crashinfo_add_file failed") - .into() -} - -/// Adds the tag with given "key" and "value" to the crashinfo -/// -/// # Safety -/// `crashinfo` must be a valid pointer to a `CrashInfo` object. -/// `key` should be a valid reference to a utf8 encoded String. -/// `value` should be a valid reference to a utf8 encoded String. -/// The string is copied into the crashinfo, so it does not need to outlive this -/// call. -#[no_mangle] -#[must_use] -pub unsafe extern "C" fn ddog_crashinfo_add_tag( - crashinfo: *mut CrashInfo, - key: CharSlice, - value: CharSlice, -) -> CrashtrackerResult { - (|| { - let crashinfo = crashinfo_ptr_to_inner(crashinfo)?; - let key = key.to_utf8_lossy().to_string(); - let value = value.to_utf8_lossy().to_string(); - crashinfo.add_tag(key, value) - })() - .context("ddog_crashinfo_add_tag failed") - .into() -} - -/// Sets the crashinfo metadata -/// -/// # Safety -/// `crashinfo` must be a valid pointer to a `CrashInfo` object. -/// All references inside `metadata` must be valid. -/// Strings are copied into the crashinfo, and do not need to outlive this call. -#[no_mangle] -#[must_use] -pub unsafe extern "C" fn ddog_crashinfo_set_metadata( - crashinfo: *mut CrashInfo, - metadata: CrashtrackerMetadata, -) -> CrashtrackerResult { - (|| { - let crashinfo = crashinfo_ptr_to_inner(crashinfo)?; - let metadata = metadata.try_into()?; - crashinfo.set_metadata(metadata) - })() - .context("ddog_crashinfo_set_metadata failed") - .into() -} - -/// Sets the crashinfo siginfo -/// -/// # Safety -/// `crashinfo` must be a valid pointer to a `CrashInfo` object. -/// All references inside `metadata` must be valid. -/// Strings are copied into the crashinfo, and do not need to outlive this call. -#[no_mangle] -#[must_use] -pub unsafe extern "C" fn ddog_crashinfo_set_siginfo( - crashinfo: *mut CrashInfo, - siginfo: SigInfo, -) -> CrashtrackerResult { - (|| { - let crashinfo = crashinfo_ptr_to_inner(crashinfo)?; - let siginfo = siginfo.try_into()?; - crashinfo.set_siginfo(siginfo) - })() - .context("ddog_crashinfo_set_siginfo failed") - .into() -} - -/// If `thread_id` is empty, sets `stacktrace` as the default stacktrace. -/// Otherwise, adds an additional stacktrace with id "thread_id". -/// -/// # Safety -/// `crashinfo` must be a valid pointer to a `CrashInfo` object. -/// All references inside `stacktraces` must be valid. -/// Strings are copied into the crashinfo, and do not need to outlive this call. -#[no_mangle] -#[must_use] -pub unsafe extern "C" fn ddog_crashinfo_set_stacktrace( - crashinfo: *mut CrashInfo, - thread_id: CharSlice, - stacktrace: Slice, -) -> CrashtrackerResult { - (|| { - let crashinfo = crashinfo_ptr_to_inner(crashinfo)?; - let thread_id = option_from_char_slice(thread_id)?; - let mut stacktrace_vec = Vec::with_capacity(stacktrace.len()); - for s in stacktrace.iter() { - stacktrace_vec.push(s.try_into()?) - } - crashinfo.set_stacktrace(thread_id, stacktrace_vec) - })() - .context("ddog_crashinfo_set_stacktrace failed") - .into() -} - -/// Sets the timestamp to the given unix timestamp -/// -/// # Safety -/// `crashinfo` must be a valid pointer to a `CrashInfo` object. -#[no_mangle] -#[must_use] -pub unsafe extern "C" fn ddog_crashinfo_set_timestamp( - crashinfo: *mut CrashInfo, - secs: i64, - nsecs: u32, -) -> CrashtrackerResult { - (|| { - let crashinfo = crashinfo_ptr_to_inner(crashinfo)?; - let ts = DateTime::from_timestamp(secs, nsecs) - .with_context(|| format!("Invalid timestamp {secs} {nsecs}"))?; - crashinfo.set_timestamp(ts) - })() - .context("ddog_crashinfo_set_timestamp_to_now failed") - .into() -} - -/// Sets the timestamp to the current time -/// -/// # Safety -/// `crashinfo` must be a valid pointer to a `CrashInfo` object. -#[no_mangle] -#[must_use] -pub unsafe extern "C" fn ddog_crashinfo_set_timestamp_to_now( - crashinfo: *mut CrashInfo, -) -> CrashtrackerResult { - (|| { - let crashinfo = crashinfo_ptr_to_inner(crashinfo)?; - crashinfo.set_timestamp_to_now() - })() - .context("ddog_crashinfo_set_timestamp_to_now failed") - .into() -} - -/// Exports `crashinfo` to the backend at `endpoint` -/// Note that we support the "file://" endpoint for local file output. -/// # Safety -/// `crashinfo` must be a valid pointer to a `CrashInfo` object. -#[no_mangle] -#[must_use] -pub unsafe extern "C" fn ddog_crashinfo_upload_to_endpoint( - crashinfo: *mut CrashInfo, - endpoint: ProfilingEndpoint, -) -> CrashtrackerResult { - (|| { - let crashinfo = crashinfo_ptr_to_inner(crashinfo)?; - let endpoint = Some(unsafe { crate::exporter::try_to_endpoint(endpoint)? }); - crashinfo.upload_to_endpoint(&endpoint) - })() - .context("ddog_crashinfo_upload_to_endpoint failed") - .into() -} diff --git a/profiling-ffi/src/crashtracker/datatypes/mod.rs b/profiling-ffi/src/crashtracker/datatypes/mod.rs deleted file mode 100644 index ec7b51f7e..000000000 --- a/profiling-ffi/src/crashtracker/datatypes/mod.rs +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright 2021-Present Datadog, Inc. https://www.datadoghq.com/ -// SPDX-License-Identifier: Apache-2.0 - -use ddcommon_ffi::slice::{AsBytes, CharSlice}; -use ddcommon_ffi::Error; -use std::ops::Not; - -pub fn option_from_char_slice(s: CharSlice) -> anyhow::Result> { - let s = s.try_to_utf8()?.to_string(); - Ok(s.is_empty().not().then_some(s)) -} - -/// A generic result type for when a crashtracking operation may fail, -/// but there's nothing to return in the case of success. -#[repr(C)] -pub enum CrashtrackerResult { - Ok( - /// Do not use the value of Ok. This value only exists to overcome - /// Rust -> C code generation. - bool, - ), - Err(Error), -} - -impl From> for CrashtrackerResult { - fn from(value: anyhow::Result<()>) -> Self { - match value { - Ok(_) => Self::Ok(true), - Err(err) => Self::Err(err.into()), - } - } -} diff --git a/profiling-ffi/src/crashtracker/demangler/datatypes.rs b/profiling-ffi/src/crashtracker/demangler/datatypes.rs deleted file mode 100644 index 877bc1b9c..000000000 --- a/profiling-ffi/src/crashtracker/demangler/datatypes.rs +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright 2024-Present Datadog, Inc. https://www.datadoghq.com/ -// SPDX-License-Identifier: Apache-2.0 - -use ddcommon_ffi::{Error, StringWrapper}; - -#[repr(C)] -pub enum DemangleOptions { - Complete, - NameOnly, -} - -#[repr(C)] -pub enum StringWrapperResult { - Ok(StringWrapper), - #[allow(dead_code)] - Err(Error), -} - -// Useful for testing -impl StringWrapperResult { - pub fn unwrap(self) -> StringWrapper { - match self { - StringWrapperResult::Ok(s) => s, - StringWrapperResult::Err(e) => panic!("{e}"), - } - } -} - -impl From> for StringWrapperResult { - fn from(value: anyhow::Result) -> Self { - match value { - Ok(x) => Self::Ok(x.into()), - Err(err) => Self::Err(err.into()), - } - } -} - -impl From for StringWrapperResult { - fn from(value: String) -> Self { - Self::Ok(value.into()) - } -} diff --git a/profiling-ffi/src/crashtracker/demangler/mod.rs b/profiling-ffi/src/crashtracker/demangler/mod.rs deleted file mode 100644 index 3c1ed09bf..000000000 --- a/profiling-ffi/src/crashtracker/demangler/mod.rs +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright 2024-Present Datadog, Inc. https://www.datadoghq.com/ -// SPDX-License-Identifier: Apache-2.0 -mod datatypes; -pub use datatypes::*; - -use ddcommon_ffi::{slice::AsBytes, CharSlice}; -use symbolic_common::Name; -use symbolic_demangle::Demangle; - -/// Demangles the string "name". -/// If demangling fails, returns an empty string "" -/// -/// # Safety -/// `name` should be a valid reference to a utf8 encoded String. -/// The string is copied into the result, and does not need to outlive this call -#[no_mangle] -#[must_use] -pub unsafe extern "C" fn ddog_demangle( - name: CharSlice, - options: DemangleOptions, -) -> StringWrapperResult { - let name = name.to_utf8_lossy(); - let name = Name::from(name); - let options = match options { - DemangleOptions::Complete => symbolic_demangle::DemangleOptions::complete(), - DemangleOptions::NameOnly => symbolic_demangle::DemangleOptions::name_only(), - }; - StringWrapperResult::Ok(name.demangle(options).unwrap_or_default().into()) -} - -#[test] -fn test_demangle() { - let test_string = "_ZNSt28__atomic_futex_unsigned_base26_M_futex_wait_until_steadyEPjjbNSt6chrono8durationIlSt5ratioILl1ELl1EEEENS2_IlS3_ILl1ELl1000000000EEEE"; - let test_slice = CharSlice::from(test_string); - let result: String = unsafe { ddog_demangle(test_slice, DemangleOptions::Complete) } - .unwrap() - .into(); - assert_eq!(result, "std::__atomic_futex_unsigned_base::_M_futex_wait_until_steady(unsigned int*, unsigned int, bool, std::chrono::duration >, std::chrono::duration >)"); - - let result: String = unsafe { ddog_demangle(test_slice, DemangleOptions::NameOnly) } - .unwrap() - .into(); - assert_eq!( - result, - "std::__atomic_futex_unsigned_base::_M_futex_wait_until_steady" - ); -} - -#[test] -fn test_demangle_fails() { - let test_string = "_ZNSt28__fdf"; - let test_slice = CharSlice::from(test_string); - let result: String = unsafe { ddog_demangle(test_slice, DemangleOptions::Complete) } - .unwrap() - .into(); - assert_eq!(result, ""); - - let result: String = unsafe { ddog_demangle(test_slice, DemangleOptions::NameOnly) } - .unwrap() - .into(); - assert_eq!(result, ""); -} diff --git a/profiling-ffi/src/crashtracker/mod.rs b/profiling-ffi/src/crashtracker/mod.rs deleted file mode 100644 index 0a414c745..000000000 --- a/profiling-ffi/src/crashtracker/mod.rs +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2024-Present Datadog, Inc. https://www.datadoghq.com/ -// SPDX-License-Identifier: Apache-2.0 - -#[cfg(all(unix, feature = "crashtracker-collector"))] -mod collector; -mod crash_info; -mod datatypes; -mod demangler; -#[cfg(all(unix, feature = "crashtracker-receiver"))] -mod receiver; - -#[cfg(all(unix, feature = "crashtracker-collector"))] -pub use collector::*; -pub use crash_info::*; -pub use datatypes::*; -pub use demangler::*; -#[cfg(all(unix, feature = "crashtracker-receiver"))] -pub use receiver::*; diff --git a/profiling-ffi/src/crashtracker/receiver.rs b/profiling-ffi/src/crashtracker/receiver.rs deleted file mode 100644 index c366e19dc..000000000 --- a/profiling-ffi/src/crashtracker/receiver.rs +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2023-Present Datadog, Inc. https://www.datadoghq.com/ -// SPDX-License-Identifier: Apache-2.0 - -use crate::crashtracker::datatypes::*; -use anyhow::Context; -use ddcommon_ffi::{slice::AsBytes, CharSlice}; -#[no_mangle] -#[must_use] -/// Receives data from a crash collector via a pipe on `stdin`, formats it into -/// `CrashInfo` json, and emits it to the endpoint/file defined in `config`. -/// -/// At a high-level, this exists because doing anything in a -/// signal handler is dangerous, so we fork a sidecar to do the stuff we aren't -/// allowed to do in the handler. -/// -/// See comments in [profiling/crashtracker/mod.rs] for a full architecture -/// description. -/// # Safety -/// No safety concerns -pub unsafe extern "C" fn ddog_prof_Crashtracker_receiver_entry_point_stdin() -> CrashtrackerResult { - datadog_crashtracker::receiver_entry_point_stdin() - .context("ddog_prof_Crashtracker_receiver_entry_point_stdin failed") - .into() -} - -#[no_mangle] -#[must_use] -/// Receives data from a crash collector via a pipe on `stdin`, formats it into -/// `CrashInfo` json, and emits it to the endpoint/file defined in `config`. -/// -/// At a high-level, this exists because doing anything in a -/// signal handler is dangerous, so we fork a sidecar to do the stuff we aren't -/// allowed to do in the handler. -/// -/// See comments in [profiling/crashtracker/mod.rs] for a full architecture -/// description. -/// # Safety -/// No safety concerns -pub unsafe extern "C" fn ddog_prof_Crashtracker_receiver_entry_point_unix_socket( - socket_path: CharSlice, -) -> CrashtrackerResult { - (|| { - let socket_path = socket_path.try_to_utf8()?; - datadog_crashtracker::reciever_entry_point_unix_socket(socket_path) - })() - .context("ddog_prof_Crashtracker_receiver_entry_point_unix_socket failed") - .into() -} diff --git a/profiling-ffi/src/lib.rs b/profiling-ffi/src/lib.rs index 9f5c260c2..4f0c35753 100644 --- a/profiling-ffi/src/lib.rs +++ b/profiling-ffi/src/lib.rs @@ -9,11 +9,13 @@ use std::time::SystemTime; use chrono::{DateTime, TimeZone, Utc}; -mod crashtracker; mod exporter; mod profiles; -pub use crashtracker::*; +// re-export crashtracker ffi +#[cfg(feature = "crashtracker-ffi")] +pub use crashtracker_ffi::*; + // re-export telemetry ffi #[cfg(feature = "ddtelemetry-ffi")] pub use ddtelemetry_ffi::*; From 6537e948d31fb0a866defab57f296a8a8502ca2c Mon Sep 17 00:00:00 2001 From: Daniel Schwartz-Narbonne Date: Fri, 26 Jul 2024 17:10:01 -0400 Subject: [PATCH 06/31] Actually seems to work --- crashtracker-ffi/cbindgen.toml | 3 +- crashtracker-ffi/src/collector/counters.rs | 18 +++----- crashtracker-ffi/src/collector/datatypes.rs | 22 ++++----- crashtracker-ffi/src/collector/mod.rs | 32 ++++++------- crashtracker-ffi/src/collector/spans.rs | 34 +++++++------- crashtracker-ffi/src/crash_info/datatypes.rs | 6 +-- crashtracker-ffi/src/crash_info/mod.rs | 39 ++++++---------- crashtracker-ffi/src/datatypes/mod.rs | 4 +- crashtracker-ffi/src/receiver.rs | 12 ++--- .../libdatadog-crashtracking-receiver.c | 4 +- crashtracker/src/README.md | 6 +-- crashtracker/src/receiver.rs | 1 + examples/ffi/crashinfo.cpp | 46 ++++++++++--------- examples/ffi/crashtracking.c | 26 +++++------ 14 files changed, 121 insertions(+), 132 deletions(-) diff --git a/crashtracker-ffi/cbindgen.toml b/crashtracker-ffi/cbindgen.toml index 7402167c6..449e66ad9 100644 --- a/crashtracker-ffi/cbindgen.toml +++ b/crashtracker-ffi/cbindgen.toml @@ -16,13 +16,14 @@ sys_includes = ["stdbool.h", "stddef.h", "stdint.h"] includes = ["common.h"] [export] -prefix = "ddog_prof_" +prefix = "ddog_crashtracker_" renaming_overrides_prefixing = true [export.rename] "ByteSlice" = "ddog_ByteSlice" "CancellationToken" = "ddog_CancellationToken" "CharSlice" = "ddog_CharSlice" +"Endpoint" = "ddog_Endpoint" "Error" = "ddog_Error" "HttpStatus" = "ddog_HttpStatus" "Slice_CChar" = "ddog_Slice_CChar" diff --git a/crashtracker-ffi/src/collector/counters.rs b/crashtracker-ffi/src/collector/counters.rs index 8581af4ea..1469f753c 100644 --- a/crashtracker-ffi/src/collector/counters.rs +++ b/crashtracker-ffi/src/collector/counters.rs @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 use super::datatypes::ProfilingOpTypes; -use crate::CrashtrackerResult; +use crate::Result; use anyhow::Context; /// Resets all counters to 0. @@ -15,9 +15,9 @@ use anyhow::Context; /// No safety concerns. #[no_mangle] #[must_use] -pub unsafe extern "C" fn ddog_prof_Crashtracker_reset_counters() -> CrashtrackerResult { +pub unsafe extern "C" fn ddog_crashtracker_reset_counters() -> Result { datadog_crashtracker::reset_counters() - .context("ddog_prof_Crashtracker_begin_profiling_op failed") + .context("ddog_crashtracker_begin_profiling_op failed") .into() } @@ -28,11 +28,9 @@ pub unsafe extern "C" fn ddog_prof_Crashtracker_reset_counters() -> Crashtracker /// /// # Safety /// No safety concerns. -pub unsafe extern "C" fn ddog_prof_Crashtracker_begin_profiling_op( - op: ProfilingOpTypes, -) -> CrashtrackerResult { +pub unsafe extern "C" fn ddog_crashtracker_begin_profiling_op(op: ProfilingOpTypes) -> Result { datadog_crashtracker::begin_profiling_op(op) - .context("ddog_prof_Crashtracker_begin_profiling_op failed") + .context("ddog_crashtracker_begin_profiling_op failed") .into() } @@ -43,10 +41,8 @@ pub unsafe extern "C" fn ddog_prof_Crashtracker_begin_profiling_op( /// /// # Safety /// No safety concerns. -pub unsafe extern "C" fn ddog_prof_Crashtracker_end_profiling_op( - op: ProfilingOpTypes, -) -> CrashtrackerResult { +pub unsafe extern "C" fn ddog_crashtracker_end_profiling_op(op: ProfilingOpTypes) -> Result { datadog_crashtracker::end_profiling_op(op) - .context("ddog_prof_Crashtracker_end_profiling_op failed") + .context("ddog_crashtracker_end_profiling_op failed") .into() } diff --git a/crashtracker-ffi/src/collector/datatypes.rs b/crashtracker-ffi/src/collector/datatypes.rs index 1af121aed..e272c9526 100644 --- a/crashtracker-ffi/src/collector/datatypes.rs +++ b/crashtracker-ffi/src/collector/datatypes.rs @@ -14,7 +14,7 @@ pub struct EnvVar<'a> { } #[repr(C)] -pub struct CrashtrackerReceiverConfig<'a> { +pub struct ReceiverConfig<'a> { pub args: Slice<'a, CharSlice<'a>>, pub env: Slice<'a, EnvVar<'a>>, pub path_to_receiver_binary: CharSlice<'a>, @@ -24,11 +24,9 @@ pub struct CrashtrackerReceiverConfig<'a> { pub optional_stdout_filename: CharSlice<'a>, } -impl<'a> TryFrom> - for datadog_crashtracker::CrashtrackerReceiverConfig -{ +impl<'a> TryFrom> for datadog_crashtracker::CrashtrackerReceiverConfig { type Error = anyhow::Error; - fn try_from(value: CrashtrackerReceiverConfig<'a>) -> anyhow::Result { + fn try_from(value: ReceiverConfig<'a>) -> anyhow::Result { let args = { let mut vec = Vec::with_capacity(value.args.len()); for x in value.args.iter() { @@ -60,7 +58,7 @@ impl<'a> TryFrom> } #[repr(C)] -pub struct CrashtrackerConfiguration<'a> { +pub struct Configuration<'a> { pub additional_files: Slice<'a, CharSlice<'a>>, pub create_alt_stack: bool, /// The endpoint to send the crash report to (can be a file://). @@ -71,11 +69,9 @@ pub struct CrashtrackerConfiguration<'a> { pub wait_for_receiver: bool, } -impl<'a> TryFrom> - for datadog_crashtracker::CrashtrackerConfiguration -{ +impl<'a> TryFrom> for datadog_crashtracker::CrashtrackerConfiguration { type Error = anyhow::Error; - fn try_from(value: CrashtrackerConfiguration<'a>) -> anyhow::Result { + fn try_from(value: Configuration<'a>) -> anyhow::Result { let additional_files = { let mut vec = Vec::with_capacity(value.additional_files.len()); for x in value.additional_files.iter() { @@ -84,7 +80,7 @@ impl<'a> TryFrom> vec }; let create_alt_stack = value.create_alt_stack; - let endpoint = None; // DSNunsafe { exporter::try_to_endpoint(value.endpoint).ok() }; + let endpoint = value.endpoint.cloned(); let resolve_frames = value.resolve_frames; let wait_for_receiver = value.wait_for_receiver; Self::new( @@ -98,13 +94,13 @@ impl<'a> TryFrom> } #[repr(C)] -pub enum CrashtrackerUsizeResult { +pub enum UsizeResult { Ok(usize), #[allow(dead_code)] Err(Error), } -impl From> for CrashtrackerUsizeResult { +impl From> for UsizeResult { fn from(value: anyhow::Result) -> Self { match value { Ok(x) => Self::Ok(x), diff --git a/crashtracker-ffi/src/collector/mod.rs b/crashtracker-ffi/src/collector/mod.rs index d2a11f662..b8fbd84b5 100644 --- a/crashtracker-ffi/src/collector/mod.rs +++ b/crashtracker-ffi/src/collector/mod.rs @@ -4,8 +4,8 @@ mod counters; mod datatypes; mod spans; -use super::crash_info::CrashtrackerMetadata; -use crate::CrashtrackerResult; +use super::crash_info::Metadata; +use crate::Result; use anyhow::Context; pub use counters::*; pub use datatypes::*; @@ -28,9 +28,9 @@ pub use spans::*; /// # Atomicity /// This function is not atomic. A crash during its execution may lead to /// unexpected crash-handling behaviour. -pub unsafe extern "C" fn ddog_prof_Crashtracker_shutdown() -> CrashtrackerResult { +pub unsafe extern "C" fn ddog_crashtracker_shutdown() -> Result { datadog_crashtracker::shutdown_crash_handler() - .context("ddog_prof_Crashtracker_shutdown failed") + .context("ddog_crashtracker_shutdown failed") .into() } @@ -54,18 +54,18 @@ pub unsafe extern "C" fn ddog_prof_Crashtracker_shutdown() -> CrashtrackerResult /// # Atomicity /// This function is not atomic. A crash during its execution may lead to /// unexpected crash-handling behaviour. -pub unsafe extern "C" fn ddog_prof_Crashtracker_update_on_fork( - config: CrashtrackerConfiguration, - receiver_config: CrashtrackerReceiverConfig, - metadata: CrashtrackerMetadata, -) -> CrashtrackerResult { +pub unsafe extern "C" fn ddog_crashtracker_update_on_fork( + config: Configuration, + receiver_config: ReceiverConfig, + metadata: Metadata, +) -> Result { (|| { let config = config.try_into()?; let receiver_config = receiver_config.try_into()?; let metadata = metadata.try_into()?; datadog_crashtracker::on_fork(config, receiver_config, metadata) })() - .context("ddog_prof_Crashtracker_update_on_fork failed") + .context("ddog_crashtracker_update_on_fork failed") .into() } @@ -81,17 +81,17 @@ pub unsafe extern "C" fn ddog_prof_Crashtracker_update_on_fork( /// # Atomicity /// This function is not atomic. A crash during its execution may lead to /// unexpected crash-handling behaviour. -pub unsafe extern "C" fn ddog_prof_Crashtracker_init_with_receiver( - config: CrashtrackerConfiguration, - receiver_config: CrashtrackerReceiverConfig, - metadata: CrashtrackerMetadata, -) -> CrashtrackerResult { +pub unsafe extern "C" fn ddog_crashtracker_init_with_receiver( + config: Configuration, + receiver_config: ReceiverConfig, + metadata: Metadata, +) -> Result { (|| { let config = config.try_into()?; let receiver_config = receiver_config.try_into()?; let metadata = metadata.try_into()?; datadog_crashtracker::init_with_receiver(config, receiver_config, metadata) })() - .context("ddog_prof_Crashtracker_init failed") + .context("ddog_crashtracker_init failed") .into() } diff --git a/crashtracker-ffi/src/collector/spans.rs b/crashtracker-ffi/src/collector/spans.rs index 063573a96..70cdff34d 100644 --- a/crashtracker-ffi/src/collector/spans.rs +++ b/crashtracker-ffi/src/collector/spans.rs @@ -1,7 +1,7 @@ // Copyright 2024-Present Datadog, Inc. https://www.datadoghq.com/ // SPDX-License-Identifier: Apache-2.0 -use crate::{CrashtrackerResult, CrashtrackerUsizeResult}; +use crate::{Result, UsizeResult}; use anyhow::Context; /// Resets all stored spans to 0. @@ -14,9 +14,9 @@ use anyhow::Context; /// No safety concerns. #[no_mangle] #[must_use] -pub unsafe extern "C" fn ddog_prof_Crashtracker_clear_span_ids() -> CrashtrackerResult { +pub unsafe extern "C" fn ddog_crashtracker_clear_span_ids() -> Result { datadog_crashtracker::clear_spans() - .context("ddog_prof_Crashtracker_clear_span_ids failed") + .context("ddog_crashtracker_clear_span_ids failed") .into() } @@ -30,9 +30,9 @@ pub unsafe extern "C" fn ddog_prof_Crashtracker_clear_span_ids() -> Crashtracker /// No safety concerns. #[no_mangle] #[must_use] -pub unsafe extern "C" fn ddog_prof_Crashtracker_clear_trace_ids() -> CrashtrackerResult { +pub unsafe extern "C" fn ddog_crashtracker_clear_trace_ids() -> Result { datadog_crashtracker::clear_traces() - .context("ddog_prof_Crashtracker_clear_trace_ids failed") + .context("ddog_crashtracker_clear_trace_ids failed") .into() } @@ -57,13 +57,13 @@ pub unsafe extern "C" fn ddog_prof_Crashtracker_clear_trace_ids() -> Crashtracke /// /// # Safety /// No safety concerns. -pub unsafe extern "C" fn ddog_prof_Crashtracker_insert_trace_id( +pub unsafe extern "C" fn ddog_crashtracker_insert_trace_id( id_high: u64, id_low: u64, -) -> CrashtrackerUsizeResult { +) -> UsizeResult { let id: u128 = (id_high as u128) << 64 | (id_low as u128); datadog_crashtracker::insert_trace(id) - .context("ddog_prof_Crashtracker_insert_trace_id failed") + .context("ddog_crashtracker_insert_trace_id failed") .into() } @@ -89,13 +89,13 @@ pub unsafe extern "C" fn ddog_prof_Crashtracker_insert_trace_id( /// /// # Safety /// No safety concerns. -pub unsafe extern "C" fn ddog_prof_Crashtracker_insert_span_id( +pub unsafe extern "C" fn ddog_crashtracker_insert_span_id( id_high: u64, id_low: u64, -) -> CrashtrackerUsizeResult { +) -> UsizeResult { let id: u128 = (id_high as u128) << 64 | (id_low as u128); datadog_crashtracker::insert_span(id) - .context("ddog_prof_Crashtracker_insert_span_id failed") + .context("ddog_crashtracker_insert_span_id failed") .into() } @@ -121,14 +121,14 @@ pub unsafe extern "C" fn ddog_prof_Crashtracker_insert_span_id( /// /// # Safety /// No safety concerns. -pub unsafe extern "C" fn ddog_prof_Crashtracker_remove_span_id( +pub unsafe extern "C" fn ddog_crashtracker_remove_span_id( id_high: u64, id_low: u64, idx: usize, -) -> CrashtrackerResult { +) -> Result { let id: u128 = (id_high as u128) << 64 | (id_low as u128); datadog_crashtracker::remove_span(id, idx) - .context("ddog_prof_Crashtracker_remove_span_id failed") + .context("ddog_crashtracker_remove_span_id failed") .into() } @@ -154,13 +154,13 @@ pub unsafe extern "C" fn ddog_prof_Crashtracker_remove_span_id( /// /// # Safety /// No safety concerns. -pub unsafe extern "C" fn ddog_prof_Crashtracker_remove_trace_id( +pub unsafe extern "C" fn ddog_crashtracker_remove_trace_id( id_high: u64, id_low: u64, idx: usize, -) -> CrashtrackerResult { +) -> Result { let id: u128 = (id_high as u128) << 64 | (id_low as u128); datadog_crashtracker::remove_trace(id, idx) - .context("ddog_prof_Crashtracker_remove_trace_id failed") + .context("ddog_crashtracker_remove_trace_id failed") .into() } diff --git a/crashtracker-ffi/src/crash_info/datatypes.rs b/crashtracker-ffi/src/crash_info/datatypes.rs index 5f75a1537..f4a31ed55 100644 --- a/crashtracker-ffi/src/crash_info/datatypes.rs +++ b/crashtracker-ffi/src/crash_info/datatypes.rs @@ -227,7 +227,7 @@ impl<'a> TryFrom> for datadog_crashtracker::SigInfo { } #[repr(C)] -pub struct CrashtrackerMetadata<'a> { +pub struct Metadata<'a> { pub profiling_library_name: CharSlice<'a>, pub profiling_library_version: CharSlice<'a>, pub family: CharSlice<'a>, @@ -235,9 +235,9 @@ pub struct CrashtrackerMetadata<'a> { pub tags: Option<&'a ddcommon_ffi::Vec>, } -impl<'a> TryFrom> for datadog_crashtracker::CrashtrackerMetadata { +impl<'a> TryFrom> for datadog_crashtracker::CrashtrackerMetadata { type Error = anyhow::Error; - fn try_from(value: CrashtrackerMetadata<'a>) -> anyhow::Result { + fn try_from(value: Metadata<'a>) -> anyhow::Result { let profiling_library_name = value.profiling_library_name.try_to_utf8()?.to_string(); let profiling_library_version = value.profiling_library_version.try_to_utf8()?.to_string(); let family = value.family.try_to_utf8()?.to_string(); diff --git a/crashtracker-ffi/src/crash_info/mod.rs b/crashtracker-ffi/src/crash_info/mod.rs index 36a29907a..cbb979b8f 100644 --- a/crashtracker-ffi/src/crash_info/mod.rs +++ b/crashtracker-ffi/src/crash_info/mod.rs @@ -4,16 +4,10 @@ mod datatypes; pub use datatypes::*; -//DSN -#[repr(C)] -pub struct ProfilingEndpoint<'a> { - _nonempty: bool, - _pd: std::marker::PhantomData<&'a bool>, -} - -use crate::{option_from_char_slice, CrashtrackerResult}; +use crate::{option_from_char_slice, Result}; use anyhow::Context; use chrono::DateTime; +use ddcommon::Endpoint; use ddcommon_ffi::{slice::AsBytes, CharSlice, Slice}; /// Create a new crashinfo, and returns an opaque reference to it. @@ -48,7 +42,7 @@ pub unsafe extern "C" fn ddog_crashinfo_drop(crashinfo: *mut CrashInfo) { pub unsafe extern "C" fn ddog_crashinfo_normalize_ips( crashinfo: *mut CrashInfo, pid: u32, -) -> CrashtrackerResult { +) -> Result { (|| { let crashinfo = crashinfo_ptr_to_inner(crashinfo)?; crashinfo.normalize_ips(pid) @@ -71,7 +65,7 @@ pub unsafe extern "C" fn ddog_crashinfo_add_counter( crashinfo: *mut CrashInfo, name: CharSlice, val: i64, -) -> CrashtrackerResult { +) -> Result { (|| { let crashinfo = crashinfo_ptr_to_inner(crashinfo)?; let name = name.to_utf8_lossy(); @@ -93,7 +87,7 @@ pub unsafe extern "C" fn ddog_crashinfo_add_counter( pub unsafe extern "C" fn ddog_crashinfo_add_file( crashinfo: *mut CrashInfo, name: CharSlice, -) -> CrashtrackerResult { +) -> Result { (|| { let crashinfo = crashinfo_ptr_to_inner(crashinfo)?; let name = name.to_utf8_lossy(); @@ -117,7 +111,7 @@ pub unsafe extern "C" fn ddog_crashinfo_add_tag( crashinfo: *mut CrashInfo, key: CharSlice, value: CharSlice, -) -> CrashtrackerResult { +) -> Result { (|| { let crashinfo = crashinfo_ptr_to_inner(crashinfo)?; let key = key.to_utf8_lossy().to_string(); @@ -138,8 +132,8 @@ pub unsafe extern "C" fn ddog_crashinfo_add_tag( #[must_use] pub unsafe extern "C" fn ddog_crashinfo_set_metadata( crashinfo: *mut CrashInfo, - metadata: CrashtrackerMetadata, -) -> CrashtrackerResult { + metadata: Metadata, +) -> Result { (|| { let crashinfo = crashinfo_ptr_to_inner(crashinfo)?; let metadata = metadata.try_into()?; @@ -160,7 +154,7 @@ pub unsafe extern "C" fn ddog_crashinfo_set_metadata( pub unsafe extern "C" fn ddog_crashinfo_set_siginfo( crashinfo: *mut CrashInfo, siginfo: SigInfo, -) -> CrashtrackerResult { +) -> Result { (|| { let crashinfo = crashinfo_ptr_to_inner(crashinfo)?; let siginfo = siginfo.try_into()?; @@ -183,7 +177,7 @@ pub unsafe extern "C" fn ddog_crashinfo_set_stacktrace( crashinfo: *mut CrashInfo, thread_id: CharSlice, stacktrace: Slice, -) -> CrashtrackerResult { +) -> Result { (|| { let crashinfo = crashinfo_ptr_to_inner(crashinfo)?; let thread_id = option_from_char_slice(thread_id)?; @@ -207,7 +201,7 @@ pub unsafe extern "C" fn ddog_crashinfo_set_timestamp( crashinfo: *mut CrashInfo, secs: i64, nsecs: u32, -) -> CrashtrackerResult { +) -> Result { (|| { let crashinfo = crashinfo_ptr_to_inner(crashinfo)?; let ts = DateTime::from_timestamp(secs, nsecs) @@ -224,9 +218,7 @@ pub unsafe extern "C" fn ddog_crashinfo_set_timestamp( /// `crashinfo` must be a valid pointer to a `CrashInfo` object. #[no_mangle] #[must_use] -pub unsafe extern "C" fn ddog_crashinfo_set_timestamp_to_now( - crashinfo: *mut CrashInfo, -) -> CrashtrackerResult { +pub unsafe extern "C" fn ddog_crashinfo_set_timestamp_to_now(crashinfo: *mut CrashInfo) -> Result { (|| { let crashinfo = crashinfo_ptr_to_inner(crashinfo)?; crashinfo.set_timestamp_to_now() @@ -243,12 +235,11 @@ pub unsafe extern "C" fn ddog_crashinfo_set_timestamp_to_now( #[must_use] pub unsafe extern "C" fn ddog_crashinfo_upload_to_endpoint( crashinfo: *mut CrashInfo, - _endpoint: ProfilingEndpoint, -) -> CrashtrackerResult { + endpoint: Option<&Endpoint>, +) -> Result { (|| { let crashinfo = crashinfo_ptr_to_inner(crashinfo)?; - // DSN - let endpoint = None; //Some(unsafe { crate::exporter::try_to_endpoint(endpoint)? }); + let endpoint = endpoint.cloned(); crashinfo.upload_to_endpoint(&endpoint) })() .context("ddog_crashinfo_upload_to_endpoint failed") diff --git a/crashtracker-ffi/src/datatypes/mod.rs b/crashtracker-ffi/src/datatypes/mod.rs index ec7b51f7e..04eb263ab 100644 --- a/crashtracker-ffi/src/datatypes/mod.rs +++ b/crashtracker-ffi/src/datatypes/mod.rs @@ -13,7 +13,7 @@ pub fn option_from_char_slice(s: CharSlice) -> anyhow::Result> { /// A generic result type for when a crashtracking operation may fail, /// but there's nothing to return in the case of success. #[repr(C)] -pub enum CrashtrackerResult { +pub enum Result { Ok( /// Do not use the value of Ok. This value only exists to overcome /// Rust -> C code generation. @@ -22,7 +22,7 @@ pub enum CrashtrackerResult { Err(Error), } -impl From> for CrashtrackerResult { +impl From> for Result { fn from(value: anyhow::Result<()>) -> Self { match value { Ok(_) => Self::Ok(true), diff --git a/crashtracker-ffi/src/receiver.rs b/crashtracker-ffi/src/receiver.rs index e3d3ced24..05bbda078 100644 --- a/crashtracker-ffi/src/receiver.rs +++ b/crashtracker-ffi/src/receiver.rs @@ -1,7 +1,7 @@ // Copyright 2023-Present Datadog, Inc. https://www.datadoghq.com/ // SPDX-License-Identifier: Apache-2.0 -use crate::CrashtrackerResult; +use crate::Result; use anyhow::Context; use ddcommon_ffi::{slice::AsBytes, CharSlice}; #[no_mangle] @@ -17,9 +17,9 @@ use ddcommon_ffi::{slice::AsBytes, CharSlice}; /// description. /// # Safety /// No safety concerns -pub unsafe extern "C" fn ddog_prof_Crashtracker_receiver_entry_point_stdin() -> CrashtrackerResult { +pub unsafe extern "C" fn ddog_crashtracker_receiver_entry_point_stdin() -> Result { datadog_crashtracker::receiver_entry_point_stdin() - .context("ddog_prof_Crashtracker_receiver_entry_point_stdin failed") + .context("ddog_crashtracker_receiver_entry_point_stdin failed") .into() } @@ -36,13 +36,13 @@ pub unsafe extern "C" fn ddog_prof_Crashtracker_receiver_entry_point_stdin() -> /// description. /// # Safety /// No safety concerns -pub unsafe extern "C" fn ddog_prof_Crashtracker_receiver_entry_point_unix_socket( +pub unsafe extern "C" fn ddog_crashtracker_receiver_entry_point_unix_socket( socket_path: CharSlice, -) -> CrashtrackerResult { +) -> Result { (|| { let socket_path = socket_path.try_to_utf8()?; datadog_crashtracker::reciever_entry_point_unix_socket(socket_path) })() - .context("ddog_prof_Crashtracker_receiver_entry_point_unix_socket failed") + .context("ddog_crashtracker_receiver_entry_point_unix_socket failed") .into() } diff --git a/crashtracker/libdatadog-crashtracking-receiver.c b/crashtracker/libdatadog-crashtracking-receiver.c index f7a57fb9d..506da967e 100644 --- a/crashtracker/libdatadog-crashtracking-receiver.c +++ b/crashtracker/libdatadog-crashtracking-receiver.c @@ -7,8 +7,8 @@ #include int main(void) { - ddog_prof_CrashtrackerResult new_result = ddog_prof_Crashtracker_receiver_entry_point_stdin(); - if (new_result.tag != DDOG_PROF_CRASHTRACKER_RESULT_OK) { + ddog_crashtracker_Result new_result = ddog_crashtracker_receiver_entry_point_stdin(); + if (new_result.tag != DDOG_CRASHTRACKER_RESULT_OK) { ddog_CharSlice message = ddog_Error_message(&new_result.err); fprintf(stderr, "%.*s", (int)message.len, message.ptr); ddog_Error_drop(&new_result.err); diff --git a/crashtracker/src/README.md b/crashtracker/src/README.md index 06755ee56..09357ab94 100644 --- a/crashtracker/src/README.md +++ b/crashtracker/src/README.md @@ -13,10 +13,10 @@ It has three related parts: ## How to use the crashhandler -1. Initilize it using `ddog_prof_Crashtracker_init` -2. After a fork, reset the crashtracker in the child using `ddog_prof_Crashtracker_update_on_fork`. +1. Initilize it using `ddog_crashtracker_init` +2. After a fork, reset the crashtracker in the child using `ddog_crashtracker_update_on_fork`. This can be done in an `pthread_atfork` handler. -2. [Optional]. The crash-tracker can be shutdown, and the previous crash handler restored, using `ddog_prof_Crashtracker_shutdown`. +2. [Optional]. The crash-tracker can be shutdown, and the previous crash handler restored, using `ddog_crashtracker_shutdown`. Currently, there is a state machine that stops you from then restarting the crash-tracker. Fixing this is a todo diff --git a/crashtracker/src/receiver.rs b/crashtracker/src/receiver.rs index eed6a8eb4..f009c97af 100644 --- a/crashtracker/src/receiver.rs +++ b/crashtracker/src/receiver.rs @@ -223,6 +223,7 @@ fn process_line( Ok(next) } +#[derive(Debug)] enum CrashReportStatus { NoCrash, CrashReport(CrashtrackerConfiguration, CrashInfo), diff --git a/examples/ffi/crashinfo.cpp b/examples/ffi/crashinfo.cpp index 0b70fc9b0..1b28c390e 100644 --- a/examples/ffi/crashinfo.cpp +++ b/examples/ffi/crashinfo.cpp @@ -3,7 +3,7 @@ extern "C" { #include -#include +#include } #include #include @@ -21,15 +21,17 @@ static ddog_CharSlice to_slice_string(std::string &s) { // TODO: Testing on my mac, the tags appear to have the opposite meaning you'd // expect -static ddog_prof_Option_U32 some_u32(uint32_t i) { - ddog_prof_Option_U32 rval = {.tag = DDOG_PROF_OPTION_U32_SOME_U32}; +static ddog_crashtracker_Option_U32 some_u32(uint32_t i) { + ddog_crashtracker_Option_U32 rval = {.tag = DDOG_CRASHTRACKER_OPTION_U32_SOME_U32}; rval.some = i; return rval; } -static ddog_prof_Option_U32 none_u32() { return {.tag = DDOG_PROF_OPTION_U32_NONE_U32}; } +static ddog_crashtracker_Option_U32 none_u32() { + return {.tag = DDOG_CRASHTRACKER_OPTION_U32_NONE_U32}; +} struct Deleter { - void operator()(ddog_prof_CrashInfo *object) { ddog_crashinfo_drop(object); } + void operator()(ddog_crashtracker_CrashInfo *object) { ddog_crashinfo_drop(object); } }; void print_error(const char *s, const ddog_Error &err) { @@ -37,15 +39,15 @@ void print_error(const char *s, const ddog_Error &err) { printf("%s (%.*s)\n", s, static_cast(charslice.len), charslice.ptr); } -void check_result(ddog_prof_CrashtrackerResult result, const char *msg) { - if (result.tag != DDOG_PROF_CRASHTRACKER_RESULT_OK) { +void check_result(ddog_crashtracker_Result result, const char *msg) { + if (result.tag != DDOG_CRASHTRACKER_RESULT_OK) { print_error(msg, result.err); ddog_Error_drop(&result.err); exit(EXIT_FAILURE); } } -void add_stacktrace(std::unique_ptr &crashinfo) { +void add_stacktrace(std::unique_ptr &crashinfo) { // Collect things into vectors so they stay alive till the function exits std::vector filenames; @@ -55,7 +57,7 @@ void add_stacktrace(std::unique_ptr &crashinfo) { function_names.push_back("func_" + std::to_string(i)); } - std::vector names; + std::vector names; for (uintptr_t i = 0; i < 20; ++i) { names.push_back({.colno = some_u32(i), .filename = to_slice_string(filenames[i]), @@ -63,16 +65,16 @@ void add_stacktrace(std::unique_ptr &crashinfo) { .name = to_slice_string(function_names[i])}); } - std::vector trace; + std::vector trace; for (uintptr_t i = 0; i < 20; ++i) { - ddog_prof_StackFrame frame = {.ip = i, - .module_base_address = 0, - .names = {.ptr = &names[i], .len = 1}, - .sp = 0, - .symbol_address = 0}; + ddog_crashtracker_StackFrame frame = {.ip = i, + .module_base_address = 0, + .names = {.ptr = &names[i], .len = 1}, + .sp = 0, + .symbol_address = 0}; trace.push_back(frame); } - ddog_prof_Slice_StackFrame trace_slice = {.ptr = trace.data(), .len = trace.size()}; + ddog_crashtracker_Slice_StackFrame trace_slice = {.ptr = trace.data(), .len = trace.size()}; check_result(ddog_crashinfo_set_stacktrace(crashinfo.get(), to_slice_c_char(""), trace_slice), "Failed to set stacktrace"); @@ -80,12 +82,12 @@ void add_stacktrace(std::unique_ptr &crashinfo) { int main(void) { auto crashinfo_new_result = ddog_crashinfo_new(); - if (crashinfo_new_result.tag != DDOG_PROF_CRASH_INFO_NEW_RESULT_OK) { + if (crashinfo_new_result.tag != DDOG_CRASHTRACKER_CRASH_INFO_NEW_RESULT_OK) { print_error("Failed to make new crashinfo: ", crashinfo_new_result.err); ddog_Error_drop(&crashinfo_new_result.err); exit(EXIT_FAILURE); } - std::unique_ptr crashinfo{&crashinfo_new_result.ok}; + std::unique_ptr crashinfo{&crashinfo_new_result.ok}; check_result( ddog_crashinfo_add_counter(crashinfo.get(), to_slice_c_char("my_amazing_counter"), 3), @@ -93,7 +95,7 @@ int main(void) { // TODO add some tags here auto tags = ddog_Vec_Tag_new(); - const ddog_prof_CrashtrackerMetadata metadata = { + const ddog_crashtracker_Metadata metadata = { .profiling_library_name = to_slice_c_char("libdatadog"), .profiling_library_version = to_slice_c_char("42"), .family = to_slice_c_char("rust"), @@ -118,7 +120,9 @@ int main(void) { check_result(ddog_crashinfo_set_timestamp(crashinfo.get(), 1568899800, 0), "Failed to set timestamp"); - check_result(ddog_crashinfo_upload_to_endpoint( - crashinfo.get(), ddog_Endpoint_file(to_slice_c_char("file://tmp/test"))), + auto endpoint = ddog_endpoint_from_filename(to_slice_c_char("/tmp/test")); + + check_result(ddog_crashinfo_upload_to_endpoint(crashinfo.get(), endpoint), "Failed to export to file"); + ddog_endpoint_drop(endpoint); } \ No newline at end of file diff --git a/examples/ffi/crashtracking.c b/examples/ffi/crashtracking.c index 63725a919..6f7f7f51b 100644 --- a/examples/ffi/crashtracking.c +++ b/examples/ffi/crashtracking.c @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 #include -#include +#include #include #include #include @@ -12,8 +12,8 @@ void example_segfault_handler(int signal) { exit(-1); } -void handle_result(ddog_prof_CrashtrackerResult result) { - if (result.tag == DDOG_PROF_PROFILE_RESULT_ERR) { +void handle_result(ddog_crashtracker_Result result) { + if (result.tag == DDOG_CRASHTRACKER_RESULT_ERR) { ddog_CharSlice message = ddog_Error_message(&result.err); fprintf(stderr, "%.*s\n", (int)message.len, message.ptr); ddog_Error_drop(&result.err); @@ -21,8 +21,8 @@ void handle_result(ddog_prof_CrashtrackerResult result) { } } -uintptr_t handle_uintptr_t_result(ddog_prof_CrashtrackerUsizeResult result) { - if (result.tag == DDOG_PROF_PROFILE_RESULT_ERR) { +uintptr_t handle_uintptr_t_result(ddog_crashtracker_UsizeResult result) { + if (result.tag == DDOG_CRASHTRACKER_USIZE_RESULT_ERR) { ddog_CharSlice message = ddog_Error_message(&result.err); fprintf(stderr, "%.*s\n", (int)message.len, message.ptr); ddog_Error_drop(&result.err); @@ -37,7 +37,7 @@ int main(int argc, char **argv) { return -1; } - ddog_prof_CrashtrackerReceiverConfig receiver_config = { + ddog_crashtracker_ReceiverConfig receiver_config = { .args = {}, .env = {}, .path_to_receiver_binary = DDOG_CHARSLICE_C("SET ME TO THE ACTUAL PATH ON YOUR MACHINE"), @@ -55,26 +55,26 @@ int main(int argc, char **argv) { // struct ddog_Endpoint * endpoint = // ddog_endpoint_from_url(DDOG_CHARSLICE_C("http://localhost:8126")); - ddog_prof_CrashtrackerConfiguration config = { + ddog_crashtracker_Configuration config = { .create_alt_stack = false, .endpoint = endpoint, - .resolve_frames = DDOG_PROF_STACKTRACE_COLLECTION_ENABLED_WITH_INPROCESS_SYMBOLS, + .resolve_frames = DDOG_CRASHTRACKER_STACKTRACE_COLLECTION_ENABLED_WITH_INPROCESS_SYMBOLS, }; - ddog_prof_CrashtrackerMetadata metadata = { + ddog_crashtracker_Metadata metadata = { .profiling_library_name = DDOG_CHARSLICE_C("crashtracking-test"), .profiling_library_version = DDOG_CHARSLICE_C("12.34.56"), .family = DDOG_CHARSLICE_C("crashtracking-test"), .tags = NULL, }; - handle_result(ddog_prof_Crashtracker_init_with_receiver(config, receiver_config, metadata)); + handle_result(ddog_crashtracker_init_with_receiver(config, receiver_config, metadata)); ddog_endpoint_drop(endpoint); handle_result( - ddog_prof_Crashtracker_begin_profiling_op(DDOG_PROF_PROFILING_OP_TYPES_SERIALIZING)); - handle_uintptr_t_result(ddog_prof_Crashtracker_insert_span_id(0, 42)); - handle_uintptr_t_result(ddog_prof_Crashtracker_insert_trace_id(1, 1)); + ddog_crashtracker_begin_profiling_op(DDOG_CRASHTRACKER_PROFILING_OP_TYPES_SERIALIZING)); + handle_uintptr_t_result(ddog_crashtracker_insert_span_id(0, 42)); + handle_uintptr_t_result(ddog_crashtracker_insert_trace_id(1, 1)); #ifdef EXPLICIT_RAISE_SEGV // Test raising SEGV explicitly, to ensure chaining works From 459311f30d3f8162c85b460949bb022fcee6d49b Mon Sep 17 00:00:00 2001 From: Daniel Schwartz-Narbonne Date: Fri, 26 Jul 2024 17:14:24 -0400 Subject: [PATCH 07/31] fix the dockerfile --- tools/docker/Dockerfile.build | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/docker/Dockerfile.build b/tools/docker/Dockerfile.build index 9db3aab71..955ff42a1 100644 --- a/tools/docker/Dockerfile.build +++ b/tools/docker/Dockerfile.build @@ -77,6 +77,7 @@ COPY [ "Cargo.lock", "Cargo.toml", "./"] COPY "alloc/Cargo.toml" "alloc/" COPY "build-common/Cargo.toml" "build-common/" COPY "crashtracker/Cargo.toml" "crashtracker/" +COPY "crashtracker-ffi/Cargo.toml" "crashtracker-ffi/" COPY "ddcommon/Cargo.toml" "ddcommon/" COPY "ddcommon-ffi/Cargo.toml" "ddcommon-ffi/" COPY "ddtelemetry/Cargo.toml" "ddtelemetry/" From 995abe4460e0f52dbb3f839f9a4190941d2a081b Mon Sep 17 00:00:00 2001 From: Daniel Schwartz-Narbonne Date: Fri, 26 Jul 2024 17:16:44 -0400 Subject: [PATCH 08/31] trailing newline --- examples/ffi/crashinfo.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/ffi/crashinfo.cpp b/examples/ffi/crashinfo.cpp index 1b28c390e..bea177ce5 100644 --- a/examples/ffi/crashinfo.cpp +++ b/examples/ffi/crashinfo.cpp @@ -125,4 +125,4 @@ int main(void) { check_result(ddog_crashinfo_upload_to_endpoint(crashinfo.get(), endpoint), "Failed to export to file"); ddog_endpoint_drop(endpoint); -} \ No newline at end of file +} From 0411e84b4abbe289d60d53ad4adcf5adb6560750 Mon Sep 17 00:00:00 2001 From: Daniel Schwartz-Narbonne Date: Fri, 26 Jul 2024 17:20:19 -0400 Subject: [PATCH 09/31] don't use unnecessart quantification --- ddcommon-ffi/src/endpoint.rs | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/ddcommon-ffi/src/endpoint.rs b/ddcommon-ffi/src/endpoint.rs index 34d317ed9..6477e23d2 100644 --- a/ddcommon-ffi/src/endpoint.rs +++ b/ddcommon-ffi/src/endpoint.rs @@ -9,10 +9,10 @@ use std::str::FromStr; #[no_mangle] #[must_use] -pub extern "C" fn ddog_endpoint_from_url(url: crate::CharSlice) -> Option> { +pub extern "C" fn ddog_endpoint_from_url(url: crate::CharSlice) -> Option> { parse_uri(url.to_utf8_lossy().as_ref()) .ok() - .map(|url| Box::new(ddcommon::Endpoint::from_url(url))) + .map(|url| Box::new(Endpoint::from_url(url))) } #[no_mangle] @@ -26,10 +26,10 @@ pub extern "C" fn ddog_endpoint_from_filename(filename: crate::CharSlice) -> Opt // own subdomains. #[no_mangle] #[must_use] -pub extern "C" fn ddog_endpoint_from_api_key(api_key: crate::CharSlice) -> Box { +pub extern "C" fn ddog_endpoint_from_api_key(api_key: crate::CharSlice) -> Box { let mut parts = Parts::default(); parts.authority = Some(Authority::from_static("datadoghq.com")); - Box::new(ddcommon::Endpoint { + Box::new(Endpoint { url: hyper::Uri::from_parts(parts).unwrap(), api_key: Some(api_key.to_utf8_lossy().to_string().into()), ..Default::default() @@ -43,14 +43,14 @@ pub extern "C" fn ddog_endpoint_from_api_key(api_key: crate::CharSlice) -> Box Option> { let mut parts = Parts::default(); parts.authority = Some(match Authority::from_str(&site.to_utf8_lossy()) { Ok(s) => s, Err(e) => return Some(Box::new(Error::from(e.to_string()))), }); - *endpoint = Box::into_raw(Box::new(ddcommon::Endpoint { + *endpoint = Box::into_raw(Box::new(Endpoint { url: hyper::Uri::from_parts(parts).unwrap(), api_key: Some(api_key.to_utf8_lossy().to_string().into()), ..Default::default() @@ -59,12 +59,12 @@ pub extern "C" fn ddog_endpoint_from_api_key_and_site( } #[no_mangle] -extern "C" fn ddog_endpoint_set_timeout(endpoint: &mut ddcommon::Endpoint, millis: u64) { +extern "C" fn ddog_endpoint_set_timeout(endpoint: &mut Endpoint, millis: u64) { endpoint.timeout_ms = millis; } #[no_mangle] -pub extern "C" fn ddog_endpoint_drop(_: Box) {} +pub extern "C" fn ddog_endpoint_drop(_: Box) {} #[cfg(test)] mod tests { @@ -96,17 +96,14 @@ mod tests { let mut endpoint = ddog_endpoint_from_url(url); assert_eq!( endpoint.as_ref().unwrap().timeout_ms, - ddcommon::Endpoint::DEFAULT_TIMEOUT + Endpoint::DEFAULT_TIMEOUT ); ddog_endpoint_set_timeout(endpoint.as_mut().unwrap(), 2000); assert_eq!(endpoint.unwrap().timeout_ms, 2000); let mut endpoint_api_key = ddog_endpoint_from_api_key(CharSlice::from("test-key")); - assert_eq!( - endpoint_api_key.timeout_ms, - ddcommon::Endpoint::DEFAULT_TIMEOUT - ); + assert_eq!(endpoint_api_key.timeout_ms, Endpoint::DEFAULT_TIMEOUT); ddog_endpoint_set_timeout(&mut endpoint_api_key, 2000); assert_eq!(endpoint_api_key.timeout_ms, 2000); From 6a42ab9259d477ef501af7a3837cfcdf475b3c23 Mon Sep 17 00:00:00 2001 From: Daniel Schwartz-Narbonne Date: Mon, 29 Jul 2024 12:49:58 -0400 Subject: [PATCH 10/31] fix doctest --- crashtracker-ffi/src/collector/mod.rs | 34 +++++++++++++-------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/crashtracker-ffi/src/collector/mod.rs b/crashtracker-ffi/src/collector/mod.rs index b8fbd84b5..bbc00ed2d 100644 --- a/crashtracker-ffi/src/collector/mod.rs +++ b/crashtracker-ffi/src/collector/mod.rs @@ -20,14 +20,14 @@ pub use spans::*; /// exit. /// /// # Preconditions -/// This function assumes that the crash-tracker has previously been -/// initialized. +/// This function assumes that the crash-tracker has previously been +/// initialized. /// # Safety -/// Crash-tracking functions are not reentrant. -/// No other crash-handler functions should be called concurrently. +/// Crash-tracking functions are not reentrant. +/// No other crash-handler functions should be called concurrently. /// # Atomicity -/// This function is not atomic. A crash during its execution may lead to -/// unexpected crash-handling behaviour. +/// This function is not atomic. A crash during its execution may lead to +/// unexpected crash-handling behaviour. pub unsafe extern "C" fn ddog_crashtracker_shutdown() -> Result { datadog_crashtracker::shutdown_crash_handler() .context("ddog_crashtracker_shutdown failed") @@ -46,14 +46,14 @@ pub unsafe extern "C" fn ddog_crashtracker_shutdown() -> Result { /// advantage would be to have fewer processes in `ps -a`. /// /// # Preconditions -/// This function assumes that the crash-tracker has previously been -/// initialized. +/// This function assumes that the crash-tracker has previously been +/// initialized. /// # Safety -/// Crash-tracking functions are not reentrant. -/// No other crash-handler functions should be called concurrently. +/// Crash-tracking functions are not reentrant. +/// No other crash-handler functions should be called concurrently. /// # Atomicity -/// This function is not atomic. A crash during its execution may lead to -/// unexpected crash-handling behaviour. +/// This function is not atomic. A crash during its execution may lead to +/// unexpected crash-handling behaviour. pub unsafe extern "C" fn ddog_crashtracker_update_on_fork( config: Configuration, receiver_config: ReceiverConfig, @@ -74,13 +74,13 @@ pub unsafe extern "C" fn ddog_crashtracker_update_on_fork( /// Initialize the crash-tracking infrastructure. /// /// # Preconditions -/// None. +/// None. /// # Safety -/// Crash-tracking functions are not reentrant. -/// No other crash-handler functions should be called concurrently. +/// Crash-tracking functions are not reentrant. +/// No other crash-handler functions should be called concurrently. /// # Atomicity -/// This function is not atomic. A crash during its execution may lead to -/// unexpected crash-handling behaviour. +/// This function is not atomic. A crash during its execution may lead to +/// unexpected crash-handling behaviour. pub unsafe extern "C" fn ddog_crashtracker_init_with_receiver( config: Configuration, receiver_config: ReceiverConfig, From 4e9056ab60fa751607cf2a66b53acad9f6f603a4 Mon Sep 17 00:00:00 2001 From: Daniel Schwartz-Narbonne Date: Wed, 31 Jul 2024 14:28:43 -0400 Subject: [PATCH 11/31] Update crashtracker-ffi/src/collector/mod.rs Co-authored-by: Ivo Anjo --- crashtracker-ffi/src/collector/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crashtracker-ffi/src/collector/mod.rs b/crashtracker-ffi/src/collector/mod.rs index bbc00ed2d..ccb2fcaf3 100644 --- a/crashtracker-ffi/src/collector/mod.rs +++ b/crashtracker-ffi/src/collector/mod.rs @@ -20,7 +20,7 @@ pub use spans::*; /// exit. /// /// # Preconditions -/// This function assumes that the crash-tracker has previously been +/// This function assumes that the crashtracker has previously been /// initialized. /// # Safety /// Crash-tracking functions are not reentrant. From 41e081c7e5ef0f9c94788730d885821d4c18e3fe Mon Sep 17 00:00:00 2001 From: Duncan Harvey <35278470+duncanpharvey@users.noreply.github.com> Date: Wed, 31 Jul 2024 07:43:25 -0400 Subject: [PATCH 12/31] [Serverless Mini Agent] Add _dd.mini_agent_version tag to all spans for Azure Functions, Google Cloud Functions, and Azure Spring Apps (#548) * add _dd.mini_agent_version to spans in all environments * apply formatting --- Cargo.lock | 2 +- serverless/src/main.rs | 5 ++++- trace-mini-agent/Cargo.toml | 6 ++++-- trace-mini-agent/src/config.rs | 4 ---- trace-mini-agent/src/env_verifier.rs | 2 ++ trace-mini-agent/src/trace_processor.rs | 6 +----- trace-utils/src/trace_utils.rs | 23 ++++++++++++++++++++--- 7 files changed, 32 insertions(+), 16 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index cc2019a54..bc4b660bd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1571,7 +1571,7 @@ dependencies = [ [[package]] name = "datadog-trace-mini-agent" -version = "0.5.0" +version = "11.0.0" dependencies = [ "anyhow", "async-trait", diff --git a/serverless/src/main.rs b/serverless/src/main.rs index 483370a47..b0b5acfe8 100644 --- a/serverless/src/main.rs +++ b/serverless/src/main.rs @@ -3,7 +3,7 @@ use env_logger::{Builder, Env, Target}; use log::{error, info}; -use std::sync::Arc; +use std::{env, sync::Arc}; use datadog_trace_mini_agent::{ config, env_verifier, mini_agent, stats_flusher, stats_processor, trace_flusher, @@ -16,6 +16,9 @@ pub fn main() { info!("Starting serverless trace mini agent"); + let mini_agent_version = env!("CARGO_PKG_VERSION").to_string(); + env::set_var("DD_MINI_AGENT_VERSION", mini_agent_version); + let env_verifier = Arc::new(env_verifier::ServerlessEnvVerifier::default()); let trace_flusher = Arc::new(trace_flusher::ServerlessTraceFlusher {}); diff --git a/trace-mini-agent/Cargo.toml b/trace-mini-agent/Cargo.toml index dc94b626d..483e2301c 100644 --- a/trace-mini-agent/Cargo.toml +++ b/trace-mini-agent/Cargo.toml @@ -1,8 +1,10 @@ [package] name = "datadog-trace-mini-agent" description = "A subset of the trace agent that is shipped alongside tracers in a few serverless use cases (Google Cloud Functions and Azure Functions)" -version = "0.5.0" -edition = "2021" +edition.workspace = true +version.workspace = true +rust-version.workspace = true +license.workspace = true autobenches = false [lib] diff --git a/trace-mini-agent/src/config.rs b/trace-mini-agent/src/config.rs index 647bea804..418c6495a 100644 --- a/trace-mini-agent/src/config.rs +++ b/trace-mini-agent/src/config.rs @@ -19,7 +19,6 @@ pub struct Config { pub env_type: trace_utils::EnvironmentType, pub function_name: Option, pub max_request_content_length: usize, - pub mini_agent_version: String, pub obfuscation_config: obfuscation_config::ObfuscationConfig, pub os: String, /// how often to flush stats, in seconds @@ -62,8 +61,6 @@ impl Config { ) })?; - let mini_agent_version: String = env!("CARGO_PKG_VERSION").to_string(); - Ok(Config { function_name: Some(function_name), env_type, @@ -84,7 +81,6 @@ impl Config { ..Default::default() }, obfuscation_config, - mini_agent_version, }) } } diff --git a/trace-mini-agent/src/env_verifier.rs b/trace-mini-agent/src/env_verifier.rs index 8363d224f..4cd2fc17c 100644 --- a/trace-mini-agent/src/env_verifier.rs +++ b/trace-mini-agent/src/env_verifier.rs @@ -117,6 +117,7 @@ impl ServerlessEnvVerifier { gcp_region: Some(get_region_from_gcp_region_string( gcp_metadata.instance.region, )), + version: trace_utils::MiniAgentMetadata::default().version, } } } @@ -466,6 +467,7 @@ mod tests { trace_utils::MiniAgentMetadata { gcp_project_id: Some("unknown".to_string()), gcp_region: Some("unknown".to_string()), + version: None } ); } diff --git a/trace-mini-agent/src/trace_processor.rs b/trace-mini-agent/src/trace_processor.rs index 5ec036480..feae500f9 100644 --- a/trace-mini-agent/src/trace_processor.rs +++ b/trace-mini-agent/src/trace_processor.rs @@ -47,10 +47,7 @@ impl TraceChunkProcessor for ChunkProcessor { ); for span in chunk.spans.iter_mut() { trace_utils::enrich_span_with_mini_agent_metadata(span, &self.mini_agent_metadata); - trace_utils::enrich_span_with_azure_metadata( - span, - self.config.mini_agent_version.as_str(), - ); + trace_utils::enrich_span_with_azure_metadata(span); obfuscate_span(span, &self.config.obfuscation_config); } } @@ -174,7 +171,6 @@ mod tests { env_type: trace_utils::EnvironmentType::CloudFunction, os: "linux".to_string(), obfuscation_config: ObfuscationConfig::new().unwrap(), - mini_agent_version: "0.1.0".to_string(), } } diff --git a/trace-utils/src/trace_utils.rs b/trace-utils/src/trace_utils.rs index 14806c33a..294620853 100644 --- a/trace-utils/src/trace_utils.rs +++ b/trace-utils/src/trace_utils.rs @@ -10,6 +10,7 @@ use rmpv::decode::read_value; use rmpv::{Integer, Value}; use std::cmp::Ordering; use std::collections::{HashMap, HashSet}; +use std::env; pub use crate::send_data::send_data_result::SendDataResult; pub use crate::send_data::SendData; @@ -453,10 +454,21 @@ pub enum EnvironmentType { LambdaFunction, } -#[derive(Clone, Default, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq)] pub struct MiniAgentMetadata { pub gcp_project_id: Option, pub gcp_region: Option, + pub version: Option, +} + +impl Default for MiniAgentMetadata { + fn default() -> Self { + MiniAgentMetadata { + gcp_project_id: Default::default(), + gcp_region: Default::default(), + version: env::var("DD_MINI_AGENT_VERSION").ok(), + } + } } pub fn enrich_span_with_mini_agent_metadata( @@ -471,9 +483,15 @@ pub fn enrich_span_with_mini_agent_metadata( span.meta .insert("location".to_string(), gcp_region.to_string()); } + if let Some(mini_agent_version) = &mini_agent_metadata.version { + span.meta.insert( + "_dd.mini_agent_version".to_string(), + mini_agent_version.to_string(), + ); + } } -pub fn enrich_span_with_azure_metadata(span: &mut pb::Span, mini_agent_version: &str) { +pub fn enrich_span_with_azure_metadata(span: &mut pb::Span) { if let Some(aas_metadata) = azure_app_services::get_function_metadata() { let aas_tags = [ ("aas.resource.id", aas_metadata.get_resource_id()), @@ -486,7 +504,6 @@ pub fn enrich_span_with_azure_metadata(span: &mut pb::Span, mini_agent_version: aas_metadata.get_instance_name(), ), ("aas.subscription.id", aas_metadata.get_subscription_id()), - ("aas.environment.mini_agent_version", mini_agent_version), ("aas.environment.os", aas_metadata.get_operating_system()), ("aas.environment.runtime", aas_metadata.get_runtime()), ( From 78f337fc45c14c3a3a7b25891b239e6913ff10dc Mon Sep 17 00:00:00 2001 From: Duncan Harvey <35278470+duncanpharvey@users.noreply.github.com> Date: Wed, 31 Jul 2024 08:24:08 -0400 Subject: [PATCH 13/31] [Serverless Mini Agent] Run in Azure Spring Apps (#547) * add azure spring app environment type for serverless mini agent * add config.statsd_port to mini agent info endpoint * update mini agent trace endpoint status code and response body to work with java tracer * use different environment variable to identify azure spring apps * only update http response for success responses to traces endpoint * address lint errors * updates comment and formatting * update trace-mini-agent description to include Azure Spring Apps * fix formatting --- trace-mini-agent/Cargo.toml | 2 +- trace-mini-agent/src/env_verifier.rs | 3 +++ trace-mini-agent/src/http_utils.rs | 20 ++++++++++++++++++++ trace-mini-agent/src/mini_agent.rs | 3 +++ trace-mini-agent/src/trace_processor.rs | 6 +++--- trace-utils/src/config_utils.rs | 4 ++++ trace-utils/src/trace_utils.rs | 2 ++ 7 files changed, 36 insertions(+), 4 deletions(-) diff --git a/trace-mini-agent/Cargo.toml b/trace-mini-agent/Cargo.toml index 483e2301c..1ffc2bb1c 100644 --- a/trace-mini-agent/Cargo.toml +++ b/trace-mini-agent/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "datadog-trace-mini-agent" -description = "A subset of the trace agent that is shipped alongside tracers in a few serverless use cases (Google Cloud Functions and Azure Functions)" +description = "A subset of the trace agent that is shipped alongside tracers in a few serverless use cases (Google Cloud Functions, Azure Functions, and Azure Spring Apps)" edition.workspace = true version.workspace = true rust-version.workspace = true diff --git a/trace-mini-agent/src/env_verifier.rs b/trace-mini-agent/src/env_verifier.rs index 4cd2fc17c..3400006aa 100644 --- a/trace-mini-agent/src/env_verifier.rs +++ b/trace-mini-agent/src/env_verifier.rs @@ -140,6 +140,9 @@ impl EnvVerifier for ServerlessEnvVerifier { .verify_gcp_environment_or_exit(verify_env_timeout) .await; } + trace_utils::EnvironmentType::AzureSpringApp => { + trace_utils::MiniAgentMetadata::default() + } trace_utils::EnvironmentType::LambdaFunction => { trace_utils::MiniAgentMetadata::default() } diff --git a/trace-mini-agent/src/http_utils.rs b/trace-mini-agent/src/http_utils.rs index d2afb1672..523736d63 100644 --- a/trace-mini-agent/src/http_utils.rs +++ b/trace-mini-agent/src/http_utils.rs @@ -31,6 +31,26 @@ pub fn log_and_create_http_response( Response::builder().status(status).body(Body::from(body)) } +/// Does two things: +/// 1. Logs the given message +/// 2. Returns the rate_by_service map to use to set the sampling priority in the body of JSON +/// response with the given status code. +/// +/// Response body format: +/// { +/// "rate_by_service": { +/// "service:,env:":1 +/// } +/// } +pub fn log_and_create_traces_success_http_response( + message: &str, + status: StatusCode, +) -> http::Result> { + info!("{message}"); + let body = json!({"rate_by_service":{"service:,env:":1}}).to_string(); + Response::builder().status(status).body(Body::from(body)) +} + /// Takes a request's header map, and verifies that the "content-length" header is present, valid, /// and less than the given max_content_length. /// diff --git a/trace-mini-agent/src/mini_agent.rs b/trace-mini-agent/src/mini_agent.rs index e42103bd1..e62b53c30 100644 --- a/trace-mini-agent/src/mini_agent.rs +++ b/trace-mini-agent/src/mini_agent.rs @@ -192,6 +192,9 @@ impl MiniAgent { INFO_ENDPOINT_PATH ], "client_drop_p0s": true, + "config": { + "statsd_port": MINI_AGENT_PORT + } } ); Response::builder() diff --git a/trace-mini-agent/src/trace_processor.rs b/trace-mini-agent/src/trace_processor.rs index feae500f9..be1fafb2b 100644 --- a/trace-mini-agent/src/trace_processor.rs +++ b/trace-mini-agent/src/trace_processor.rs @@ -17,7 +17,7 @@ use datadog_trace_utils::tracer_payload::TraceEncoding; use crate::{ config::Config, - http_utils::{self, log_and_create_http_response}, + http_utils::{self, log_and_create_http_response, log_and_create_traces_success_http_response}, }; #[async_trait] @@ -105,9 +105,9 @@ impl TraceProcessor for ServerlessTraceProcessor { // send trace payload to our trace flusher match tx.send(send_data).await { Ok(_) => { - return log_and_create_http_response( + return log_and_create_traces_success_http_response( "Successfully buffered traces to be flushed.", - StatusCode::ACCEPTED, + StatusCode::OK, ); } Err(err) => { diff --git a/trace-utils/src/config_utils.rs b/trace-utils/src/config_utils.rs index 3095e5800..e071072f1 100644 --- a/trace-utils/src/config_utils.rs +++ b/trace-utils/src/config_utils.rs @@ -25,6 +25,10 @@ pub fn read_cloud_env() -> Option<(String, trace_utils::EnvironmentType)> { // Set by Azure Functions return Some((res, trace_utils::EnvironmentType::AzureFunction)); } + if let Ok(res) = env::var("ASCSVCRT_SPRING__APPLICATION__NAME") { + // Set by Azure Spring Apps + return Some((res, trace_utils::EnvironmentType::AzureSpringApp)); + } None } diff --git a/trace-utils/src/trace_utils.rs b/trace-utils/src/trace_utils.rs index 294620853..72130cb2d 100644 --- a/trace-utils/src/trace_utils.rs +++ b/trace-utils/src/trace_utils.rs @@ -429,6 +429,7 @@ pub fn set_serverless_root_span_tags( let origin_tag = match env_type { EnvironmentType::CloudFunction => "cloudfunction", EnvironmentType::AzureFunction => "azurefunction", + EnvironmentType::AzureSpringApp => "azurespringapp", EnvironmentType::LambdaFunction => "lambda", // historical reasons }; span.meta @@ -451,6 +452,7 @@ fn update_tracer_top_level(span: &mut pb::Span) { pub enum EnvironmentType { CloudFunction, AzureFunction, + AzureSpringApp, LambdaFunction, } From c3548ee882696b96a4aaf814d63aa3d00167d522 Mon Sep 17 00:00:00 2001 From: Duncan Harvey <35278470+duncanpharvey@users.noreply.github.com> Date: Wed, 31 Jul 2024 10:47:40 -0400 Subject: [PATCH 14/31] bump datadog-serverless-trace-mini-agent version to 0.6.0 (#555) --- Cargo.lock | 2 +- serverless/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index bc4b660bd..b1473bf61 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1479,7 +1479,7 @@ dependencies = [ [[package]] name = "datadog-serverless-trace-mini-agent" -version = "0.5.0" +version = "0.6.0" dependencies = [ "datadog-trace-mini-agent", "datadog-trace-protobuf", diff --git a/serverless/Cargo.toml b/serverless/Cargo.toml index 102539afa..bf8ad4410 100644 --- a/serverless/Cargo.toml +++ b/serverless/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "datadog-serverless-trace-mini-agent" -version = "0.5.0" +version = "0.6.0" edition = "2021" [dependencies] From 20067fd559f9b4c0ce6a90dbe66048fdcd70c2ca Mon Sep 17 00:00:00 2001 From: Daniel Schwartz-Narbonne Date: Wed, 31 Jul 2024 12:46:39 -0400 Subject: [PATCH 15/31] rename to datadog-crashtracker-ffi --- Cargo.lock | 32 ++++++++++++++++---------------- crashtracker-ffi/Cargo.toml | 2 +- profiling-ffi/Cargo.toml | 8 ++++---- profiling-ffi/src/lib.rs | 2 +- 4 files changed, 22 insertions(+), 22 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b1473bf61..68b05d642 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1119,21 +1119,6 @@ dependencies = [ "cfg-if", ] -[[package]] -name = "crashtracker-ffi" -version = "11.0.0" -dependencies = [ - "anyhow", - "build_common", - "chrono", - "datadog-crashtracker", - "ddcommon", - "ddcommon-ffi", - "hyper 0.14.28", - "symbolic-common", - "symbolic-demangle", -] - [[package]] name = "crc32fast" version = "1.4.0" @@ -1358,6 +1343,21 @@ dependencies = [ "uuid", ] +[[package]] +name = "datadog-crashtracker-ffi" +version = "11.0.0" +dependencies = [ + "anyhow", + "build_common", + "chrono", + "datadog-crashtracker", + "ddcommon", + "ddcommon-ffi", + "hyper 0.14.28", + "symbolic-common", + "symbolic-demangle", +] + [[package]] name = "datadog-ddsketch" version = "11.0.0" @@ -1450,8 +1450,8 @@ dependencies = [ "anyhow", "build_common", "chrono", - "crashtracker-ffi", "data-pipeline-ffi", + "datadog-crashtracker-ffi", "datadog-profiling", "ddcommon", "ddcommon-ffi", diff --git a/crashtracker-ffi/Cargo.toml b/crashtracker-ffi/Cargo.toml index cfa38f680..1a5c3beb4 100644 --- a/crashtracker-ffi/Cargo.toml +++ b/crashtracker-ffi/Cargo.toml @@ -2,7 +2,7 @@ # SPDX-License-Identifier: Apache-2.0 [package] -name = "crashtracker-ffi" +name = "datadog-crashtracker-ffi" edition.workspace = true version.workspace = true rust-version.workspace = true diff --git a/profiling-ffi/Cargo.toml b/profiling-ffi/Cargo.toml index 33f04f4b3..c617e78e9 100644 --- a/profiling-ffi/Cargo.toml +++ b/profiling-ffi/Cargo.toml @@ -20,11 +20,11 @@ cbindgen = ["build_common/cbindgen", "ddcommon-ffi/cbindgen"] ddtelemetry-ffi = ["dep:ddtelemetry-ffi"] symbolizer = ["symbolizer-ffi"] data-pipeline-ffi = ["dep:data-pipeline-ffi"] -crashtracker-ffi = ["dep:crashtracker-ffi"] +crashtracker-ffi = ["dep:datadog-crashtracker-ffi"] # Enables the in-process collection of crash-info -crashtracker-collector = ["crashtracker-ffi", "crashtracker-ffi/collector"] +crashtracker-collector = ["crashtracker-ffi", "datadog-crashtracker-ffi/collector"] # Enables the use of this library to receiver crash-info from a suitable collector -crashtracker-receiver = ["crashtracker-ffi", "crashtracker-ffi/receiver"] +crashtracker-receiver = ["crashtracker-ffi", "datadog-crashtracker-ffi/receiver"] [build-dependencies] build_common = { path = "../build-common" } @@ -32,7 +32,7 @@ build_common = { path = "../build-common" } [dependencies] anyhow = "1.0" chrono = {version = "0.4", default-features = false } -crashtracker-ffi = { path = "../crashtracker-ffi", default-features = false, optional = true} +datadog-crashtracker-ffi = { path = "../crashtracker-ffi", default-features = false, optional = true} datadog-profiling = { path = "../profiling" } hyper = { version = "0.14", default-features = false } ddcommon = { path = "../ddcommon"} diff --git a/profiling-ffi/src/lib.rs b/profiling-ffi/src/lib.rs index 4f0c35753..edd00cc53 100644 --- a/profiling-ffi/src/lib.rs +++ b/profiling-ffi/src/lib.rs @@ -14,7 +14,7 @@ mod profiles; // re-export crashtracker ffi #[cfg(feature = "crashtracker-ffi")] -pub use crashtracker_ffi::*; +pub use datadog_crashtracker_ffi::*; // re-export telemetry ffi #[cfg(feature = "ddtelemetry-ffi")] From 85a08aee1d1a4392d1bcebae322730227fac14e7 Mon Sep 17 00:00:00 2001 From: Daniel Schwartz-Narbonne Date: Wed, 31 Jul 2024 12:49:53 -0400 Subject: [PATCH 16/31] go with lib for the ffi crate --- crashtracker-ffi/Cargo.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/crashtracker-ffi/Cargo.toml b/crashtracker-ffi/Cargo.toml index 1a5c3beb4..4e7722a62 100644 --- a/crashtracker-ffi/Cargo.toml +++ b/crashtracker-ffi/Cargo.toml @@ -9,7 +9,6 @@ rust-version.workspace = true license.workspace = true [lib] -#FIXME: should this be like profiling-ffi or like ddcommon-ffi? bench =false [features] From b9ee3d506dc343bff8100a3211e6becfa717020a Mon Sep 17 00:00:00 2001 From: Daniel Schwartz-Narbonne Date: Wed, 31 Jul 2024 14:09:51 -0400 Subject: [PATCH 17/31] _crasht_ --- crashtracker-ffi/cbindgen.toml | 2 +- crashtracker-ffi/src/collector/counters.rs | 12 +++--- crashtracker-ffi/src/collector/mod.rs | 12 +++--- crashtracker-ffi/src/collector/spans.rs | 24 +++++------ crashtracker-ffi/src/crash_info/mod.rs | 44 ++++++++++----------- examples/ffi/crashinfo.cpp | 46 +++++++++++----------- examples/ffi/crashtracking.c | 24 +++++------ 7 files changed, 82 insertions(+), 82 deletions(-) diff --git a/crashtracker-ffi/cbindgen.toml b/crashtracker-ffi/cbindgen.toml index 449e66ad9..af0c48eee 100644 --- a/crashtracker-ffi/cbindgen.toml +++ b/crashtracker-ffi/cbindgen.toml @@ -16,7 +16,7 @@ sys_includes = ["stdbool.h", "stddef.h", "stdint.h"] includes = ["common.h"] [export] -prefix = "ddog_crashtracker_" +prefix = "ddog_crasht_" renaming_overrides_prefixing = true [export.rename] diff --git a/crashtracker-ffi/src/collector/counters.rs b/crashtracker-ffi/src/collector/counters.rs index 1469f753c..9d836107a 100644 --- a/crashtracker-ffi/src/collector/counters.rs +++ b/crashtracker-ffi/src/collector/counters.rs @@ -15,9 +15,9 @@ use anyhow::Context; /// No safety concerns. #[no_mangle] #[must_use] -pub unsafe extern "C" fn ddog_crashtracker_reset_counters() -> Result { +pub unsafe extern "C" fn ddog_crasht_reset_counters() -> Result { datadog_crashtracker::reset_counters() - .context("ddog_crashtracker_begin_profiling_op failed") + .context("ddog_crasht_reset_counters failed") .into() } @@ -28,9 +28,9 @@ pub unsafe extern "C" fn ddog_crashtracker_reset_counters() -> Result { /// /// # Safety /// No safety concerns. -pub unsafe extern "C" fn ddog_crashtracker_begin_profiling_op(op: ProfilingOpTypes) -> Result { +pub unsafe extern "C" fn ddog_crasht_begin_profiling_op(op: ProfilingOpTypes) -> Result { datadog_crashtracker::begin_profiling_op(op) - .context("ddog_crashtracker_begin_profiling_op failed") + .context("ddog_crasht_begin_profiling_op failed") .into() } @@ -41,8 +41,8 @@ pub unsafe extern "C" fn ddog_crashtracker_begin_profiling_op(op: ProfilingOpTyp /// /// # Safety /// No safety concerns. -pub unsafe extern "C" fn ddog_crashtracker_end_profiling_op(op: ProfilingOpTypes) -> Result { +pub unsafe extern "C" fn ddog_crasht_end_profiling_op(op: ProfilingOpTypes) -> Result { datadog_crashtracker::end_profiling_op(op) - .context("ddog_crashtracker_end_profiling_op failed") + .context("ddog_crasht_end_profiling_op failed") .into() } diff --git a/crashtracker-ffi/src/collector/mod.rs b/crashtracker-ffi/src/collector/mod.rs index ccb2fcaf3..6d8bc2d5b 100644 --- a/crashtracker-ffi/src/collector/mod.rs +++ b/crashtracker-ffi/src/collector/mod.rs @@ -28,9 +28,9 @@ pub use spans::*; /// # Atomicity /// This function is not atomic. A crash during its execution may lead to /// unexpected crash-handling behaviour. -pub unsafe extern "C" fn ddog_crashtracker_shutdown() -> Result { +pub unsafe extern "C" fn ddog_crasht_shutdown() -> Result { datadog_crashtracker::shutdown_crash_handler() - .context("ddog_crashtracker_shutdown failed") + .context("ddog_crasht_shutdown failed") .into() } @@ -54,7 +54,7 @@ pub unsafe extern "C" fn ddog_crashtracker_shutdown() -> Result { /// # Atomicity /// This function is not atomic. A crash during its execution may lead to /// unexpected crash-handling behaviour. -pub unsafe extern "C" fn ddog_crashtracker_update_on_fork( +pub unsafe extern "C" fn ddog_crasht_update_on_fork( config: Configuration, receiver_config: ReceiverConfig, metadata: Metadata, @@ -65,7 +65,7 @@ pub unsafe extern "C" fn ddog_crashtracker_update_on_fork( let metadata = metadata.try_into()?; datadog_crashtracker::on_fork(config, receiver_config, metadata) })() - .context("ddog_crashtracker_update_on_fork failed") + .context("ddog_crasht_update_on_fork failed") .into() } @@ -81,7 +81,7 @@ pub unsafe extern "C" fn ddog_crashtracker_update_on_fork( /// # Atomicity /// This function is not atomic. A crash during its execution may lead to /// unexpected crash-handling behaviour. -pub unsafe extern "C" fn ddog_crashtracker_init_with_receiver( +pub unsafe extern "C" fn ddog_crasht_init_with_receiver( config: Configuration, receiver_config: ReceiverConfig, metadata: Metadata, @@ -92,6 +92,6 @@ pub unsafe extern "C" fn ddog_crashtracker_init_with_receiver( let metadata = metadata.try_into()?; datadog_crashtracker::init_with_receiver(config, receiver_config, metadata) })() - .context("ddog_crashtracker_init failed") + .context("ddog_crasht_init failed") .into() } diff --git a/crashtracker-ffi/src/collector/spans.rs b/crashtracker-ffi/src/collector/spans.rs index 70cdff34d..5902b7fcb 100644 --- a/crashtracker-ffi/src/collector/spans.rs +++ b/crashtracker-ffi/src/collector/spans.rs @@ -14,9 +14,9 @@ use anyhow::Context; /// No safety concerns. #[no_mangle] #[must_use] -pub unsafe extern "C" fn ddog_crashtracker_clear_span_ids() -> Result { +pub unsafe extern "C" fn ddog_crasht_clear_span_ids() -> Result { datadog_crashtracker::clear_spans() - .context("ddog_crashtracker_clear_span_ids failed") + .context("ddog_crasht_clear_span_ids failed") .into() } @@ -30,9 +30,9 @@ pub unsafe extern "C" fn ddog_crashtracker_clear_span_ids() -> Result { /// No safety concerns. #[no_mangle] #[must_use] -pub unsafe extern "C" fn ddog_crashtracker_clear_trace_ids() -> Result { +pub unsafe extern "C" fn ddog_crasht_clear_trace_ids() -> Result { datadog_crashtracker::clear_traces() - .context("ddog_crashtracker_clear_trace_ids failed") + .context("ddog_crasht_clear_trace_ids failed") .into() } @@ -57,13 +57,13 @@ pub unsafe extern "C" fn ddog_crashtracker_clear_trace_ids() -> Result { /// /// # Safety /// No safety concerns. -pub unsafe extern "C" fn ddog_crashtracker_insert_trace_id( +pub unsafe extern "C" fn ddog_crasht_insert_trace_id( id_high: u64, id_low: u64, ) -> UsizeResult { let id: u128 = (id_high as u128) << 64 | (id_low as u128); datadog_crashtracker::insert_trace(id) - .context("ddog_crashtracker_insert_trace_id failed") + .context("ddog_crasht_insert_trace_id failed") .into() } @@ -89,13 +89,13 @@ pub unsafe extern "C" fn ddog_crashtracker_insert_trace_id( /// /// # Safety /// No safety concerns. -pub unsafe extern "C" fn ddog_crashtracker_insert_span_id( +pub unsafe extern "C" fn ddog_crasht_insert_span_id( id_high: u64, id_low: u64, ) -> UsizeResult { let id: u128 = (id_high as u128) << 64 | (id_low as u128); datadog_crashtracker::insert_span(id) - .context("ddog_crashtracker_insert_span_id failed") + .context("ddog_crasht_insert_span_id failed") .into() } @@ -121,14 +121,14 @@ pub unsafe extern "C" fn ddog_crashtracker_insert_span_id( /// /// # Safety /// No safety concerns. -pub unsafe extern "C" fn ddog_crashtracker_remove_span_id( +pub unsafe extern "C" fn ddog_crasht_remove_span_id( id_high: u64, id_low: u64, idx: usize, ) -> Result { let id: u128 = (id_high as u128) << 64 | (id_low as u128); datadog_crashtracker::remove_span(id, idx) - .context("ddog_crashtracker_remove_span_id failed") + .context("ddog_crasht_remove_span_id failed") .into() } @@ -154,13 +154,13 @@ pub unsafe extern "C" fn ddog_crashtracker_remove_span_id( /// /// # Safety /// No safety concerns. -pub unsafe extern "C" fn ddog_crashtracker_remove_trace_id( +pub unsafe extern "C" fn ddog_crasht_remove_trace_id( id_high: u64, id_low: u64, idx: usize, ) -> Result { let id: u128 = (id_high as u128) << 64 | (id_low as u128); datadog_crashtracker::remove_trace(id, idx) - .context("ddog_crashtracker_remove_trace_id failed") + .context("ddog_crasht_remove_trace_id failed") .into() } diff --git a/crashtracker-ffi/src/crash_info/mod.rs b/crashtracker-ffi/src/crash_info/mod.rs index cbb979b8f..e91c29942 100644 --- a/crashtracker-ffi/src/crash_info/mod.rs +++ b/crashtracker-ffi/src/crash_info/mod.rs @@ -15,7 +15,7 @@ use ddcommon_ffi::{slice::AsBytes, CharSlice, Slice}; /// No safety issues. #[no_mangle] #[must_use] -pub unsafe extern "C" fn ddog_crashinfo_new() -> CrashInfoNewResult { +pub unsafe extern "C" fn ddog_crasht_CrashInfo_new() -> CrashInfoNewResult { CrashInfoNewResult::Ok(CrashInfo::new(datadog_crashtracker::CrashInfo::new())) } @@ -23,7 +23,7 @@ pub unsafe extern "C" fn ddog_crashinfo_new() -> CrashInfoNewResult { /// The `crash_info` can be null, but if non-null it must point to a CrashInfo /// made by this module, which has not previously been dropped. #[no_mangle] -pub unsafe extern "C" fn ddog_crashinfo_drop(crashinfo: *mut CrashInfo) { +pub unsafe extern "C" fn ddog_crasht_CrashInfo_drop(crashinfo: *mut CrashInfo) { // Technically, this function has been designed so if it's double-dropped // then it's okay, but it's not something that should be relied on. if !crashinfo.is_null() { @@ -39,7 +39,7 @@ pub unsafe extern "C" fn ddog_crashinfo_drop(crashinfo: *mut CrashInfo) { #[cfg(unix)] #[no_mangle] #[must_use] -pub unsafe extern "C" fn ddog_crashinfo_normalize_ips( +pub unsafe extern "C" fn ddog_crasht_CrashInfo_normalize_ips( crashinfo: *mut CrashInfo, pid: u32, ) -> Result { @@ -47,7 +47,7 @@ pub unsafe extern "C" fn ddog_crashinfo_normalize_ips( let crashinfo = crashinfo_ptr_to_inner(crashinfo)?; crashinfo.normalize_ips(pid) })() - .context("ddog_crashinfo_normalize_ips failed") + .context("ddog_crasht_CrashInfo_normalize_ips failed") .into() } @@ -61,7 +61,7 @@ pub unsafe extern "C" fn ddog_crashinfo_normalize_ips( /// call. #[no_mangle] #[must_use] -pub unsafe extern "C" fn ddog_crashinfo_add_counter( +pub unsafe extern "C" fn ddog_crasht_CrashInfo_add_counter( crashinfo: *mut CrashInfo, name: CharSlice, val: i64, @@ -71,7 +71,7 @@ pub unsafe extern "C" fn ddog_crashinfo_add_counter( let name = name.to_utf8_lossy(); crashinfo.add_counter(&name, val) })() - .context("ddog_crashinfo_add_counter failed") + .context("ddog_crasht_CrashInfo_add_counter failed") .into() } @@ -84,7 +84,7 @@ pub unsafe extern "C" fn ddog_crashinfo_add_counter( /// call. #[no_mangle] #[must_use] -pub unsafe extern "C" fn ddog_crashinfo_add_file( +pub unsafe extern "C" fn ddog_crasht_CrashInfo_add_file( crashinfo: *mut CrashInfo, name: CharSlice, ) -> Result { @@ -93,7 +93,7 @@ pub unsafe extern "C" fn ddog_crashinfo_add_file( let name = name.to_utf8_lossy(); crashinfo.add_file(&name) })() - .context("ddog_crashinfo_add_file failed") + .context("ddog_crasht_CrashInfo_add_file failed") .into() } @@ -107,7 +107,7 @@ pub unsafe extern "C" fn ddog_crashinfo_add_file( /// call. #[no_mangle] #[must_use] -pub unsafe extern "C" fn ddog_crashinfo_add_tag( +pub unsafe extern "C" fn ddog_crasht_CrashInfo_add_tag( crashinfo: *mut CrashInfo, key: CharSlice, value: CharSlice, @@ -118,7 +118,7 @@ pub unsafe extern "C" fn ddog_crashinfo_add_tag( let value = value.to_utf8_lossy().to_string(); crashinfo.add_tag(key, value) })() - .context("ddog_crashinfo_add_tag failed") + .context("ddog_crasht_CrashInfo_add_tag failed") .into() } @@ -130,7 +130,7 @@ pub unsafe extern "C" fn ddog_crashinfo_add_tag( /// Strings are copied into the crashinfo, and do not need to outlive this call. #[no_mangle] #[must_use] -pub unsafe extern "C" fn ddog_crashinfo_set_metadata( +pub unsafe extern "C" fn ddog_crasht_CrashInfo_set_metadata( crashinfo: *mut CrashInfo, metadata: Metadata, ) -> Result { @@ -139,7 +139,7 @@ pub unsafe extern "C" fn ddog_crashinfo_set_metadata( let metadata = metadata.try_into()?; crashinfo.set_metadata(metadata) })() - .context("ddog_crashinfo_set_metadata failed") + .context("ddog_crasht_CrashInfo_set_metadata failed") .into() } @@ -151,7 +151,7 @@ pub unsafe extern "C" fn ddog_crashinfo_set_metadata( /// Strings are copied into the crashinfo, and do not need to outlive this call. #[no_mangle] #[must_use] -pub unsafe extern "C" fn ddog_crashinfo_set_siginfo( +pub unsafe extern "C" fn ddog_crasht_CrashInfo_set_siginfo( crashinfo: *mut CrashInfo, siginfo: SigInfo, ) -> Result { @@ -160,7 +160,7 @@ pub unsafe extern "C" fn ddog_crashinfo_set_siginfo( let siginfo = siginfo.try_into()?; crashinfo.set_siginfo(siginfo) })() - .context("ddog_crashinfo_set_siginfo failed") + .context("ddog_crasht_CrashInfo_set_siginfo failed") .into() } @@ -173,7 +173,7 @@ pub unsafe extern "C" fn ddog_crashinfo_set_siginfo( /// Strings are copied into the crashinfo, and do not need to outlive this call. #[no_mangle] #[must_use] -pub unsafe extern "C" fn ddog_crashinfo_set_stacktrace( +pub unsafe extern "C" fn ddog_crasht_CrashInfo_set_stacktrace( crashinfo: *mut CrashInfo, thread_id: CharSlice, stacktrace: Slice, @@ -187,7 +187,7 @@ pub unsafe extern "C" fn ddog_crashinfo_set_stacktrace( } crashinfo.set_stacktrace(thread_id, stacktrace_vec) })() - .context("ddog_crashinfo_set_stacktrace failed") + .context("ddog_crasht_CrashInfo_set_stacktrace failed") .into() } @@ -197,7 +197,7 @@ pub unsafe extern "C" fn ddog_crashinfo_set_stacktrace( /// `crashinfo` must be a valid pointer to a `CrashInfo` object. #[no_mangle] #[must_use] -pub unsafe extern "C" fn ddog_crashinfo_set_timestamp( +pub unsafe extern "C" fn ddog_crasht_CrashInfo_set_timestamp( crashinfo: *mut CrashInfo, secs: i64, nsecs: u32, @@ -208,7 +208,7 @@ pub unsafe extern "C" fn ddog_crashinfo_set_timestamp( .with_context(|| format!("Invalid timestamp {secs} {nsecs}"))?; crashinfo.set_timestamp(ts) })() - .context("ddog_crashinfo_set_timestamp_to_now failed") + .context("ddog_crasht_CrashInfo_set_timestamp_to_now failed") .into() } @@ -218,12 +218,12 @@ pub unsafe extern "C" fn ddog_crashinfo_set_timestamp( /// `crashinfo` must be a valid pointer to a `CrashInfo` object. #[no_mangle] #[must_use] -pub unsafe extern "C" fn ddog_crashinfo_set_timestamp_to_now(crashinfo: *mut CrashInfo) -> Result { +pub unsafe extern "C" fn ddog_crasht_CrashInfo_set_timestamp_to_now(crashinfo: *mut CrashInfo) -> Result { (|| { let crashinfo = crashinfo_ptr_to_inner(crashinfo)?; crashinfo.set_timestamp_to_now() })() - .context("ddog_crashinfo_set_timestamp_to_now failed") + .context("ddog_crasht_CrashInfo_set_timestamp_to_now failed") .into() } @@ -233,7 +233,7 @@ pub unsafe extern "C" fn ddog_crashinfo_set_timestamp_to_now(crashinfo: *mut Cra /// `crashinfo` must be a valid pointer to a `CrashInfo` object. #[no_mangle] #[must_use] -pub unsafe extern "C" fn ddog_crashinfo_upload_to_endpoint( +pub unsafe extern "C" fn ddog_crasht_CrashInfo_upload_to_endpoint( crashinfo: *mut CrashInfo, endpoint: Option<&Endpoint>, ) -> Result { @@ -242,6 +242,6 @@ pub unsafe extern "C" fn ddog_crashinfo_upload_to_endpoint( let endpoint = endpoint.cloned(); crashinfo.upload_to_endpoint(&endpoint) })() - .context("ddog_crashinfo_upload_to_endpoint failed") + .context("ddog_crasht_CrashInfo_upload_to_endpoint failed") .into() } diff --git a/examples/ffi/crashinfo.cpp b/examples/ffi/crashinfo.cpp index bea177ce5..099c1172e 100644 --- a/examples/ffi/crashinfo.cpp +++ b/examples/ffi/crashinfo.cpp @@ -21,17 +21,17 @@ static ddog_CharSlice to_slice_string(std::string &s) { // TODO: Testing on my mac, the tags appear to have the opposite meaning you'd // expect -static ddog_crashtracker_Option_U32 some_u32(uint32_t i) { - ddog_crashtracker_Option_U32 rval = {.tag = DDOG_CRASHTRACKER_OPTION_U32_SOME_U32}; +static ddog_crasht_Option_U32 some_u32(uint32_t i) { + ddog_crasht_Option_U32 rval = {.tag = DDOG_CRASHT_OPTION_U32_SOME_U32}; rval.some = i; return rval; } -static ddog_crashtracker_Option_U32 none_u32() { - return {.tag = DDOG_CRASHTRACKER_OPTION_U32_NONE_U32}; +static ddog_crasht_Option_U32 none_u32() { + return {.tag = DDOG_CRASHT_OPTION_U32_NONE_U32}; } struct Deleter { - void operator()(ddog_crashtracker_CrashInfo *object) { ddog_crashinfo_drop(object); } + void operator()(ddog_crasht_CrashInfo *object) { ddog_crasht_CrashInfo_drop(object); } }; void print_error(const char *s, const ddog_Error &err) { @@ -39,15 +39,15 @@ void print_error(const char *s, const ddog_Error &err) { printf("%s (%.*s)\n", s, static_cast(charslice.len), charslice.ptr); } -void check_result(ddog_crashtracker_Result result, const char *msg) { - if (result.tag != DDOG_CRASHTRACKER_RESULT_OK) { +void check_result(ddog_crasht_Result result, const char *msg) { + if (result.tag != DDOG_CRASHT_RESULT_OK) { print_error(msg, result.err); ddog_Error_drop(&result.err); exit(EXIT_FAILURE); } } -void add_stacktrace(std::unique_ptr &crashinfo) { +void add_stacktrace(std::unique_ptr &crashinfo) { // Collect things into vectors so they stay alive till the function exits std::vector filenames; @@ -57,7 +57,7 @@ void add_stacktrace(std::unique_ptr &crash function_names.push_back("func_" + std::to_string(i)); } - std::vector names; + std::vector names; for (uintptr_t i = 0; i < 20; ++i) { names.push_back({.colno = some_u32(i), .filename = to_slice_string(filenames[i]), @@ -65,37 +65,37 @@ void add_stacktrace(std::unique_ptr &crash .name = to_slice_string(function_names[i])}); } - std::vector trace; + std::vector trace; for (uintptr_t i = 0; i < 20; ++i) { - ddog_crashtracker_StackFrame frame = {.ip = i, + ddog_crasht_StackFrame frame = {.ip = i, .module_base_address = 0, .names = {.ptr = &names[i], .len = 1}, .sp = 0, .symbol_address = 0}; trace.push_back(frame); } - ddog_crashtracker_Slice_StackFrame trace_slice = {.ptr = trace.data(), .len = trace.size()}; + ddog_crasht_Slice_StackFrame trace_slice = {.ptr = trace.data(), .len = trace.size()}; - check_result(ddog_crashinfo_set_stacktrace(crashinfo.get(), to_slice_c_char(""), trace_slice), + check_result(ddog_crasht_CrashInfo_set_stacktrace(crashinfo.get(), to_slice_c_char(""), trace_slice), "Failed to set stacktrace"); } int main(void) { - auto crashinfo_new_result = ddog_crashinfo_new(); - if (crashinfo_new_result.tag != DDOG_CRASHTRACKER_CRASH_INFO_NEW_RESULT_OK) { + auto crashinfo_new_result = ddog_crasht_CrashInfo_new(); + if (crashinfo_new_result.tag != DDOG_CRASHT_CRASH_INFO_NEW_RESULT_OK) { print_error("Failed to make new crashinfo: ", crashinfo_new_result.err); ddog_Error_drop(&crashinfo_new_result.err); exit(EXIT_FAILURE); } - std::unique_ptr crashinfo{&crashinfo_new_result.ok}; + std::unique_ptr crashinfo{&crashinfo_new_result.ok}; check_result( - ddog_crashinfo_add_counter(crashinfo.get(), to_slice_c_char("my_amazing_counter"), 3), + ddog_crasht_CrashInfo_add_counter(crashinfo.get(), to_slice_c_char("my_amazing_counter"), 3), "Failed to add counter"); // TODO add some tags here auto tags = ddog_Vec_Tag_new(); - const ddog_crashtracker_Metadata metadata = { + const ddog_crasht_Metadata metadata = { .profiling_library_name = to_slice_c_char("libdatadog"), .profiling_library_version = to_slice_c_char("42"), .family = to_slice_c_char("rust"), @@ -103,26 +103,26 @@ int main(void) { }; // TODO: We should set more tags that are expected by telemetry - check_result(ddog_crashinfo_set_metadata(crashinfo.get(), metadata), "Failed to add metadata"); - check_result(ddog_crashinfo_add_tag(crashinfo.get(), to_slice_c_char("best hockey team"), + check_result(ddog_crasht_CrashInfo_set_metadata(crashinfo.get(), metadata), "Failed to add metadata"); + check_result(ddog_crasht_CrashInfo_add_tag(crashinfo.get(), to_slice_c_char("best hockey team"), to_slice_c_char("Habs")), "Failed to add tag"); // This API allows one to capture useful files (e.g. /proc/pid/maps) // For testing purposes, use `/etc/hosts` which should exist on any reasonable // UNIX system - check_result(ddog_crashinfo_add_file(crashinfo.get(), to_slice_c_char("/etc/hosts")), + check_result(ddog_crasht_CrashInfo_add_file(crashinfo.get(), to_slice_c_char("/etc/hosts")), "Failed to add file"); add_stacktrace(crashinfo); // Datadog IPO at 2019-09-19T13:30:00Z = 1568899800 unix - check_result(ddog_crashinfo_set_timestamp(crashinfo.get(), 1568899800, 0), + check_result(ddog_crasht_CrashInfo_set_timestamp(crashinfo.get(), 1568899800, 0), "Failed to set timestamp"); auto endpoint = ddog_endpoint_from_filename(to_slice_c_char("/tmp/test")); - check_result(ddog_crashinfo_upload_to_endpoint(crashinfo.get(), endpoint), + check_result(ddog_crasht_CrashInfo_upload_to_endpoint(crashinfo.get(), endpoint), "Failed to export to file"); ddog_endpoint_drop(endpoint); } diff --git a/examples/ffi/crashtracking.c b/examples/ffi/crashtracking.c index 6f7f7f51b..397bb7829 100644 --- a/examples/ffi/crashtracking.c +++ b/examples/ffi/crashtracking.c @@ -12,8 +12,8 @@ void example_segfault_handler(int signal) { exit(-1); } -void handle_result(ddog_crashtracker_Result result) { - if (result.tag == DDOG_CRASHTRACKER_RESULT_ERR) { +void handle_result(ddog_crasht_Result result) { + if (result.tag == DDOG_CRASHT_RESULT_ERR) { ddog_CharSlice message = ddog_Error_message(&result.err); fprintf(stderr, "%.*s\n", (int)message.len, message.ptr); ddog_Error_drop(&result.err); @@ -21,8 +21,8 @@ void handle_result(ddog_crashtracker_Result result) { } } -uintptr_t handle_uintptr_t_result(ddog_crashtracker_UsizeResult result) { - if (result.tag == DDOG_CRASHTRACKER_USIZE_RESULT_ERR) { +uintptr_t handle_uintptr_t_result(ddog_crasht_UsizeResult result) { + if (result.tag == DDOG_CRASHT_USIZE_RESULT_ERR) { ddog_CharSlice message = ddog_Error_message(&result.err); fprintf(stderr, "%.*s\n", (int)message.len, message.ptr); ddog_Error_drop(&result.err); @@ -37,7 +37,7 @@ int main(int argc, char **argv) { return -1; } - ddog_crashtracker_ReceiverConfig receiver_config = { + ddog_crasht_ReceiverConfig receiver_config = { .args = {}, .env = {}, .path_to_receiver_binary = DDOG_CHARSLICE_C("SET ME TO THE ACTUAL PATH ON YOUR MACHINE"), @@ -55,26 +55,26 @@ int main(int argc, char **argv) { // struct ddog_Endpoint * endpoint = // ddog_endpoint_from_url(DDOG_CHARSLICE_C("http://localhost:8126")); - ddog_crashtracker_Configuration config = { + ddog_crasht_Configuration config = { .create_alt_stack = false, .endpoint = endpoint, - .resolve_frames = DDOG_CRASHTRACKER_STACKTRACE_COLLECTION_ENABLED_WITH_INPROCESS_SYMBOLS, + .resolve_frames = DDOG_CRASHT_STACKTRACE_COLLECTION_ENABLED_WITH_INPROCESS_SYMBOLS, }; - ddog_crashtracker_Metadata metadata = { + ddog_crasht_Metadata metadata = { .profiling_library_name = DDOG_CHARSLICE_C("crashtracking-test"), .profiling_library_version = DDOG_CHARSLICE_C("12.34.56"), .family = DDOG_CHARSLICE_C("crashtracking-test"), .tags = NULL, }; - handle_result(ddog_crashtracker_init_with_receiver(config, receiver_config, metadata)); + handle_result(ddog_crasht_init_with_receiver(config, receiver_config, metadata)); ddog_endpoint_drop(endpoint); handle_result( - ddog_crashtracker_begin_profiling_op(DDOG_CRASHTRACKER_PROFILING_OP_TYPES_SERIALIZING)); - handle_uintptr_t_result(ddog_crashtracker_insert_span_id(0, 42)); - handle_uintptr_t_result(ddog_crashtracker_insert_trace_id(1, 1)); + ddog_crasht_begin_profiling_op(DDOG_CRASHT_PROFILING_OP_TYPES_SERIALIZING)); + handle_uintptr_t_result(ddog_crasht_insert_span_id(0, 42)); + handle_uintptr_t_result(ddog_crasht_insert_trace_id(1, 1)); #ifdef EXPLICIT_RAISE_SEGV // Test raising SEGV explicitly, to ensure chaining works From 7506a744677d6f5faf0ff621819cb8a840802916 Mon Sep 17 00:00:00 2001 From: Daniel Schwartz-Narbonne Date: Wed, 31 Jul 2024 14:25:37 -0400 Subject: [PATCH 18/31] _crasht_ --- crashtracker-ffi/src/receiver.rs | 8 ++++---- crashtracker/libdatadog-crashtracking-receiver.c | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/crashtracker-ffi/src/receiver.rs b/crashtracker-ffi/src/receiver.rs index 05bbda078..d7f64f65d 100644 --- a/crashtracker-ffi/src/receiver.rs +++ b/crashtracker-ffi/src/receiver.rs @@ -17,9 +17,9 @@ use ddcommon_ffi::{slice::AsBytes, CharSlice}; /// description. /// # Safety /// No safety concerns -pub unsafe extern "C" fn ddog_crashtracker_receiver_entry_point_stdin() -> Result { +pub unsafe extern "C" fn ddog_crasht_receiver_entry_point_stdin() -> Result { datadog_crashtracker::receiver_entry_point_stdin() - .context("ddog_crashtracker_receiver_entry_point_stdin failed") + .context("ddog_crasht_receiver_entry_point_stdin failed") .into() } @@ -36,13 +36,13 @@ pub unsafe extern "C" fn ddog_crashtracker_receiver_entry_point_stdin() -> Resul /// description. /// # Safety /// No safety concerns -pub unsafe extern "C" fn ddog_crashtracker_receiver_entry_point_unix_socket( +pub unsafe extern "C" fn ddog_crasht_receiver_entry_point_unix_socket( socket_path: CharSlice, ) -> Result { (|| { let socket_path = socket_path.try_to_utf8()?; datadog_crashtracker::reciever_entry_point_unix_socket(socket_path) })() - .context("ddog_crashtracker_receiver_entry_point_unix_socket failed") + .context("ddog_crasht_receiver_entry_point_unix_socket failed") .into() } diff --git a/crashtracker/libdatadog-crashtracking-receiver.c b/crashtracker/libdatadog-crashtracking-receiver.c index 506da967e..c8e3e265f 100644 --- a/crashtracker/libdatadog-crashtracking-receiver.c +++ b/crashtracker/libdatadog-crashtracking-receiver.c @@ -7,8 +7,8 @@ #include int main(void) { - ddog_crashtracker_Result new_result = ddog_crashtracker_receiver_entry_point_stdin(); - if (new_result.tag != DDOG_CRASHTRACKER_RESULT_OK) { + ddog_crasht_Result new_result = ddog_crasht_receiver_entry_point_stdin(); + if (new_result.tag != DDOG_CRASHT_RESULT_OK) { ddog_CharSlice message = ddog_Error_message(&new_result.err); fprintf(stderr, "%.*s", (int)message.len, message.ptr); ddog_Error_drop(&new_result.err); From 48de74020a5e2c2f49f6817bbe98e789578555cd Mon Sep 17 00:00:00 2001 From: Daniel Schwartz-Narbonne Date: Wed, 31 Jul 2024 14:29:04 -0400 Subject: [PATCH 19/31] function name --- crashtracker-ffi/src/collector/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crashtracker-ffi/src/collector/mod.rs b/crashtracker-ffi/src/collector/mod.rs index 6d8bc2d5b..8e9a37a09 100644 --- a/crashtracker-ffi/src/collector/mod.rs +++ b/crashtracker-ffi/src/collector/mod.rs @@ -92,6 +92,6 @@ pub unsafe extern "C" fn ddog_crasht_init_with_receiver( let metadata = metadata.try_into()?; datadog_crashtracker::init_with_receiver(config, receiver_config, metadata) })() - .context("ddog_crasht_init failed") + .context("ddog_crasht_init_with_receiver failed") .into() } From ae8798e8090530cef37942a436efc1bfd42aaeee Mon Sep 17 00:00:00 2001 From: Daniel Schwartz-Narbonne Date: Wed, 31 Jul 2024 15:05:04 -0400 Subject: [PATCH 20/31] format --- crashtracker-ffi/src/collector/spans.rs | 10 ++-------- crashtracker-ffi/src/crash_info/mod.rs | 4 +++- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/crashtracker-ffi/src/collector/spans.rs b/crashtracker-ffi/src/collector/spans.rs index 5902b7fcb..de9efacaa 100644 --- a/crashtracker-ffi/src/collector/spans.rs +++ b/crashtracker-ffi/src/collector/spans.rs @@ -57,10 +57,7 @@ pub unsafe extern "C" fn ddog_crasht_clear_trace_ids() -> Result { /// /// # Safety /// No safety concerns. -pub unsafe extern "C" fn ddog_crasht_insert_trace_id( - id_high: u64, - id_low: u64, -) -> UsizeResult { +pub unsafe extern "C" fn ddog_crasht_insert_trace_id(id_high: u64, id_low: u64) -> UsizeResult { let id: u128 = (id_high as u128) << 64 | (id_low as u128); datadog_crashtracker::insert_trace(id) .context("ddog_crasht_insert_trace_id failed") @@ -89,10 +86,7 @@ pub unsafe extern "C" fn ddog_crasht_insert_trace_id( /// /// # Safety /// No safety concerns. -pub unsafe extern "C" fn ddog_crasht_insert_span_id( - id_high: u64, - id_low: u64, -) -> UsizeResult { +pub unsafe extern "C" fn ddog_crasht_insert_span_id(id_high: u64, id_low: u64) -> UsizeResult { let id: u128 = (id_high as u128) << 64 | (id_low as u128); datadog_crashtracker::insert_span(id) .context("ddog_crasht_insert_span_id failed") diff --git a/crashtracker-ffi/src/crash_info/mod.rs b/crashtracker-ffi/src/crash_info/mod.rs index e91c29942..e324d46c4 100644 --- a/crashtracker-ffi/src/crash_info/mod.rs +++ b/crashtracker-ffi/src/crash_info/mod.rs @@ -218,7 +218,9 @@ pub unsafe extern "C" fn ddog_crasht_CrashInfo_set_timestamp( /// `crashinfo` must be a valid pointer to a `CrashInfo` object. #[no_mangle] #[must_use] -pub unsafe extern "C" fn ddog_crasht_CrashInfo_set_timestamp_to_now(crashinfo: *mut CrashInfo) -> Result { +pub unsafe extern "C" fn ddog_crasht_CrashInfo_set_timestamp_to_now( + crashinfo: *mut CrashInfo, +) -> Result { (|| { let crashinfo = crashinfo_ptr_to_inner(crashinfo)?; crashinfo.set_timestamp_to_now() From f2ecfa2e749ce70c5018e976b52d36f8f5a6b655 Mon Sep 17 00:00:00 2001 From: Daniel Schwartz-Narbonne Date: Wed, 31 Jul 2024 15:46:35 -0400 Subject: [PATCH 21/31] Option_U32 --- crashtracker-ffi/cbindgen.toml | 1 + ddcommon-ffi/src/lib.rs | 2 +- ddcommon-ffi/src/option.rs | 10 ++++++++++ examples/ffi/crashinfo.cpp | 15 ++------------- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/crashtracker-ffi/cbindgen.toml b/crashtracker-ffi/cbindgen.toml index af0c48eee..b5571f563 100644 --- a/crashtracker-ffi/cbindgen.toml +++ b/crashtracker-ffi/cbindgen.toml @@ -26,6 +26,7 @@ renaming_overrides_prefixing = true "Endpoint" = "ddog_Endpoint" "Error" = "ddog_Error" "HttpStatus" = "ddog_HttpStatus" +"Option_U32" = "ddog_Option_U32" "Slice_CChar" = "ddog_Slice_CChar" "Slice_I64" = "ddog_Slice_I64" "Slice_U8" = "ddog_Slice_U8" diff --git a/ddcommon-ffi/src/lib.rs b/ddcommon-ffi/src/lib.rs index 23855c6e6..f5acad56f 100644 --- a/ddcommon-ffi/src/lib.rs +++ b/ddcommon-ffi/src/lib.rs @@ -13,6 +13,6 @@ pub mod vec; pub use error::*; pub use string::*; -pub use option::Option; +pub use option::*; pub use slice::{CharSlice, Slice}; pub use vec::Vec; diff --git a/ddcommon-ffi/src/option.rs b/ddcommon-ffi/src/option.rs index 2f55d95c9..05047a81a 100644 --- a/ddcommon-ffi/src/option.rs +++ b/ddcommon-ffi/src/option.rs @@ -31,3 +31,13 @@ impl From<&Option> for std::option::Option { } } } + +#[no_mangle] +pub extern "C" fn ddog_Option_U32_some(v: u32) -> Option { + Option::Some(v) +} + +#[no_mangle] +pub extern "C" fn ddog_Option_U32_none() -> Option { + Option::None +} diff --git a/examples/ffi/crashinfo.cpp b/examples/ffi/crashinfo.cpp index 099c1172e..7ee5c23f4 100644 --- a/examples/ffi/crashinfo.cpp +++ b/examples/ffi/crashinfo.cpp @@ -19,17 +19,6 @@ static ddog_CharSlice to_slice_string(std::string &s) { return {.ptr = s.data(), .len = s.length()}; } -// TODO: Testing on my mac, the tags appear to have the opposite meaning you'd -// expect -static ddog_crasht_Option_U32 some_u32(uint32_t i) { - ddog_crasht_Option_U32 rval = {.tag = DDOG_CRASHT_OPTION_U32_SOME_U32}; - rval.some = i; - return rval; -} -static ddog_crasht_Option_U32 none_u32() { - return {.tag = DDOG_CRASHT_OPTION_U32_NONE_U32}; -} - struct Deleter { void operator()(ddog_crasht_CrashInfo *object) { ddog_crasht_CrashInfo_drop(object); } }; @@ -59,9 +48,9 @@ void add_stacktrace(std::unique_ptr &crashinfo) std::vector names; for (uintptr_t i = 0; i < 20; ++i) { - names.push_back({.colno = some_u32(i), + names.push_back({.colno = ddog_Option_U32_some(i), .filename = to_slice_string(filenames[i]), - .lineno = some_u32(2 * i + 3), + .lineno = ddog_Option_U32_some(2 * i + 3), .name = to_slice_string(function_names[i])}); } From 019f250b719669a0a5360fe284d9ec51eaf45b51 Mon Sep 17 00:00:00 2001 From: Daniel Schwartz-Narbonne Date: Wed, 31 Jul 2024 15:51:23 -0400 Subject: [PATCH 22/31] licence --- LICENSE-3rdparty.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE-3rdparty.yml b/LICENSE-3rdparty.yml index 7ad0631a6..8dc05c8a1 100644 --- a/LICENSE-3rdparty.yml +++ b/LICENSE-3rdparty.yml @@ -1,4 +1,4 @@ -root_name: datadog-alloc, datadog-crashtracker, ddcommon, ddtelemetry, datadog-ddsketch, crashtracker-ffi, ddcommon-ffi, build_common, datadog-profiling, datadog-profiling-ffi, data-pipeline-ffi, data-pipeline, datadog-trace-normalization, datadog-trace-protobuf, datadog-trace-utils, ddtelemetry-ffi, symbolizer-ffi, datadog-profiling-replayer, tools, datadog-ipc, datadog-ipc-macros, tarpc, tarpc-plugins, spawn_worker, cc_utils, datadog-sidecar, datadog-sidecar-macros, datadog-sidecar-ffi, sidecar_mockgen, datadog-trace-obfuscation, test_spawn_from_lib, datadog-serverless-trace-mini-agent, datadog-trace-mini-agent +root_name: datadog-alloc, datadog-crashtracker, ddcommon, ddtelemetry, datadog-ddsketch, datadog-crashtracker-ffi, ddcommon-ffi, build_common, datadog-profiling, datadog-profiling-ffi, data-pipeline-ffi, data-pipeline, datadog-trace-normalization, datadog-trace-protobuf, datadog-trace-utils, ddtelemetry-ffi, symbolizer-ffi, datadog-profiling-replayer, tools, datadog-ipc, datadog-ipc-macros, tarpc, tarpc-plugins, spawn_worker, cc_utils, datadog-sidecar, datadog-sidecar-macros, datadog-sidecar-ffi, sidecar_mockgen, datadog-trace-obfuscation, test_spawn_from_lib, datadog-serverless-trace-mini-agent, datadog-trace-mini-agent third_party_libraries: - package_name: addr2line package_version: 0.21.0 From 9ad69bf6108239ac667c976e12d2d74e786c3ada Mon Sep 17 00:00:00 2001 From: Daniel Schwartz-Narbonne Date: Wed, 31 Jul 2024 16:12:50 -0400 Subject: [PATCH 23/31] Timespec --- Cargo.lock | 3 +- Cargo.toml | 3 -- crashtracker-ffi/Cargo.toml | 1 - crashtracker-ffi/src/crash_info/mod.rs | 16 +++----- ddcommon-ffi/Cargo.toml | 3 +- ddcommon-ffi/src/lib.rs | 5 ++- examples/ffi/crashinfo.cpp | 21 ++++++----- profiling-ffi/Cargo.toml | 1 - profiling-ffi/src/exporter.rs | 3 +- profiling-ffi/src/lib.rs | 52 -------------------------- profiling-ffi/src/profiles.rs | 3 +- 11 files changed, 26 insertions(+), 85 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 68b05d642..6fd42e5d8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1349,7 +1349,6 @@ version = "11.0.0" dependencies = [ "anyhow", "build_common", - "chrono", "datadog-crashtracker", "ddcommon", "ddcommon-ffi", @@ -1449,7 +1448,6 @@ version = "11.0.0" dependencies = [ "anyhow", "build_common", - "chrono", "data-pipeline-ffi", "datadog-crashtracker-ffi", "datadog-profiling", @@ -1694,6 +1692,7 @@ version = "11.0.0" dependencies = [ "anyhow", "build_common", + "chrono", "ddcommon", "hyper 0.14.28", ] diff --git a/Cargo.toml b/Cargo.toml index 5d9e83d21..4c296ab62 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -53,9 +53,6 @@ debug = "line-tables-only" lto = true opt-level = "s" # optimize for size -[profile.release.package.datadog-serverless-trace-mini-agent] -strip = true - # https://camshaft.github.io/bolero/library-installation.html [profile.fuzz] inherits = "dev" diff --git a/crashtracker-ffi/Cargo.toml b/crashtracker-ffi/Cargo.toml index 4e7722a62..4e68be01e 100644 --- a/crashtracker-ffi/Cargo.toml +++ b/crashtracker-ffi/Cargo.toml @@ -24,7 +24,6 @@ build_common = { path = "../build-common" } [dependencies] anyhow = "1.0" -chrono = {version = "0.4", default-features = false } datadog-crashtracker = { path = "../crashtracker" } ddcommon = { path = "../ddcommon" } ddcommon-ffi = { path = "../ddcommon-ffi", default-features = false } diff --git a/crashtracker-ffi/src/crash_info/mod.rs b/crashtracker-ffi/src/crash_info/mod.rs index e324d46c4..18e49e0cf 100644 --- a/crashtracker-ffi/src/crash_info/mod.rs +++ b/crashtracker-ffi/src/crash_info/mod.rs @@ -6,9 +6,8 @@ pub use datatypes::*; use crate::{option_from_char_slice, Result}; use anyhow::Context; -use chrono::DateTime; use ddcommon::Endpoint; -use ddcommon_ffi::{slice::AsBytes, CharSlice, Slice}; +use ddcommon_ffi::{slice::AsBytes, CharSlice, Slice, Timespec}; /// Create a new crashinfo, and returns an opaque reference to it. /// # Safety @@ -86,12 +85,12 @@ pub unsafe extern "C" fn ddog_crasht_CrashInfo_add_counter( #[must_use] pub unsafe extern "C" fn ddog_crasht_CrashInfo_add_file( crashinfo: *mut CrashInfo, - name: CharSlice, + filename: CharSlice, ) -> Result { (|| { let crashinfo = crashinfo_ptr_to_inner(crashinfo)?; - let name = name.to_utf8_lossy(); - crashinfo.add_file(&name) + let filename = filename.to_utf8_lossy(); + crashinfo.add_file(&filename) })() .context("ddog_crasht_CrashInfo_add_file failed") .into() @@ -199,14 +198,11 @@ pub unsafe extern "C" fn ddog_crasht_CrashInfo_set_stacktrace( #[must_use] pub unsafe extern "C" fn ddog_crasht_CrashInfo_set_timestamp( crashinfo: *mut CrashInfo, - secs: i64, - nsecs: u32, + ts: Timespec, ) -> Result { (|| { let crashinfo = crashinfo_ptr_to_inner(crashinfo)?; - let ts = DateTime::from_timestamp(secs, nsecs) - .with_context(|| format!("Invalid timestamp {secs} {nsecs}"))?; - crashinfo.set_timestamp(ts) + crashinfo.set_timestamp(ts.into()) })() .context("ddog_crasht_CrashInfo_set_timestamp_to_now failed") .into() diff --git a/ddcommon-ffi/Cargo.toml b/ddcommon-ffi/Cargo.toml index 5ca6ad9b3..980591700 100644 --- a/ddcommon-ffi/Cargo.toml +++ b/ddcommon-ffi/Cargo.toml @@ -19,6 +19,7 @@ cbindgen = ["build_common/cbindgen"] build_common = { path = "../build-common" } [dependencies] -ddcommon = { path = "../ddcommon" } anyhow = "1.0" +chrono = {version = "0.4", default-features = false } +ddcommon = { path = "../ddcommon" } hyper = {version = "0.14", default-features = false} diff --git a/ddcommon-ffi/src/lib.rs b/ddcommon-ffi/src/lib.rs index f5acad56f..1fdef2289 100644 --- a/ddcommon-ffi/src/lib.rs +++ b/ddcommon-ffi/src/lib.rs @@ -8,11 +8,12 @@ pub mod option; pub mod slice; pub mod string; pub mod tags; +pub mod timespec; pub mod vec; pub use error::*; -pub use string::*; - pub use option::*; pub use slice::{CharSlice, Slice}; +pub use string::*; +pub use timespec::*; pub use vec::Vec; diff --git a/examples/ffi/crashinfo.cpp b/examples/ffi/crashinfo.cpp index 7ee5c23f4..881035a4d 100644 --- a/examples/ffi/crashinfo.cpp +++ b/examples/ffi/crashinfo.cpp @@ -57,16 +57,17 @@ void add_stacktrace(std::unique_ptr &crashinfo) std::vector trace; for (uintptr_t i = 0; i < 20; ++i) { ddog_crasht_StackFrame frame = {.ip = i, - .module_base_address = 0, - .names = {.ptr = &names[i], .len = 1}, - .sp = 0, - .symbol_address = 0}; + .module_base_address = 0, + .names = {.ptr = &names[i], .len = 1}, + .sp = 0, + .symbol_address = 0}; trace.push_back(frame); } ddog_crasht_Slice_StackFrame trace_slice = {.ptr = trace.data(), .len = trace.size()}; - check_result(ddog_crasht_CrashInfo_set_stacktrace(crashinfo.get(), to_slice_c_char(""), trace_slice), - "Failed to set stacktrace"); + check_result( + ddog_crasht_CrashInfo_set_stacktrace(crashinfo.get(), to_slice_c_char(""), trace_slice), + "Failed to set stacktrace"); } int main(void) { @@ -92,9 +93,10 @@ int main(void) { }; // TODO: We should set more tags that are expected by telemetry - check_result(ddog_crasht_CrashInfo_set_metadata(crashinfo.get(), metadata), "Failed to add metadata"); + check_result(ddog_crasht_CrashInfo_set_metadata(crashinfo.get(), metadata), + "Failed to add metadata"); check_result(ddog_crasht_CrashInfo_add_tag(crashinfo.get(), to_slice_c_char("best hockey team"), - to_slice_c_char("Habs")), + to_slice_c_char("Habs")), "Failed to add tag"); // This API allows one to capture useful files (e.g. /proc/pid/maps) @@ -106,7 +108,8 @@ int main(void) { add_stacktrace(crashinfo); // Datadog IPO at 2019-09-19T13:30:00Z = 1568899800 unix - check_result(ddog_crasht_CrashInfo_set_timestamp(crashinfo.get(), 1568899800, 0), + check_result(ddog_crasht_CrashInfo_set_timestamp( + crashinfo.get(), (ddog_Timespec){.seconds = 1568899800, .nanoseconds = 0}), "Failed to set timestamp"); auto endpoint = ddog_endpoint_from_filename(to_slice_c_char("/tmp/test")); diff --git a/profiling-ffi/Cargo.toml b/profiling-ffi/Cargo.toml index c617e78e9..62515d60f 100644 --- a/profiling-ffi/Cargo.toml +++ b/profiling-ffi/Cargo.toml @@ -31,7 +31,6 @@ build_common = { path = "../build-common" } [dependencies] anyhow = "1.0" -chrono = {version = "0.4", default-features = false } datadog-crashtracker-ffi = { path = "../crashtracker-ffi", default-features = false, optional = true} datadog-profiling = { path = "../profiling" } hyper = { version = "0.14", default-features = false } diff --git a/profiling-ffi/src/exporter.rs b/profiling-ffi/src/exporter.rs index 7d00acbb9..515ede7ff 100644 --- a/profiling-ffi/src/exporter.rs +++ b/profiling-ffi/src/exporter.rs @@ -4,13 +4,12 @@ #![allow(renamed_and_removed_lints)] #![allow(clippy::box_vec)] -use crate::Timespec; use datadog_profiling::exporter; use datadog_profiling::exporter::{ProfileExporter, Request}; use datadog_profiling::internal::ProfiledEndpointsStats; use ddcommon::tag::Tag; use ddcommon_ffi::slice::{AsBytes, ByteSlice, CharSlice, Slice}; -use ddcommon_ffi::{Error, MaybeError}; +use ddcommon_ffi::{Error, MaybeError, Timespec}; use std::borrow::Cow; use std::ptr::NonNull; use std::str::FromStr; diff --git a/profiling-ffi/src/lib.rs b/profiling-ffi/src/lib.rs index edd00cc53..f25481447 100644 --- a/profiling-ffi/src/lib.rs +++ b/profiling-ffi/src/lib.rs @@ -4,11 +4,6 @@ #[cfg(all(feature = "symbolizer", not(target_os = "windows")))] pub use symbolizer_ffi::*; -use std::fmt::Debug; -use std::time::SystemTime; - -use chrono::{DateTime, TimeZone, Utc}; - mod exporter; mod profiles; @@ -23,50 +18,3 @@ pub use ddtelemetry_ffi::*; #[cfg(feature = "data-pipeline-ffi")] #[allow(unused_imports)] pub use data_pipeline_ffi::*; - -/// Represents time since the Unix Epoch in seconds plus nanoseconds. -#[repr(C)] -#[derive(Copy, Clone, Debug)] -pub struct Timespec { - pub seconds: i64, - pub nanoseconds: u32, -} - -impl From for DateTime { - fn from(value: Timespec) -> Self { - Utc.timestamp_opt(value.seconds, value.nanoseconds).unwrap() - } -} - -impl From for SystemTime { - fn from(value: Timespec) -> Self { - // The DateTime API is more convenient, so let's delegate. - let datetime: DateTime = value.into(); - SystemTime::from(datetime) - } -} - -impl<'a> From<&'a Timespec> for SystemTime { - fn from(value: &'a Timespec) -> Self { - // The DateTime API is more convenient, so let's delegate. - let datetime: DateTime = (*value).into(); - SystemTime::from(datetime) - } -} - -impl From> for Timespec { - fn from(value: DateTime) -> Self { - Self { - seconds: value.timestamp(), - nanoseconds: value.timestamp_subsec_nanos(), - } - } -} - -impl From for Timespec { - fn from(value: SystemTime) -> Self { - // The DateTime API is more convenient, so let's delegate again. - let datetime: DateTime = value.into(); - Self::from(datetime) - } -} diff --git a/profiling-ffi/src/profiles.rs b/profiling-ffi/src/profiles.rs index 5ec993237..6f3b4716b 100644 --- a/profiling-ffi/src/profiles.rs +++ b/profiling-ffi/src/profiles.rs @@ -1,13 +1,12 @@ // Copyright 2021-Present Datadog, Inc. https://www.datadoghq.com/ // SPDX-License-Identifier: Apache-2.0 -use crate::Timespec; use anyhow::Context; use datadog_profiling::api; use datadog_profiling::internal; use datadog_profiling::internal::ProfiledEndpointsStats; use ddcommon_ffi::slice::{AsBytes, CharSlice, Slice}; -use ddcommon_ffi::Error; +use ddcommon_ffi::{Error, Timespec}; use std::num::NonZeroI64; use std::str::Utf8Error; use std::time::{Duration, SystemTime}; From b1e45cfe53307014baed73f01430c815249eedd7 Mon Sep 17 00:00:00 2001 From: Daniel Schwartz-Narbonne Date: Wed, 31 Jul 2024 16:20:17 -0400 Subject: [PATCH 24/31] Config --- crashtracker-ffi/src/collector/datatypes.rs | 6 +++--- crashtracker-ffi/src/collector/mod.rs | 4 ++-- examples/ffi/crashtracking.c | 5 ++--- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/crashtracker-ffi/src/collector/datatypes.rs b/crashtracker-ffi/src/collector/datatypes.rs index e272c9526..48eafe26f 100644 --- a/crashtracker-ffi/src/collector/datatypes.rs +++ b/crashtracker-ffi/src/collector/datatypes.rs @@ -58,7 +58,7 @@ impl<'a> TryFrom> for datadog_crashtracker::CrashtrackerRecei } #[repr(C)] -pub struct Configuration<'a> { +pub struct Config<'a> { pub additional_files: Slice<'a, CharSlice<'a>>, pub create_alt_stack: bool, /// The endpoint to send the crash report to (can be a file://). @@ -69,9 +69,9 @@ pub struct Configuration<'a> { pub wait_for_receiver: bool, } -impl<'a> TryFrom> for datadog_crashtracker::CrashtrackerConfiguration { +impl<'a> TryFrom> for datadog_crashtracker::CrashtrackerConfiguration { type Error = anyhow::Error; - fn try_from(value: Configuration<'a>) -> anyhow::Result { + fn try_from(value: Config<'a>) -> anyhow::Result { let additional_files = { let mut vec = Vec::with_capacity(value.additional_files.len()); for x in value.additional_files.iter() { diff --git a/crashtracker-ffi/src/collector/mod.rs b/crashtracker-ffi/src/collector/mod.rs index 8e9a37a09..41d526670 100644 --- a/crashtracker-ffi/src/collector/mod.rs +++ b/crashtracker-ffi/src/collector/mod.rs @@ -55,7 +55,7 @@ pub unsafe extern "C" fn ddog_crasht_shutdown() -> Result { /// This function is not atomic. A crash during its execution may lead to /// unexpected crash-handling behaviour. pub unsafe extern "C" fn ddog_crasht_update_on_fork( - config: Configuration, + config: Config, receiver_config: ReceiverConfig, metadata: Metadata, ) -> Result { @@ -82,7 +82,7 @@ pub unsafe extern "C" fn ddog_crasht_update_on_fork( /// This function is not atomic. A crash during its execution may lead to /// unexpected crash-handling behaviour. pub unsafe extern "C" fn ddog_crasht_init_with_receiver( - config: Configuration, + config: Config, receiver_config: ReceiverConfig, metadata: Metadata, ) -> Result { diff --git a/examples/ffi/crashtracking.c b/examples/ffi/crashtracking.c index 397bb7829..a3b373904 100644 --- a/examples/ffi/crashtracking.c +++ b/examples/ffi/crashtracking.c @@ -55,7 +55,7 @@ int main(int argc, char **argv) { // struct ddog_Endpoint * endpoint = // ddog_endpoint_from_url(DDOG_CHARSLICE_C("http://localhost:8126")); - ddog_crasht_Configuration config = { + ddog_crasht_Config config = { .create_alt_stack = false, .endpoint = endpoint, .resolve_frames = DDOG_CRASHT_STACKTRACE_COLLECTION_ENABLED_WITH_INPROCESS_SYMBOLS, @@ -71,8 +71,7 @@ int main(int argc, char **argv) { handle_result(ddog_crasht_init_with_receiver(config, receiver_config, metadata)); ddog_endpoint_drop(endpoint); - handle_result( - ddog_crasht_begin_profiling_op(DDOG_CRASHT_PROFILING_OP_TYPES_SERIALIZING)); + handle_result(ddog_crasht_begin_profiling_op(DDOG_CRASHT_PROFILING_OP_TYPES_SERIALIZING)); handle_uintptr_t_result(ddog_crasht_insert_span_id(0, 42)); handle_uintptr_t_result(ddog_crasht_insert_trace_id(1, 1)); From ff47bd4fdcee249e779e18a96f9ba1a1ed14051b Mon Sep 17 00:00:00 2001 From: Daniel Schwartz-Narbonne Date: Wed, 31 Jul 2024 16:21:34 -0400 Subject: [PATCH 25/31] added timespec file for real --- ddcommon-ffi/src/timespec.rs | 53 ++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 ddcommon-ffi/src/timespec.rs diff --git a/ddcommon-ffi/src/timespec.rs b/ddcommon-ffi/src/timespec.rs new file mode 100644 index 000000000..a490845c3 --- /dev/null +++ b/ddcommon-ffi/src/timespec.rs @@ -0,0 +1,53 @@ +// Copyright 2021-Present Datadog, Inc. https://www.datadoghq.com/ +// SPDX-License-Identifier: Apache-2.0 + +use chrono::{DateTime, TimeZone, Utc}; +use std::fmt::Debug; +use std::time::SystemTime; + +/// Represents time since the Unix Epoch in seconds plus nanoseconds. +#[repr(C)] +#[derive(Copy, Clone, Debug)] +pub struct Timespec { + pub seconds: i64, + pub nanoseconds: u32, +} + +impl From for DateTime { + fn from(value: Timespec) -> Self { + Utc.timestamp_opt(value.seconds, value.nanoseconds).unwrap() + } +} + +impl From for SystemTime { + fn from(value: Timespec) -> Self { + // The DateTime API is more convenient, so let's delegate. + let datetime: DateTime = value.into(); + SystemTime::from(datetime) + } +} + +impl<'a> From<&'a Timespec> for SystemTime { + fn from(value: &'a Timespec) -> Self { + // The DateTime API is more convenient, so let's delegate. + let datetime: DateTime = (*value).into(); + SystemTime::from(datetime) + } +} + +impl From> for Timespec { + fn from(value: DateTime) -> Self { + Self { + seconds: value.timestamp(), + nanoseconds: value.timestamp_subsec_nanos(), + } + } +} + +impl From for Timespec { + fn from(value: SystemTime) -> Self { + // The DateTime API is more convenient, so let's delegate again. + let datetime: DateTime = value.into(); + Self::from(datetime) + } +} From cc6c9225da213a4ccdcd9c8c47002278e587d5c1 Mon Sep 17 00:00:00 2001 From: Daniel Schwartz-Narbonne Date: Wed, 31 Jul 2024 16:24:13 -0400 Subject: [PATCH 26/31] put back toml change --- Cargo.toml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index 4c296ab62..5d9e83d21 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -53,6 +53,9 @@ debug = "line-tables-only" lto = true opt-level = "s" # optimize for size +[profile.release.package.datadog-serverless-trace-mini-agent] +strip = true + # https://camshaft.github.io/bolero/library-installation.html [profile.fuzz] inherits = "dev" From 52bde76151416f3e2d4b9a088d8db7e9807422c4 Mon Sep 17 00:00:00 2001 From: Daniel Schwartz-Narbonne Date: Wed, 31 Jul 2024 17:23:39 -0400 Subject: [PATCH 27/31] chrono needed the std feature to compile ddcommon-ffi --- Cargo.lock | 4 ++-- LICENSE-3rdparty.yml | 2 +- ddcommon-ffi/Cargo.toml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a843ae1eb..f261acf21 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -903,9 +903,9 @@ checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" [[package]] name = "chrono" -version = "0.4.37" +version = "0.4.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a0d04d43504c61aa6c7531f1871dd0d418d91130162063b789da00fd7057a5e" +checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" dependencies = [ "android-tzdata", "iana-time-zone", diff --git a/LICENSE-3rdparty.yml b/LICENSE-3rdparty.yml index 8dc05c8a1..4dc7ebacc 100644 --- a/LICENSE-3rdparty.yml +++ b/LICENSE-3rdparty.yml @@ -5682,7 +5682,7 @@ third_party_libraries: - license: Apache-2.0 text: " Apache License\n Version 2.0, January 2004\n http://www.apache.org/licenses/\n\nTERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n1. Definitions.\n\n \"License\" shall mean the terms and conditions for use, reproduction,\n and distribution as defined by Sections 1 through 9 of this document.\n\n \"Licensor\" shall mean the copyright owner or entity authorized by\n the copyright owner that is granting the License.\n\n \"Legal Entity\" shall mean the union of the acting entity and all\n other entities that control, are controlled by, or are under common\n control with that entity. For the purposes of this definition,\n \"control\" means (i) the power, direct or indirect, to cause the\n direction or management of such entity, whether by contract or\n otherwise, or (ii) ownership of fifty percent (50%) or more of the\n outstanding shares, or (iii) beneficial ownership of such entity.\n\n \"You\" (or \"Your\") shall mean an individual or Legal Entity\n exercising permissions granted by this License.\n\n \"Source\" form shall mean the preferred form for making modifications,\n including but not limited to software source code, documentation\n source, and configuration files.\n\n \"Object\" form shall mean any form resulting from mechanical\n transformation or translation of a Source form, including but\n not limited to compiled object code, generated documentation,\n and conversions to other media types.\n\n \"Work\" shall mean the work of authorship, whether in Source or\n Object form, made available under the License, as indicated by a\n copyright notice that is included in or attached to the work\n (an example is provided in the Appendix below).\n\n \"Derivative Works\" shall mean any work, whether in Source or Object\n form, that is based on (or derived from) the Work and for which the\n editorial revisions, annotations, elaborations, or other modifications\n represent, as a whole, an original work of authorship. For the purposes\n of this License, Derivative Works shall not include works that remain\n separable from, or merely link (or bind by name) to the interfaces of,\n the Work and Derivative Works thereof.\n\n \"Contribution\" shall mean any work of authorship, including\n the original version of the Work and any modifications or additions\n to that Work or Derivative Works thereof, that is intentionally\n submitted to Licensor for inclusion in the Work by the copyright owner\n or by an individual or Legal Entity authorized to submit on behalf of\n the copyright owner. For the purposes of this definition, \"submitted\"\n means any form of electronic, verbal, or written communication sent\n to the Licensor or its representatives, including but not limited to\n communication on electronic mailing lists, source code control systems,\n and issue tracking systems that are managed by, or on behalf of, the\n Licensor for the purpose of discussing and improving the Work, but\n excluding communication that is conspicuously marked or otherwise\n designated in writing by the copyright owner as \"Not a Contribution.\"\n\n \"Contributor\" shall mean Licensor and any individual or Legal Entity\n on behalf of whom a Contribution has been received by Licensor and\n subsequently incorporated within the Work.\n\n2. Grant of Copyright License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n copyright license to reproduce, prepare Derivative Works of,\n publicly display, publicly perform, sublicense, and distribute the\n Work and such Derivative Works in Source or Object form.\n\n3. Grant of Patent License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n (except as stated in this section) patent license to make, have made,\n use, offer to sell, sell, import, and otherwise transfer the Work,\n where such license applies only to those patent claims licensable\n by such Contributor that are necessarily infringed by their\n Contribution(s) alone or by combination of their Contribution(s)\n with the Work to which such Contribution(s) was submitted. If You\n institute patent litigation against any entity (including a\n cross-claim or counterclaim in a lawsuit) alleging that the Work\n or a Contribution incorporated within the Work constitutes direct\n or contributory patent infringement, then any patent licenses\n granted to You under this License for that Work shall terminate\n as of the date such litigation is filed.\n\n4. Redistribution. You may reproduce and distribute copies of the\n Work or Derivative Works thereof in any medium, with or without\n modifications, and in Source or Object form, provided that You\n meet the following conditions:\n\n (a) You must give any other recipients of the Work or\n Derivative Works a copy of this License; and\n\n (b) You must cause any modified files to carry prominent notices\n stating that You changed the files; and\n\n (c) You must retain, in the Source form of any Derivative Works\n that You distribute, all copyright, patent, trademark, and\n attribution notices from the Source form of the Work,\n excluding those notices that do not pertain to any part of\n the Derivative Works; and\n\n (d) If the Work includes a \"NOTICE\" text file as part of its\n distribution, then any Derivative Works that You distribute must\n include a readable copy of the attribution notices contained\n within such NOTICE file, excluding those notices that do not\n pertain to any part of the Derivative Works, in at least one\n of the following places: within a NOTICE text file distributed\n as part of the Derivative Works; within the Source form or\n documentation, if provided along with the Derivative Works; or,\n within a display generated by the Derivative Works, if and\n wherever such third-party notices normally appear. The contents\n of the NOTICE file are for informational purposes only and\n do not modify the License. You may add Your own attribution\n notices within Derivative Works that You distribute, alongside\n or as an addendum to the NOTICE text from the Work, provided\n that such additional attribution notices cannot be construed\n as modifying the License.\n\n You may add Your own copyright statement to Your modifications and\n may provide additional or different license terms and conditions\n for use, reproduction, or distribution of Your modifications, or\n for any such Derivative Works as a whole, provided Your use,\n reproduction, and distribution of the Work otherwise complies with\n the conditions stated in this License.\n\n5. Submission of Contributions. Unless You explicitly state otherwise,\n any Contribution intentionally submitted for inclusion in the Work\n by You to the Licensor shall be under the terms and conditions of\n this License, without any additional terms or conditions.\n Notwithstanding the above, nothing herein shall supersede or modify\n the terms of any separate license agreement you may have executed\n with Licensor regarding such Contributions.\n\n6. Trademarks. This License does not grant permission to use the trade\n names, trademarks, service marks, or product names of the Licensor,\n except as required for reasonable and customary use in describing the\n origin of the Work and reproducing the content of the NOTICE file.\n\n7. Disclaimer of Warranty. Unless required by applicable law or\n agreed to in writing, Licensor provides the Work (and each\n Contributor provides its Contributions) on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n implied, including, without limitation, any warranties or conditions\n of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n PARTICULAR PURPOSE. You are solely responsible for determining the\n appropriateness of using or redistributing the Work and assume any\n risks associated with Your exercise of permissions under this License.\n\n8. Limitation of Liability. In no event and under no legal theory,\n whether in tort (including negligence), contract, or otherwise,\n unless required by applicable law (such as deliberate and grossly\n negligent acts) or agreed to in writing, shall any Contributor be\n liable to You for damages, including any direct, indirect, special,\n incidental, or consequential damages of any character arising as a\n result of this License or out of the use or inability to use the\n Work (including but not limited to damages for loss of goodwill,\n work stoppage, computer failure or malfunction, or any and all\n other commercial damages or losses), even if such Contributor\n has been advised of the possibility of such damages.\n\n9. Accepting Warranty or Additional Liability. While redistributing\n the Work or Derivative Works thereof, You may choose to offer,\n and charge a fee for, acceptance of support, warranty, indemnity,\n or other liability obligations and/or rights consistent with this\n License. However, in accepting such obligations, You may act only\n on Your own behalf and on Your sole responsibility, not on behalf\n of any other Contributor, and only if You agree to indemnify,\n defend, and hold each Contributor harmless for any liability\n incurred by, or claims asserted against, such Contributor by reason\n of your accepting any such warranty or additional liability.\n\nEND OF TERMS AND CONDITIONS\n\nAPPENDIX: How to apply the Apache License to your work.\n\n To apply the Apache License to your work, attach the following\n boilerplate notice, with the fields enclosed by brackets \"[]\"\n replaced with your own identifying information. (Don't include\n the brackets!) The text should be enclosed in the appropriate\n comment syntax for the file format. We also recommend that a\n file or class name and description of purpose be included on the\n same \"printed page\" as the copyright notice for easier\n identification within third-party archives.\n\nCopyright [yyyy] [name of copyright owner]\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n\thttp://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n" - package_name: chrono - package_version: 0.4.37 + package_version: 0.4.38 repository: https://github.com/chronotope/chrono license: MIT OR Apache-2.0 licenses: diff --git a/ddcommon-ffi/Cargo.toml b/ddcommon-ffi/Cargo.toml index 980591700..2c621a8ab 100644 --- a/ddcommon-ffi/Cargo.toml +++ b/ddcommon-ffi/Cargo.toml @@ -20,6 +20,6 @@ build_common = { path = "../build-common" } [dependencies] anyhow = "1.0" -chrono = {version = "0.4", default-features = false } +chrono = { version = "0.4.38", features = ["std"] } ddcommon = { path = "../ddcommon" } hyper = {version = "0.14", default-features = false} From 8b18343515bbbe46ba94940d7f55b1cd1c02258e Mon Sep 17 00:00:00 2001 From: Daniel Schwartz-Narbonne Date: Wed, 31 Jul 2024 17:47:44 -0400 Subject: [PATCH 28/31] try a different format to see if msvc is happy --- examples/ffi/crashinfo.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/ffi/crashinfo.cpp b/examples/ffi/crashinfo.cpp index 881035a4d..9b5dca912 100644 --- a/examples/ffi/crashinfo.cpp +++ b/examples/ffi/crashinfo.cpp @@ -107,9 +107,10 @@ int main(void) { add_stacktrace(crashinfo); + ddog_Timespec timestamp = {.seconds = 1568899800, .nanoseconds = 0}; // Datadog IPO at 2019-09-19T13:30:00Z = 1568899800 unix check_result(ddog_crasht_CrashInfo_set_timestamp( - crashinfo.get(), (ddog_Timespec){.seconds = 1568899800, .nanoseconds = 0}), + crashinfo.get(), timestamp), "Failed to set timestamp"); auto endpoint = ddog_endpoint_from_filename(to_slice_c_char("/tmp/test")); From a1ad98a5e04037f7e8f33d1ed710538e61e85ca5 Mon Sep 17 00:00:00 2001 From: Daniel Schwartz-Narbonne Date: Thu, 1 Aug 2024 10:58:37 -0400 Subject: [PATCH 29/31] Update crashtracker-ffi/Cargo.toml Co-authored-by: Ivo Anjo --- crashtracker-ffi/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crashtracker-ffi/Cargo.toml b/crashtracker-ffi/Cargo.toml index 4e68be01e..253f7d22f 100644 --- a/crashtracker-ffi/Cargo.toml +++ b/crashtracker-ffi/Cargo.toml @@ -9,7 +9,7 @@ rust-version.workspace = true license.workspace = true [lib] -bench =false +bench = false [features] default = ["cbindgen", "collector", "receiver"] From 091f4d99e53d38c291253ee37c43757df43b6e41 Mon Sep 17 00:00:00 2001 From: Daniel Schwartz-Narbonne Date: Thu, 1 Aug 2024 11:07:55 -0400 Subject: [PATCH 30/31] demangle feature and naming --- crashtracker-ffi/Cargo.toml | 7 ++++--- crashtracker-ffi/src/demangler/mod.rs | 10 +++++----- crashtracker-ffi/src/lib.rs | 2 ++ 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/crashtracker-ffi/Cargo.toml b/crashtracker-ffi/Cargo.toml index 253f7d22f..a5fae0377 100644 --- a/crashtracker-ffi/Cargo.toml +++ b/crashtracker-ffi/Cargo.toml @@ -12,10 +12,11 @@ license.workspace = true bench = false [features] -default = ["cbindgen", "collector", "receiver"] +default = ["cbindgen", "collector", "demangler", "receiver"] cbindgen = ["build_common/cbindgen"] # Enables the in-process collection of crash-info collector = [] +demangler = ["dep:symbolic-demangle", "dep:symbolic-common"] # Enables the use of this library to receiver crash-info from a suitable collector receiver = [] @@ -28,5 +29,5 @@ datadog-crashtracker = { path = "../crashtracker" } ddcommon = { path = "../ddcommon" } ddcommon-ffi = { path = "../ddcommon-ffi", default-features = false } hyper = {version = "0.14", default-features = false} -symbolic-demangle = { version = "12.8.0", default-features = false, features = ["rust", "cpp", "msvc"] } -symbolic-common = "12.8.0" +symbolic-demangle = { version = "12.8.0", default-features = false, features = ["rust", "cpp", "msvc"], optional = true } +symbolic-common = { version = "12.8.0", default-features = false, optional = true } diff --git a/crashtracker-ffi/src/demangler/mod.rs b/crashtracker-ffi/src/demangler/mod.rs index 3c1ed09bf..c5e47b5ed 100644 --- a/crashtracker-ffi/src/demangler/mod.rs +++ b/crashtracker-ffi/src/demangler/mod.rs @@ -15,7 +15,7 @@ use symbolic_demangle::Demangle; /// The string is copied into the result, and does not need to outlive this call #[no_mangle] #[must_use] -pub unsafe extern "C" fn ddog_demangle( +pub unsafe extern "C" fn ddog_crasht_demangle( name: CharSlice, options: DemangleOptions, ) -> StringWrapperResult { @@ -32,12 +32,12 @@ pub unsafe extern "C" fn ddog_demangle( fn test_demangle() { let test_string = "_ZNSt28__atomic_futex_unsigned_base26_M_futex_wait_until_steadyEPjjbNSt6chrono8durationIlSt5ratioILl1ELl1EEEENS2_IlS3_ILl1ELl1000000000EEEE"; let test_slice = CharSlice::from(test_string); - let result: String = unsafe { ddog_demangle(test_slice, DemangleOptions::Complete) } + let result: String = unsafe { ddog_crasht_demangle(test_slice, DemangleOptions::Complete) } .unwrap() .into(); assert_eq!(result, "std::__atomic_futex_unsigned_base::_M_futex_wait_until_steady(unsigned int*, unsigned int, bool, std::chrono::duration >, std::chrono::duration >)"); - let result: String = unsafe { ddog_demangle(test_slice, DemangleOptions::NameOnly) } + let result: String = unsafe { ddog_crasht_demangle(test_slice, DemangleOptions::NameOnly) } .unwrap() .into(); assert_eq!( @@ -50,12 +50,12 @@ fn test_demangle() { fn test_demangle_fails() { let test_string = "_ZNSt28__fdf"; let test_slice = CharSlice::from(test_string); - let result: String = unsafe { ddog_demangle(test_slice, DemangleOptions::Complete) } + let result: String = unsafe { ddog_crasht_demangle(test_slice, DemangleOptions::Complete) } .unwrap() .into(); assert_eq!(result, ""); - let result: String = unsafe { ddog_demangle(test_slice, DemangleOptions::NameOnly) } + let result: String = unsafe { ddog_crasht_demangle(test_slice, DemangleOptions::NameOnly) } .unwrap() .into(); assert_eq!(result, ""); diff --git a/crashtracker-ffi/src/lib.rs b/crashtracker-ffi/src/lib.rs index 98d57dfe1..1dc4a8a8d 100644 --- a/crashtracker-ffi/src/lib.rs +++ b/crashtracker-ffi/src/lib.rs @@ -5,6 +5,7 @@ mod collector; mod crash_info; mod datatypes; +#[cfg(feature = "demangler")] mod demangler; #[cfg(all(unix, feature = "receiver"))] mod receiver; @@ -13,6 +14,7 @@ mod receiver; pub use collector::*; pub use crash_info::*; pub use datatypes::*; +#[cfg(feature = "demangler")] pub use demangler::*; #[cfg(all(unix, feature = "receiver"))] pub use receiver::*; From 4cc220739bca83194569fc2c2c63b8a8e56cd229 Mon Sep 17 00:00:00 2001 From: Daniel Schwartz-Narbonne Date: Thu, 1 Aug 2024 11:31:23 -0400 Subject: [PATCH 31/31] fix readme --- crashtracker/src/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/crashtracker/src/README.md b/crashtracker/src/README.md index 09357ab94..8e4232552 100644 --- a/crashtracker/src/README.md +++ b/crashtracker/src/README.md @@ -13,10 +13,10 @@ It has three related parts: ## How to use the crashhandler -1. Initilize it using `ddog_crashtracker_init` -2. After a fork, reset the crashtracker in the child using `ddog_crashtracker_update_on_fork`. +1. Initilize it using `ddog_crasht_init` +2. After a fork, reset the crashtracker in the child using `ddog_crasht_update_on_fork`. This can be done in an `pthread_atfork` handler. -2. [Optional]. The crash-tracker can be shutdown, and the previous crash handler restored, using `ddog_crashtracker_shutdown`. +2. [Optional]. The crash-tracker can be shutdown, and the previous crash handler restored, using `ddog_crasht_shutdown`. Currently, there is a state machine that stops you from then restarting the crash-tracker. Fixing this is a todo