diff --git a/Cargo.lock b/Cargo.lock index 55e8f08e197..7d190dfa02c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -24,7 +24,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" dependencies = [ "cfg-if", - "getrandom 0.3.2", "once_cell", "version_check 0.9.5", "zerocopy 0.8.24", @@ -1285,7 +1284,8 @@ dependencies = [ "constcat", "futures", "http", - "http-body-util", + "libdd-capabilities", + "libdd-capabilities-impl", "libdd-common", "libdd-data-pipeline", "libdd-remote-config", @@ -1336,6 +1336,7 @@ dependencies = [ "libc 0.2.186", "libdd-common", "libdd-common-ffi", + "libdd-crashtracker", "libdd-crashtracker-ffi", "libdd-data-pipeline", "libdd-library-config-ffi", @@ -1343,6 +1344,7 @@ dependencies = [ "libdd-telemetry", "libdd-telemetry-ffi", "libdd-tinybytes", + "libdd-trace-protobuf", "libdd-trace-stats", "libdd-trace-utils", "log", @@ -1871,9 +1873,9 @@ checksum = "673464e1e314dd67a0fd9544abc99e8eb28d0c7e3b69b033bcff9b2d00b87333" [[package]] name = "futures" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" +checksum = "8b147ee9d1f6d097cef9ce628cd2ee62288d963e16fb287bd9286455b241382d" dependencies = [ "futures-channel", "futures-core", @@ -1886,9 +1888,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" +checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d" dependencies = [ "futures-core", "futures-sink", @@ -1896,15 +1898,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" +checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" [[package]] name = "futures-executor" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" +checksum = "baf29c38818342a3b26b5b923639e7b1f4a61fc5e76102d4b1981c6dc7a7579d" dependencies = [ "futures-core", "futures-task", @@ -1913,15 +1915,15 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" +checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718" [[package]] name = "futures-macro" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" +checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b" dependencies = [ "proc-macro2", "quote", @@ -1930,15 +1932,15 @@ dependencies = [ [[package]] name = "futures-sink" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" +checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893" [[package]] name = "futures-task" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" +checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" [[package]] name = "futures-timer" @@ -1948,9 +1950,9 @@ checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24" [[package]] name = "futures-util" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" +checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" dependencies = [ "futures-channel", "futures-core", @@ -1960,7 +1962,6 @@ dependencies = [ "futures-task", "memchr", "pin-project-lite", - "pin-utils", "slab", ] @@ -2768,29 +2769,33 @@ dependencies = [ [[package]] name = "libdd-capabilities" -version = "2.0.0" +version = "2.1.0" dependencies = [ "anyhow", "bytes", + "futures-channel", + "futures-util", "http", "thiserror 1.0.69", ] [[package]] name = "libdd-capabilities-impl" -version = "2.0.0" +version = "3.0.0" dependencies = [ + "anyhow", "bytes", "http", "http-body-util", "libdd-capabilities", "libdd-common", + "tempfile", "tokio", ] [[package]] name = "libdd-common" -version = "4.2.0" +version = "5.1.0" dependencies = [ "anyhow", "bytes", @@ -2822,6 +2827,7 @@ dependencies = [ "rustls", "rustls-native-certs", "rustls-platform-verifier", + "rustls-webpki", "serde", "static_assertions", "tempfile", @@ -2863,6 +2869,8 @@ dependencies = [ "goblin", "http", "libc 0.2.186", + "libdd-capabilities", + "libdd-capabilities-impl", "libdd-common", "libdd-libunwind-sys", "libdd-telemetry", @@ -2906,7 +2914,7 @@ dependencies = [ [[package]] name = "libdd-data-pipeline" -version = "6.0.0" +version = "7.0.0" dependencies = [ "anyhow", "arc-swap", @@ -2916,6 +2924,7 @@ dependencies = [ "criterion", "duplicate 2.0.1", "either", + "futures", "getrandom 0.2.15", "http", "http-body-util", @@ -2934,6 +2943,7 @@ dependencies = [ "libdd-trace-protobuf", "libdd-trace-stats", "libdd-trace-utils", + "prost", "rand 0.8.5", "regex", "rmp-serde", @@ -2945,11 +2955,12 @@ dependencies = [ "tokio-util", "tracing", "uuid", + "web-time", ] [[package]] name = "libdd-ddsketch" -version = "1.0.1" +version = "1.1.0" dependencies = [ "criterion", "prost", @@ -2961,12 +2972,14 @@ dependencies = [ [[package]] name = "libdd-dogstatsd-client" -version = "3.0.0" +version = "4.0.0" dependencies = [ "anyhow", + "async-trait", "cadence", "http", "libdd-common", + "libdd-shared-runtime", "serde", "tokio", "tracing", @@ -2974,7 +2987,7 @@ dependencies = [ [[package]] name = "libdd-library-config" -version = "2.0.0" +version = "3.0.0" dependencies = [ "anyhow", "libc 0.2.186", @@ -3082,10 +3095,11 @@ dependencies = [ [[package]] name = "libdd-remote-config" -version = "0.1.0" +version = "2.0.0" dependencies = [ "anyhow", "base64 0.22.1", + "bytes", "futures", "futures-util", "hashbrown 0.15.2", @@ -3093,6 +3107,8 @@ dependencies = [ "http-body-util", "hyper", "hyper-util", + "libdd-capabilities", + "libdd-capabilities-impl", "libdd-common", "libdd-remote-config", "libdd-trace-protobuf", @@ -3113,7 +3129,7 @@ dependencies = [ [[package]] name = "libdd-shared-runtime" -version = "1.0.0" +version = "2.0.0" dependencies = [ "async-trait", "futures", @@ -3129,18 +3145,20 @@ dependencies = [ [[package]] name = "libdd-telemetry" -version = "5.0.1" +version = "6.0.0" dependencies = [ "anyhow", "async-trait", "base64 0.22.1", "bytes", "futures", + "getrandom 0.2.15", "hashbrown 0.15.2", "http", - "http-body-util", "httpmock", "libc 0.2.186", + "libdd-capabilities", + "libdd-capabilities-impl", "libdd-common", "libdd-ddsketch", "libdd-shared-runtime", @@ -3152,6 +3170,7 @@ dependencies = [ "tracing", "tracing-subscriber", "uuid", + "web-time", "winver", ] @@ -3162,6 +3181,7 @@ dependencies = [ "build_common", "function_name", "libc 0.2.186", + "libdd-capabilities-impl", "libdd-common", "libdd-common-ffi", "libdd-telemetry", @@ -3186,7 +3206,7 @@ dependencies = [ [[package]] name = "libdd-trace-normalization" -version = "2.0.0" +version = "3.0.0" dependencies = [ "anyhow", "arbitrary", @@ -3198,7 +3218,7 @@ dependencies = [ [[package]] name = "libdd-trace-obfuscation" -version = "4.0.0" +version = "5.0.0" dependencies = [ "anyhow", "criterion", @@ -3215,7 +3235,7 @@ dependencies = [ [[package]] name = "libdd-trace-protobuf" -version = "3.0.2" +version = "4.0.0" dependencies = [ "bolero", "prost", @@ -3229,12 +3249,13 @@ dependencies = [ [[package]] name = "libdd-trace-stats" -version = "5.0.0" +version = "6.0.0" dependencies = [ "anyhow", "arc-swap", "async-trait", "criterion", + "futures", "hashbrown 0.15.2", "http", "httpmock", @@ -3242,7 +3263,9 @@ dependencies = [ "libdd-capabilities-impl", "libdd-common", "libdd-ddsketch", + "libdd-dogstatsd-client", "libdd-shared-runtime", + "libdd-telemetry", "libdd-trace-obfuscation", "libdd-trace-protobuf", "libdd-trace-utils", @@ -3252,11 +3275,12 @@ dependencies = [ "tokio", "tokio-util", "tracing", + "web-time", ] [[package]] name = "libdd-trace-utils" -version = "8.0.0" +version = "9.0.0" dependencies = [ "anyhow", "base64 0.22.1", @@ -3268,12 +3292,14 @@ dependencies = [ "flate2", "futures", "getrandom 0.2.15", + "hex", "http", "http-body", "http-body-util", "httpmock", "hyper", "indexmap 2.12.1", + "itoa", "libdd-capabilities", "libdd-capabilities-impl", "libdd-common", @@ -3288,6 +3314,7 @@ dependencies = [ "rmpv", "rustc-hash 2.1.3", "serde", + "serde-transcode", "serde_json", "tempfile", "thin-vec", @@ -4028,12 +4055,6 @@ version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" -[[package]] -name = "pin-utils" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" - [[package]] name = "pkg-config" version = "0.3.32" @@ -4104,7 +4125,7 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "059a34f111a9dee2ce1ac2826a68b24601c4298cfeb1a587c3cb493d5ab46f52" dependencies = [ - "libc 0.1.12", + "libc 0.2.186", "nix 0.30.1", ] @@ -4871,9 +4892,9 @@ checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f" [[package]] name = "rustls-webpki" -version = "0.103.9" +version = "0.103.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7df23109aa6c1567d1c575b9952556388da57401e4ace1d15f79eedad0d8f53" +checksum = "61c429a8649f110dddef65e2a5ad240f747e85f7758a6bccc7e5777bd33f756e" dependencies = [ "aws-lc-rs", "ring", @@ -5066,6 +5087,15 @@ dependencies = [ "serde", ] +[[package]] +name = "serde-transcode" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "590c0e25c2a5bb6e85bf5c1bce768ceb86b316e7a01bdf07d2cb4ec2271990e2" +dependencies = [ + "serde", +] + [[package]] name = "serde_bytes" version = "0.11.15" @@ -6376,6 +6406,16 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "web-time" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + [[package]] name = "webpki-root-certs" version = "1.0.6" diff --git a/Cargo.toml b/Cargo.toml index bf4ff93f4bb..22279e8baba 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,7 +33,15 @@ inherits = "release" # These are to satistfy the build with libdatadog as a path dependency inside # components-rs. There may be a better way to fix this, but I'm alreday two # tasks removed from what I'm trying to do, so pushing forward. +# +# Every dependency that a libdatadog crate inherits via `{ workspace = true }` +# must be declared here, because those crates resolve their workspace +# inheritance against this manifest when built as path dependencies. Keep this +# list in sync with libdatadog's own `[workspace.dependencies]`; libdatadog +# #2253 consolidated `anyhow`, `serde`, `tokio` and `tracing` to the workspace +# level, so they are mirrored here too. [workspace.dependencies] +anyhow = { version = "1.0", default-features = false } arc-swap = "1.7.1" hyper = { version = "1.6", features = [ "http1", @@ -44,6 +52,9 @@ hyper-util = { version = "0.1.10", features = [ "client", "client-legacy", ] } +serde = { version = "1.0", default-features = false } +tokio = { version = "1.36", default-features = false } +tracing = { version = "0.1", default-features = false } [workspace.lints] # empty for compat with libdatadog diff --git a/cbindgen.toml b/cbindgen.toml index 2d4ec6b3588..ad11ddb0444 100644 --- a/cbindgen.toml +++ b/cbindgen.toml @@ -24,6 +24,7 @@ rename_types = "PascalCase" "ZendString" = "_zend_string" "FILE" = "FILE" "EndpointConfig" = "ddog_crasht_EndpointConfig" +"Metadata" = "ddog_crasht_Metadata" "MaybeOwnedZendString" = "_zend_string *" [enum] diff --git a/components-rs/Cargo.toml b/components-rs/Cargo.toml index c4b8de1c341..7c78ff2cad6 100644 --- a/components-rs/Cargo.toml +++ b/components-rs/Cargo.toml @@ -23,6 +23,8 @@ libdd-data-pipeline = { path = "../libdatadog/libdd-data-pipeline" } libdd-tinybytes = { path = "../libdatadog/libdd-tinybytes" } libdd-trace-utils = { path = "../libdatadog/libdd-trace-utils" } libdd-trace-stats = { path = "../libdatadog/libdd-trace-stats" } +libdd-trace-protobuf = { path = "../libdatadog/libdd-trace-protobuf" } +libdd-crashtracker = { path = "../libdatadog/libdd-crashtracker", default-features = false, features = ["collector"] } libdd-crashtracker-ffi = { path = "../libdatadog/libdd-crashtracker-ffi", default-features = false, features = ["collector"] } libdd-library-config-ffi = { path = "../libdatadog/libdd-library-config-ffi", default-features = false } spawn_worker = { path = "../libdatadog/spawn_worker" } diff --git a/components-rs/common.h b/components-rs/common.h index 9a148cb5d8b..1fe7a60f93b 100644 --- a/components-rs/common.h +++ b/components-rs/common.h @@ -52,8 +52,6 @@ typedef struct ddog_Endpoint ddog_Endpoint; -typedef struct ddog_Tag ddog_Tag; - /** * Holds the raw parts of a Rust Vec; it should only be created from Rust, * never from C. @@ -412,8 +410,11 @@ typedef enum ddog_RemoteConfigCapabilities { DDOG_REMOTE_CONFIG_CAPABILITIES_APM_TRACING_ENABLE_LIVE_DEBUGGING = 41, DDOG_REMOTE_CONFIG_CAPABILITIES_ASM_DD_MULTICONFIG = 42, DDOG_REMOTE_CONFIG_CAPABILITIES_ASM_TRACE_TAGGING_RULES = 43, + DDOG_REMOTE_CONFIG_CAPABILITIES_ASM_EXTENDED_DATA_COLLECTION = 44, DDOG_REMOTE_CONFIG_CAPABILITIES_APM_TRACING_MULTICONFIG = 45, DDOG_REMOTE_CONFIG_CAPABILITIES_FFE_FLAG_CONFIGURATION_RULES = 46, + DDOG_REMOTE_CONFIG_CAPABILITIES_DD_DATA_STREAMS_TRANSACTION_EXTRACTORS = 47, + DDOG_REMOTE_CONFIG_CAPABILITIES_LLM_OBS_ACTIVATION = 48, } ddog_RemoteConfigCapabilities; typedef enum ddog_RemoteConfigProduct { @@ -426,6 +427,7 @@ typedef enum ddog_RemoteConfigProduct { DDOG_REMOTE_CONFIG_PRODUCT_ASM_FEATURES, DDOG_REMOTE_CONFIG_PRODUCT_FFE_FLAGS, DDOG_REMOTE_CONFIG_PRODUCT_LIVE_DEBUGGER, + DDOG_REMOTE_CONFIG_PRODUCT_LIVE_DEBUGGER_SYMBOL_DB, } ddog_RemoteConfigProduct; typedef enum ddog_SpanProbeTarget { @@ -1110,9 +1112,10 @@ typedef struct ddog_TelemetryWorkerBuilder ddog_TelemetryWorkerBuilder; * The worker won't send data to the agent until you call `TelemetryWorkerHandle::send_start` * * To stop the worker, call `TelemetryWorkerHandle::send_stop` which trigger flush asynchronously - * then `TelemetryWorkerHandle::wait_for_shutdown` + * then `TelemetryWorkerHandle::wait_for_shutdown` (native only — wasm callers rely on the + * SharedRuntime worker JoinHandle instead). */ -typedef struct ddog_TelemetryWorkerHandle ddog_TelemetryWorkerHandle; +typedef struct ddog_TelemetryWorkerHandle_NativeCapabilities ddog_TelemetryWorkerHandle_NativeCapabilities; typedef enum ddog_Option_U64_Tag { DDOG_OPTION_U64_SOME_U64, @@ -1128,6 +1131,12 @@ typedef struct ddog_Option_U64 { }; } ddog_Option_U64; +/** + * FFI-facing alias: the C ABI surface is native-only, so the worker handle is + * always pinned to [`NativeCapabilities`]. + */ +typedef struct ddog_TelemetryWorkerHandle_NativeCapabilities ddog_TelemetryWorkerHandle; + typedef enum ddog_Option_Bool_Tag { DDOG_OPTION_BOOL_SOME_BOOL, DDOG_OPTION_BOOL_NONE_BOOL, diff --git a/components-rs/datadog.h b/components-rs/datadog.h index a1ed98a082b..21c7f656fe4 100644 --- a/components-rs/datadog.h +++ b/components-rs/datadog.h @@ -55,9 +55,26 @@ struct ddog_Endpoint *datadog_otel_metrics_endpoint_from_url(ddog_CharSlice url) struct ddog_Endpoint *datadog_otel_metrics_endpoint_from_agent_url(ddog_CharSlice url); -void datadog_endpoint_as_crashtracker_config(const struct ddog_Endpoint *endpoint, - void (*callback)(ddog_crasht_EndpointConfig, void*), - void *userdata); +/** + * Initialize crashtracking, selecting the receiver strategy for this process: + * - Linux, sidecar host (`master_pid == getpid()`): the in-process thread-mode sidecar can't + * serve its own crash, so spawn a fork+exec subprocess receiver (like the standalone daemon), + * resolving frames there since a crashing process can't reliably symbolize itself. + * - Linux, worker/collector: connect to the sidecar IPC socket and upgrade it to a crashtracker + * receiver on crash (`SOCK_SEQPACKET` + `enter_crashtracker_receiver`), streaming the report + * over that single socket and resolving frames in-process. + * - other unix (macOS): no sidecar upgrade; the default connector reaches the socket path. + * + * `master_pid` is the thread-mode master listener PID (0 if none): it keys the IPC socket and, on + * Linux, distinguishes the host from a worker. + * + * # Safety + * `endpoint` must point to a valid `Endpoint`; `metadata`'s borrowed strings/tags must outlive the + * call (they are copied into owned storage before it returns). + */ +ddog_MaybeError datadog_crashtracker_init(const struct ddog_Endpoint *endpoint, + ddog_crasht_Metadata metadata, + int32_t master_pid); ddog_Configurator *ddog_library_configurator_new_dummy(bool debug_logs, ddog_CharSlice language); @@ -189,7 +206,12 @@ void ddog_rshutdown_remote_config(struct ddog_RemoteConfigState *remote_config); void ddog_shutdown_remote_config(struct ddog_RemoteConfigState*); -void ddog_drop_probe(struct ddog_Probe probe); +/** + * Free the FFI-owned allocations in a `Probe` (the `tags` vec and the nested + * span-decoration / log allocations) by consuming it; borrowed `CharSlice`s are + * left untouched. Called from `dd_probe_dtor` when a probe is uninstalled. + */ +void ddog_drop_probe(struct ddog_Probe); void ddog_log_debugger_data(const struct ddog_Vec_DebuggerPayload *payloads); diff --git a/components-rs/lib.rs b/components-rs/lib.rs index f73beec72d2..a787ca9d1c1 100644 --- a/components-rs/lib.rs +++ b/components-rs/lib.rs @@ -22,7 +22,8 @@ use std::ffi::{c_char, OsStr}; use std::path::Path; use std::ptr::null_mut; use uuid::Uuid; - +#[cfg(unix)] +use datadog_sidecar::crashtracker::crashtracker_receiver_request_bytes; pub use libdd_crashtracker_ffi::*; pub use libdd_library_config_ffi::*; pub use datadog_sidecar_ffi::*; @@ -196,26 +197,144 @@ pub unsafe extern "C" fn datadog_otel_metrics_endpoint_from_agent_url(url: CharS } } -#[no_mangle] +/// Initialize crashtracking, selecting the receiver strategy for this process: +/// - Linux, sidecar host (`master_pid == getpid()`): the in-process thread-mode sidecar can't +/// serve its own crash, so spawn a fork+exec subprocess receiver (like the standalone daemon), +/// resolving frames there since a crashing process can't reliably symbolize itself. +/// - Linux, worker/collector: connect to the sidecar IPC socket and upgrade it to a crashtracker +/// receiver on crash (`SOCK_SEQPACKET` + `enter_crashtracker_receiver`), streaming the report +/// over that single socket and resolving frames in-process. +/// - other unix (macOS): no sidecar upgrade; the default connector reaches the socket path. +/// +/// `master_pid` is the thread-mode master listener PID (0 if none): it keys the IPC socket and, on +/// Linux, distinguishes the host from a worker. +/// +/// # Safety +/// `endpoint` must point to a valid `Endpoint`; `metadata`'s borrowed strings/tags must outlive the +/// call (they are copied into owned storage before it returns). #[cfg(unix)] -pub unsafe extern "C" fn datadog_endpoint_as_crashtracker_config( +#[no_mangle] +#[allow(clippy::missing_safety_doc)] +pub unsafe extern "C" fn datadog_crashtracker_init( endpoint: &Endpoint, - callback: unsafe extern "C" fn(EndpointConfig<'_>, *mut std::ffi::c_void), - userdata: *mut std::ffi::c_void, -) { - let url_str = endpoint.url.to_string(); - unsafe { - callback( - EndpointConfig { - url: CharSlice::from(url_str.as_str()), - api_key: CharSlice::from(endpoint.api_key.as_deref().unwrap_or("")), - test_token: CharSlice::from(endpoint.test_token.as_deref().unwrap_or("")), - timeout: endpoint.timeout_ms, - use_system_resolver: endpoint.use_system_resolver, - }, - userdata, - ); + metadata: Metadata, + master_pid: i32, +) -> MaybeError { + use libdd_crashtracker::{CrashtrackerConfiguration, StacktraceCollection}; + + let result = (|| -> anyhow::Result<()> { + let metadata: libdd_crashtracker::Metadata = metadata.try_into()?; + + let mut builder = CrashtrackerConfiguration::builder() + .collect_all_threads(true) + .timeout(std::time::Duration::from_millis(5000)) + .endpoint_use_system_resolver(endpoint.use_system_resolver) + .endpoint_url(&endpoint.url.to_string()); + if let Some(api_key) = endpoint.api_key.as_deref() { + builder = builder.endpoint_api_key(api_key); + } + if let Some(test_token) = endpoint.test_token.as_deref() { + builder = builder.endpoint_test_token(test_token); + } + if endpoint.timeout_ms != 0 { + builder = builder.endpoint_timeout_ms(endpoint.timeout_ms); + } + + #[cfg(target_os = "linux")] + { + // Worker/collector: open a fresh connection to the sidecar IPC socket, upgrade it with + // the SEQPACKET connector, and resolve frames in-process. + if master_pid == 0 || master_pid != std::process::id() as i32 { + let socket_path = datadog_sidecar::crashtracker::crashtracker_ipc_socket_path( + master_pid as u32, + datadog_sidecar::config::FromEnv::ipc_mode(), + ); + // Prime the request bytes outside the crash handler so the connector never + // allocates in signal context. + let _ = crashtracker_receiver_request_bytes(); + let config = builder + .resolve_frames(StacktraceCollection::EnabledWithInprocessSymbols) + .unix_socket_path(socket_path.to_string_lossy().into_owned()) + .unix_socket_connector( + datadog_sidecar::crashtracker::connect_to_sidecar_receiver, + ) + .build()?; + return libdd_crashtracker::init( + config, + libdd_crashtracker::CrashtrackerReceiverConfig::default(), + metadata, + ); + } + // Thread-mode host: its in-process sidecar can't serve its own crash, so spawn a + // transient fork+exec subprocess receiver and resolve frames there. + let config = builder + .resolve_frames(StacktraceCollection::EnabledWithSymbolsInReceiver) + .build()?; + let receiver_config = + datadog_sidecar::build_crashtracker_receiver_config(None, None)?; + libdd_crashtracker::init(config, receiver_config, metadata) + } + + // macOS can't open a fresh SOCK_SEQPACKET connection signal-safely, so reuse the + // already-open sidecar fd and upgrade it at crash time (no-op if there's no connection). + // The path is a placeholder the connector ignores; it just has to be non-empty so the + // crashtracker takes the connector path. + #[cfg(target_os = "macos")] + { + // Prime the request bytes outside the crash handler so the connector never + // allocates in signal context. + let _ = crashtracker_receiver_request_bytes(); + let config = builder + .resolve_frames(StacktraceCollection::EnabledWithInprocessSymbols) + .unix_socket_path("datadog-sidecar-crashtracker".to_string()) + .unix_socket_connector(reuse_sidecar_fd_connector) + .build()?; + libdd_crashtracker::init( + config, + libdd_crashtracker::CrashtrackerReceiverConfig::default(), + metadata, + ) + } + + #[cfg(not(any(target_os = "linux", target_os = "macos")))] + { + let _ = (master_pid, builder, metadata); + Ok(()) + } + })(); + match result { + Ok(()) => MaybeError::None, + Err(e) => { + MaybeError::Some(Error::from(format!("{e:?}"))) + } + } +} + +/// On macos we cannot easily create a new signal safe connection to the sidecar, so we reuse the +/// already open fd from datadog_sidecar_for_signal. +#[cfg(target_os = "macos")] +fn reuse_sidecar_fd_connector(_unix_socket_path: &str) -> std::os::fd::RawFd { + extern "C" { + // Set by the sidecar connect path (sidecar.c) to the live transport for best-effort + // signal-handler use; null when there is no connection. The transport pointer is stable + // across transparent reconnects (only its inner sender is swapped), so reading the fd + // through it stays current. Typed as an opaque pointer to keep the `extern` block FFI-safe; + // cast to the real type below. + static mut datadog_sidecar_for_signal: *mut std::ffi::c_void; + } + + // Best-effort, signal context: read the transport pointer and get its current fd via + // SidecarTransport::signal_fd (which uses get_mut, never locking). Going through the raw + // pointer knowingly bypasses aliasing checks — the crashing thread is the only realistic + // accessor. + let transport = unsafe { datadog_sidecar_for_signal } + as *mut datadog_sidecar::service::blocking::SidecarTransport; + if transport.is_null() { + return -1; } + let fd = unsafe { (*transport).as_raw_fd() }; + let bytes = crashtracker_receiver_request_bytes(); + let sent = unsafe { libc::send(dup, bytes.as_ptr() as *const libc::c_void, bytes.len(), 0) }; } // Hack: Without this, the PECL build of the tracer does not contain the ddog_library_* functions diff --git a/components-rs/php_sidecar_mockgen/mock_php.shared_lib b/components-rs/php_sidecar_mockgen/mock_php.shared_lib new file mode 100755 index 00000000000..44c5c154629 Binary files /dev/null and b/components-rs/php_sidecar_mockgen/mock_php.shared_lib differ diff --git a/components-rs/remote_config.rs b/components-rs/remote_config.rs index 51e2c575d73..fe60fef2aae 100644 --- a/components-rs/remote_config.rs +++ b/components-rs/remote_config.rs @@ -650,13 +650,13 @@ pub extern "C" fn ddog_remote_configs_service_env_change( tags: &libdd_common_ffi::Vec, process_tags: &libdd_common_ffi::Vec, ) -> bool { - let new_target = Target { - service: service.to_utf8_lossy().to_string(), - env: env.to_utf8_lossy().to_string(), - app_version: version.to_utf8_lossy().to_string(), - tags: tags.as_slice().to_vec(), - process_tags: process_tags.as_slice().to_vec(), - }; + let new_target = Target::new( + service.to_utf8_lossy().to_string(), + env.to_utf8_lossy().to_string(), + version.to_utf8_lossy().to_string(), + tags.as_slice().iter().map(|t| t.to_string()).collect(), + process_tags.as_slice().iter().map(|t| t.to_string()).collect(), + ); if let Some(target) = remote_config.manager.get_target() { if **target == new_target { @@ -798,7 +798,7 @@ pub unsafe extern "C" fn ddog_send_debugger_diagnostics<'a>( remote_config_state .manager .get_target() - .map_or("", |t| t.service.as_str()), + .map_or("", |t| t.service()), ); let mut payload = ddog_debugger_diagnostics_create_unboxed( probe, diff --git a/components-rs/sidecar.h b/components-rs/sidecar.h index 14c3b0c6c8c..de6df3cb550 100644 --- a/components-rs/sidecar.h +++ b/components-rs/sidecar.h @@ -442,11 +442,6 @@ ddog_MaybeError ddog_sidecar_set_test_session_token(struct ddog_SidecarTransport void ddog_sidecar_reconnect(struct ddog_SidecarTransport **transport, struct ddog_SidecarTransport *(*factory)(void)); -/** - * Return the path of the crashtracker unix domain socket. - */ -ddog_CharSlice ddog_sidecar_get_crashtracker_unix_socket_path(void); - /** * Gets an agent info reader. */ diff --git a/components-rs/stats.rs b/components-rs/stats.rs index e2e831c48e9..f09cb9a9354 100644 --- a/components-rs/stats.rs +++ b/components-rs/stats.rs @@ -11,6 +11,7 @@ use crate::trace_filter; use datadog_ipc::shm_stats::{OwnedShmSpanInput, ShmSpanConcentrator, ShmSpanInput, MAX_PEER_TAGS}; use datadog_sidecar::service::blocking::{add_span_to_concentrator, SidecarTransport}; use libdd_trace_stats::span_concentrator::FixedAggregationKey; +use libdd_trace_protobuf::pb::Trilean; use libdd_common_ffi::slice::{AsBytes, CharSlice}; use std::collections::HashMap; use std::ffi::{c_char, c_void}; @@ -148,7 +149,7 @@ fn build_fixed_key<'a>(span: &'a PhpSpanStats<'a>) -> FixedAggregationKey<&'a st http_endpoint: extract_http_endpoint(span), http_status_code: extract_http_status_code(span), is_synthetics_request: is_synthetics_request(span), - is_trace_root: span.is_trace_root, + is_trace_root: if span.is_trace_root { Trilean::True } else { Trilean::False }, grpc_status_code: extract_grpc_status_code(span), service_source: char_slice_str(span.service_source), } diff --git a/components-rs/telemetry.h b/components-rs/telemetry.h index eec7db11e79..0e818ddc0fc 100644 --- a/components-rs/telemetry.h +++ b/components-rs/telemetry.h @@ -52,7 +52,7 @@ ddog_MaybeError ddog_telemetry_builder_with_config(struct ddog_TelemetryWorkerBu * * handle should be a non null pointer to a null pointer */ ddog_MaybeError ddog_telemetry_builder_run(struct ddog_TelemetryWorkerBuilder *builder, - struct ddog_TelemetryWorkerHandle **out_handle); + ddog_TelemetryWorkerHandle **out_handle); /** * Builds the telemetry worker and return a handle to it. The worker will only process and send @@ -63,13 +63,23 @@ ddog_MaybeError ddog_telemetry_builder_run(struct ddog_TelemetryWorkerBuilder *b * * handle should be a non null pointer to a null pointer */ ddog_MaybeError ddog_telemetry_builder_run_metric_logs(struct ddog_TelemetryWorkerBuilder *builder, - struct ddog_TelemetryWorkerHandle **out_handle); + ddog_TelemetryWorkerHandle **out_handle); +/** + * Sets the telemetry endpoint from its component parts. + * + * * `api_key` / `test_token`: ignored when empty. + * * `timeout_ms`: pass 0 to keep the existing/default timeout. + */ ddog_MaybeError ddog_telemetry_builder_with_endpoint_config_endpoint(struct ddog_TelemetryWorkerBuilder *telemetry_builder, - const struct ddog_Endpoint *endpoint); + ddog_CharSlice url, + ddog_CharSlice api_key, + uint64_t timeout_ms, + ddog_CharSlice test_token, + bool use_system_resolver); /** - * Sets a property from it's string value. + * Sets the endpoint property from its component parts. * * Available properties: * @@ -77,10 +87,14 @@ ddog_MaybeError ddog_telemetry_builder_with_endpoint_config_endpoint(struct ddog */ ddog_MaybeError ddog_telemetry_builder_with_property_endpoint(struct ddog_TelemetryWorkerBuilder *telemetry_builder, enum ddog_TelemetryWorkerBuilderEndpointProperty _property, - const struct ddog_Endpoint *endpoint); + ddog_CharSlice url, + ddog_CharSlice api_key, + uint64_t timeout_ms, + ddog_CharSlice test_token, + bool use_system_resolver); /** - * Sets a property from it's string value. + * Sets a named endpoint property from its component parts. * * Available properties: * @@ -88,7 +102,11 @@ ddog_MaybeError ddog_telemetry_builder_with_property_endpoint(struct ddog_Teleme */ ddog_MaybeError ddog_telemetry_builder_with_endpoint_named_property(struct ddog_TelemetryWorkerBuilder *telemetry_builder, ddog_CharSlice property, - const struct ddog_Endpoint *endpoint); + ddog_CharSlice url, + ddog_CharSlice api_key, + uint64_t timeout_ms, + ddog_CharSlice test_token, + bool use_system_resolver); ddog_MaybeError ddog_telemetry_builder_with_str_application_service_version(struct ddog_TelemetryWorkerBuilder *telemetry_builder, ddog_CharSlice param); @@ -239,11 +257,11 @@ ddog_MaybeError ddog_telemetry_builder_with_bool_named_property(struct ddog_Tele ddog_CharSlice property, bool param); -ddog_MaybeError ddog_telemetry_handle_add_dependency(const struct ddog_TelemetryWorkerHandle *handle, +ddog_MaybeError ddog_telemetry_handle_add_dependency(const ddog_TelemetryWorkerHandle *handle, ddog_CharSlice dependency_name, ddog_CharSlice dependency_version); -ddog_MaybeError ddog_telemetry_handle_add_integration(const struct ddog_TelemetryWorkerHandle *handle, +ddog_MaybeError ddog_telemetry_handle_add_integration(const ddog_TelemetryWorkerHandle *handle, ddog_CharSlice dependency_name, ddog_CharSlice dependency_version, bool enabled, @@ -256,33 +274,33 @@ ddog_MaybeError ddog_telemetry_handle_add_integration(const struct ddog_Telemetr * * stack_trace: stack trace associated with the log. If no stack trace is available, an empty * string should be passed */ -ddog_MaybeError ddog_telemetry_handle_add_log(const struct ddog_TelemetryWorkerHandle *handle, +ddog_MaybeError ddog_telemetry_handle_add_log(const ddog_TelemetryWorkerHandle *handle, ddog_CharSlice indentifier, ddog_CharSlice message, enum ddog_LogLevel level, ddog_CharSlice stack_trace); -ddog_MaybeError ddog_telemetry_handle_start(const struct ddog_TelemetryWorkerHandle *handle); +ddog_MaybeError ddog_telemetry_handle_start(const ddog_TelemetryWorkerHandle *handle); -struct ddog_TelemetryWorkerHandle *ddog_telemetry_handle_clone(const struct ddog_TelemetryWorkerHandle *handle); +ddog_TelemetryWorkerHandle *ddog_telemetry_handle_clone(const ddog_TelemetryWorkerHandle *handle); -ddog_MaybeError ddog_telemetry_handle_stop(const struct ddog_TelemetryWorkerHandle *handle); +ddog_MaybeError ddog_telemetry_handle_stop(const ddog_TelemetryWorkerHandle *handle); /** * * compatible: should be false if the metric is language specific, true otherwise */ -struct ddog_ContextKey ddog_telemetry_handle_register_metric_context(const struct ddog_TelemetryWorkerHandle *handle, +struct ddog_ContextKey ddog_telemetry_handle_register_metric_context(const ddog_TelemetryWorkerHandle *handle, ddog_CharSlice name, enum ddog_MetricType metric_type, struct ddog_Vec_Tag tags, bool common, enum ddog_MetricNamespace namespace_); -ddog_MaybeError ddog_telemetry_handle_add_point(const struct ddog_TelemetryWorkerHandle *handle, +ddog_MaybeError ddog_telemetry_handle_add_point(const ddog_TelemetryWorkerHandle *handle, const struct ddog_ContextKey *context_key, double value); -ddog_MaybeError ddog_telemetry_handle_add_point_with_tags(const struct ddog_TelemetryWorkerHandle *handle, +ddog_MaybeError ddog_telemetry_handle_add_point_with_tags(const ddog_TelemetryWorkerHandle *handle, const struct ddog_ContextKey *context_key, double value, struct ddog_Vec_Tag extra_tags); @@ -290,18 +308,18 @@ ddog_MaybeError ddog_telemetry_handle_add_point_with_tags(const struct ddog_Tele /** * This function takes ownership of the handle. It should not be used after calling it */ -void ddog_telemetry_handle_wait_for_shutdown(struct ddog_TelemetryWorkerHandle *handle); +void ddog_telemetry_handle_wait_for_shutdown(ddog_TelemetryWorkerHandle *handle); /** * This function takes ownership of the handle. It should not be used after calling it */ -void ddog_telemetry_handle_wait_for_shutdown_ms(struct ddog_TelemetryWorkerHandle *handle, +void ddog_telemetry_handle_wait_for_shutdown_ms(ddog_TelemetryWorkerHandle *handle, uint64_t wait_for_ms); /** * Drops the handle without waiting for shutdown. The worker will continue running in the * background until it exits by itself */ -void ddog_telemetry_handle_drop(struct ddog_TelemetryWorkerHandle *handle); +void ddog_telemetry_handle_drop(ddog_TelemetryWorkerHandle *handle); #endif /* DDOG_TELEMETRY_H */ diff --git a/ext/signals.c b/ext/signals.c index 7def8a44e8c..2432234f896 100644 --- a/ext/signals.c +++ b/ext/signals.c @@ -13,6 +13,7 @@ #include #include #include +#include // getpid / geteuid for crashtracker role selection #include "configuration.h" #include "datadog.h" @@ -26,6 +27,7 @@ #include #include #include +#include #if PHP_VERSION_ID >= 80000 #include @@ -53,7 +55,6 @@ // true globals; only modify in MINIT/MSHUTDOWN static stack_t dd_altstack; static struct sigaction dd_sigsegv_sigaction; -static char crashtracker_socket_path[100] = {0}; static char *dd_signal_async_stack; static size_t dd_signal_async_stack_size; @@ -114,17 +115,6 @@ static void dd_sigsegv_handler(int sig) { _Exit(128 + sig); } -static bool dd_crashtracker_check_result(ddog_VoidResult result, const char *msg) { - if (result.tag != DDOG_VOID_RESULT_OK) { - ddog_CharSlice error_msg = ddog_Error_message(&result.err); - LOG(ERROR, "%s : %.*s", msg, (int) error_msg.len, error_msg.ptr); - ddog_Error_drop(&result.err); - return false; - } - - return true; -} - #if PHP_VERSION_ID >= 80000 static zend_never_inline ZEND_COLD void dd_crasht_failed_tag_push( ddog_Error *err, @@ -235,54 +225,18 @@ static void dd_crasht_add_opcache_inis(ddog_Vec_Tag *tags) { #endif } -typedef struct { - ddog_crasht_Config config; - ddog_crasht_Metadata metadata; -} dd_crasht_init_args; - -static void dd_crasht_do_init(ddog_crasht_EndpointConfig endpoint_config, void *userdata) { - dd_crasht_init_args *args = (dd_crasht_init_args *)userdata; - args->config.endpoint = endpoint_config; - dd_crashtracker_check_result( - ddog_crasht_init_without_receiver(args->config, args->metadata), - "Cannot initialize CrashTracker" - ); -} - static void dd_init_crashtracker() { - ddog_CharSlice socket_path = ddog_sidecar_get_crashtracker_unix_socket_path(); - if (socket_path.len > sizeof(crashtracker_socket_path) - 1) { - LOG(ERROR, "Cannot initialize CrashTracker : the socket path is too long."); - free((void *) socket_path.ptr); - return; - } - - // Copy the string to a global buffer to avoid a use-after-free error - memcpy(crashtracker_socket_path, socket_path.ptr, socket_path.len); - crashtracker_socket_path[socket_path.len] = '\0'; - free((void *) socket_path.ptr); - socket_path.ptr = crashtracker_socket_path; - if (!datadog_endpoint) { return; } ddog_Vec_Tag tags = ddog_Vec_Tag_new(); dd_crasht_add_opcache_inis(&tags); + ddog_crasht_Metadata metadata = datadog_setup_crashtracking_metadata(&tags); - dd_crasht_init_args args = { - .config = { - .timeout_ms = 5000, - .resolve_frames = DDOG_CRASHT_STACKTRACE_COLLECTION_ENABLED_WITH_INPROCESS_SYMBOLS, - .optional_unix_socket_filename = socket_path, - .additional_files = {0}, - .collect_all_threads = true, - .max_threads = 0, // uses libdatadog default, which is 256 - }, - .metadata = datadog_setup_crashtracking_metadata(&tags), - }; - - datadog_endpoint_as_crashtracker_config(datadog_endpoint, dd_crasht_do_init, &args); + int32_t master_pid = datadog_sidecar_active_mode == DD_SIDECAR_CONNECTION_THREAD ? datadog_sidecar_master_pid : 0; + datadog_ffi_try("Cannot initialize CrashTracker", + datadog_crashtracker_init(datadog_endpoint, metadata, master_pid)); datadog_register_crashtracking_frames_collection(); diff --git a/libdatadog b/libdatadog index 6a6d4a535e9..43156bbe53c 160000 --- a/libdatadog +++ b/libdatadog @@ -1 +1 @@ -Subproject commit 6a6d4a535e9875a7b012ce3f00eb6929649c3fb5 +Subproject commit 43156bbe53c026fdeeaeb3777cb9d4054507a250 diff --git a/tests/ext/appsec/agentic_onboarding_test.inc b/tests/ext/appsec/agentic_onboarding_test.inc index 89adfc53d22..b8b5833eb0c 100644 --- a/tests/ext/appsec/agentic_onboarding_test.inc +++ b/tests/ext/appsec/agentic_onboarding_test.inc @@ -19,7 +19,7 @@ for ($i = 0; $i < 300; ++$i) { if (file_exists(__DIR__ . '/'.$id.'-telemetry.out')) { $batches = []; foreach (file(__DIR__ . '/'.$id.'-telemetry.out') as $l) { - if ($l) { + if ($l && $l[0] == '{') { $json = json_decode($l, true); if ($json) { if ($json["application"]["service_name"] == "background_sender-php-service" || $json["application"]["service_name"] == "datadog-ipc-helper") { diff --git a/tests/ext/appsec/sca_test.inc b/tests/ext/appsec/sca_test.inc index eae3fa26646..042a38d2956 100644 --- a/tests/ext/appsec/sca_test.inc +++ b/tests/ext/appsec/sca_test.inc @@ -19,7 +19,7 @@ for ($i = 0; $i < 300; ++$i) { if (file_exists(__DIR__ . '/'.$id.'-telemetry.out')) { $batches = []; foreach (file(__DIR__ . '/'.$id.'-telemetry.out') as $l) { - if ($l) { + if ($l && $l[0] == '{') { $json = json_decode($l, true); if ($json) { if ($json["application"]["service_name"] == "background_sender-php-service" || $json["application"]["service_name"] == "datadog-ipc-helper") { diff --git a/tests/ext/library_config/fleet_config.phpt b/tests/ext/library_config/fleet_config.phpt index 3078cf38996..d2d63bf07e5 100644 --- a/tests/ext/library_config/fleet_config.phpt +++ b/tests/ext/library_config/fleet_config.phpt @@ -42,7 +42,7 @@ for ($i = 0; $i < 100; ++$i) { ("us" . "leep")(100000); if (file_exists(__DIR__ . '/fleet-config-telemetry.out')) { foreach (file(__DIR__ . '/fleet-config-telemetry.out') as $l) { - if ($l) { + if ($l && $l[0] == '{') { $json = json_decode($l, true); $batch = $json["request_type"] == "message-batch" ? $json["payload"] : [$json]; foreach ($batch as $json) { diff --git a/tests/ext/library_config/local_config.phpt b/tests/ext/library_config/local_config.phpt index 0bd2b41fc21..5f7a2e6e773 100644 --- a/tests/ext/library_config/local_config.phpt +++ b/tests/ext/library_config/local_config.phpt @@ -42,7 +42,7 @@ for ($i = 0; $i < 100; ++$i) { ("us" . "leep")(100000); if (file_exists(__DIR__ . '/local-config-telemetry.out')) { foreach (file(__DIR__ . '/local-config-telemetry.out') as $l) { - if ($l) { + if ($l && $l[0] == '{') { $json = json_decode($l, true); $batch = $json["request_type"] == "message-batch" ? $json["payload"] : [$json]; foreach ($batch as $json) { diff --git a/tests/ext/telemetry/broken_pipe.phpt b/tests/ext/telemetry/broken_pipe.phpt index 425770418ca..d4686176cf6 100644 --- a/tests/ext/telemetry/broken_pipe.phpt +++ b/tests/ext/telemetry/broken_pipe.phpt @@ -38,7 +38,7 @@ for ($i = 0; $i < 300; ++$i) { if (file_exists(__DIR__ . '/broken_pipe-telemetry.out')) { $batches = []; foreach (file(__DIR__ . '/broken_pipe-telemetry.out') as $l) { - if ($l) { + if ($l && $l[0] == '{') { $json = json_decode($l, true); if ($json["application"]["service_name"] == "background_sender-php-service" || $json["application"]["service_name"] == "datadog-ipc-helper") { continue; diff --git a/tests/ext/telemetry/composer.phpt b/tests/ext/telemetry/composer.phpt index 3edf95a73d9..700c95dc282 100644 --- a/tests/ext/telemetry/composer.phpt +++ b/tests/ext/telemetry/composer.phpt @@ -27,7 +27,7 @@ for ($i = 0; $i < 300; ++$i) { ("us" . "leep")(100000); if (file_exists(__DIR__ . '/composer-telemetry.out')) { foreach (file(__DIR__ . '/composer-telemetry.out') as $l) { - if ($l) { + if ($l && $l[0] == '{') { $json = json_decode($l, true); $batch = $json["request_type"] == "message-batch" ? $json["payload"] : [$json]; foreach ($batch as $json) { diff --git a/tests/ext/telemetry/config.phpt b/tests/ext/telemetry/config.phpt index fdebcc03fb4..007f2722aeb 100644 --- a/tests/ext/telemetry/config.phpt +++ b/tests/ext/telemetry/config.phpt @@ -42,7 +42,7 @@ for ($i = 0; $i < 300; ++$i) { ("us" . "leep")(100000); if (file_exists(__DIR__ . '/config-telemetry.out')) { foreach (file(__DIR__ . '/config-telemetry.out') as $l) { - if ($l) { + if ($l && $l[0] == '{') { $json = json_decode($l, true); $batch = $json["request_type"] == "message-batch" ? $json["payload"] : [$json]; foreach ($batch as $json) { diff --git a/tests/ext/telemetry/disabled.phpt b/tests/ext/telemetry/disabled.phpt index 606c412925d..757758a22cd 100644 --- a/tests/ext/telemetry/disabled.phpt +++ b/tests/ext/telemetry/disabled.phpt @@ -19,7 +19,7 @@ DDTrace\close_span(); dd_trace_internal_fn("finalize_telemetry"); usleep(100000); -var_dump(file_exists(__DIR__ . '/disabled-telemetry.out')); +var_dump(strpos(@file_get_contents(__DIR__ . '/disabled-telemetry.out') ?: "", "app-started")); ?> --EXPECT-- diff --git a/tests/ext/telemetry/integration.phpt b/tests/ext/telemetry/integration.phpt index 8e74be22933..cde1e21ad97 100644 --- a/tests/ext/telemetry/integration.phpt +++ b/tests/ext/telemetry/integration.phpt @@ -48,7 +48,7 @@ namespace ("us" . "leep")(100000); if (file_exists(__DIR__ . '/integration-telemetry.out')) { foreach (file(__DIR__ . '/integration-telemetry.out') as $l) { - if ($l) { + if ($l && $l[0] == '{') { $json = json_decode($l, true); $batch = $json["request_type"] == "message-batch" ? $json["payload"] : [$json]; foreach ($batch as $json) { diff --git a/tests/ext/telemetry/integration_filesystem_01.phpt b/tests/ext/telemetry/integration_filesystem_01.phpt index 1e27e3de854..3591fec5424 100644 --- a/tests/ext/telemetry/integration_filesystem_01.phpt +++ b/tests/ext/telemetry/integration_filesystem_01.phpt @@ -25,7 +25,7 @@ namespace usleep(100000); if (file_exists($file )) { foreach (file($file) as $l) { - if ($l) { + if ($l && $l[0] == '{') { $json = json_decode($l, true); $batch = $json["request_type"] == "message-batch" ? $json["payload"] : [$json]; foreach ($batch as $json) { diff --git a/tests/ext/telemetry/integration_filesystem_02.phpt b/tests/ext/telemetry/integration_filesystem_02.phpt index 1a3fa6930f6..685626318db 100644 --- a/tests/ext/telemetry/integration_filesystem_02.phpt +++ b/tests/ext/telemetry/integration_filesystem_02.phpt @@ -25,7 +25,7 @@ namespace usleep(100000); if (file_exists($file )) { foreach (file($file) as $l) { - if ($l) { + if ($l && $l[0] == '{') { $json = json_decode($l, true); $batch = $json["request_type"] == "message-batch" ? $json["payload"] : [$json]; foreach ($batch as $json) { diff --git a/tests/ext/telemetry/integration_filesystem_03.phpt b/tests/ext/telemetry/integration_filesystem_03.phpt index c1abac3f0df..61275011d1a 100644 --- a/tests/ext/telemetry/integration_filesystem_03.phpt +++ b/tests/ext/telemetry/integration_filesystem_03.phpt @@ -27,7 +27,7 @@ namespace usleep(100000); if (file_exists($file )) { foreach (file($file) as $l) { - if ($l) { + if ($l && $l[0] == '{') { $json = json_decode($l, true); $batch = $json["request_type"] == "message-batch" ? $json["payload"] : [$json]; foreach ($batch as $json) { diff --git a/tests/ext/telemetry/integration_filesystem_04.phpt b/tests/ext/telemetry/integration_filesystem_04.phpt index a8eb145e9ac..16fe5991cfb 100644 --- a/tests/ext/telemetry/integration_filesystem_04.phpt +++ b/tests/ext/telemetry/integration_filesystem_04.phpt @@ -25,7 +25,7 @@ namespace usleep(100000); if (file_exists($file )) { foreach (file($file) as $l) { - if ($l) { + if ($l && $l[0] == '{') { $json = json_decode($l, true); $batch = $json["request_type"] == "message-batch" ? $json["payload"] : [$json]; foreach ($batch as $json) { diff --git a/tests/ext/telemetry/integration_runtime_error.phpt b/tests/ext/telemetry/integration_runtime_error.phpt index 3a8a03aa35c..896e251df62 100644 --- a/tests/ext/telemetry/integration_runtime_error.phpt +++ b/tests/ext/telemetry/integration_runtime_error.phpt @@ -39,7 +39,7 @@ for ($i = 0; $i < 300; ++$i) { ("us" . "leep")(100000); if (file_exists(__DIR__ . '/integration-runtime-error-telemetry.out')) { foreach (file(__DIR__ . '/integration-runtime-error-telemetry.out') as $l) { - if ($l) { + if ($l && $l[0] == '{') { $json = json_decode($l, true); $batch = $json["request_type"] == "message-batch" ? $json["payload"] : [$json]; foreach ($batch as $json) { diff --git a/tests/ext/telemetry/metrics_logs_created.phpt b/tests/ext/telemetry/metrics_logs_created.phpt index 16fb8bd8768..9769ca47128 100644 --- a/tests/ext/telemetry/metrics_logs_created.phpt +++ b/tests/ext/telemetry/metrics_logs_created.phpt @@ -24,7 +24,7 @@ for ($i = 0; $i < 300; ++$i) { ("us" . "leep")(100000); if (file_exists(__DIR__ . '/metrics-logs-created-telemetry.out')) { foreach (file(__DIR__ . '/metrics-logs-created-telemetry.out') as $l) { - if ($l) { + if ($l && $l[0] == '{') { $json = json_decode($l, true); if (($json["application"]["language_version"] ?? "") == "SIDECAR") { continue; diff --git a/tests/ext/telemetry/metrics_spans_created.phpt b/tests/ext/telemetry/metrics_spans_created.phpt index cf45f052ccc..c63ed2648dc 100644 --- a/tests/ext/telemetry/metrics_spans_created.phpt +++ b/tests/ext/telemetry/metrics_spans_created.phpt @@ -84,7 +84,7 @@ namespace ("us" . "leep")(100000); if (file_exists(__DIR__ . '/metrics-spans_created-telemetry.out')) { foreach (file(__DIR__ . '/metrics-spans_created-telemetry.out') as $l) { - if ($l) { + if ($l && $l[0] == '{') { $json = json_decode($l, true); if (($json["application"]["language_version"] ?? "") == "SIDECAR") { continue; diff --git a/tests/ext/telemetry/simple.phpt b/tests/ext/telemetry/simple.phpt index 2279f460f56..a11fc653ebd 100644 --- a/tests/ext/telemetry/simple.phpt +++ b/tests/ext/telemetry/simple.phpt @@ -33,7 +33,7 @@ for ($i = 0; $i < 300; ++$i) { if (file_exists(__DIR__ . '/simple-telemetry.out')) { $batches = []; foreach (file(__DIR__ . '/simple-telemetry.out') as $l) { - if ($l) { + if ($l && $l[0] == '{') { $json = json_decode($l, true); if ($json["application"]["service_name"] == "background_sender-php-service" || $json["application"]["service_name"] == "datadog-ipc-helper") { continue; diff --git a/tests/ext/telemetry/telemetry_process_tags.phpt b/tests/ext/telemetry/telemetry_process_tags.phpt index 503ccf10c14..a92bbd44221 100644 --- a/tests/ext/telemetry/telemetry_process_tags.phpt +++ b/tests/ext/telemetry/telemetry_process_tags.phpt @@ -31,7 +31,7 @@ for ($i = 0; $i < 300; ++$i) { ("us" . "leep")(100000); if (file_exists(__DIR__ . '/process-tags-telemetry.out')) { foreach (file(__DIR__ . '/process-tags-telemetry.out') as $l) { - if ($l) { + if ($l && $l[0] == '{') { $json = json_decode($l, true); var_dump($json["application"]["process_tags"]); break 2;