From b82b5a54d8377456b7f7692f2b2909499961bbbf Mon Sep 17 00:00:00 2001 From: Alexandre Rulleau Date: Thu, 1 Oct 2026 18:01:47 +0200 Subject: [PATCH 1/5] feat(tracer): send traces as V1 payloads through the libdatadog builder FFI Serialize closed spans into a libdatadog TracerPayloadV1Builder (Box-per-node pointer handles) and send them to the sidecar as /v1.0/traces, with the sidecar negotiating /info and downgrading to v0.4 for agents that lack it. The in-process sender keeps the v0.4 wire, transcoded from the same builder. Span tags live in a single typed attributes store; SpanData::$meta and $metrics are views onto it. Process tags and the OTLP export marker are TracerPayload attributes (the v0.4 downgrade puts them on each chunk's first span), and span links and events carry native attributes. DD_TRACE_AGENT_PROTOCOL_VERSION=0.4 forces v0.4. Bump libdatadog to the V1 FFI branch and port components-rs to the new rate limiter API. --- Cargo.lock | 12 + Cargo.toml | 2 + Makefile | 2 +- appsec/src/extension/ddtrace.c | 38 +- appsec/src/extension/ddtrace.h | 4 +- components-rs/bytes.rs | 728 +++++++--- components-rs/common.h | 66 + components-rs/datadog.h | 100 +- components-rs/sidecar.h | 633 +++++++-- components-rs/sidecar.rs | 21 +- config.m4 | 1 + config.w32 | 1 + ext/agent_info.h | 1 + ext/compatibility.h | 12 +- ext/configuration.h | 7 + ext/ffi_utils.h | 7 +- ext/sidecar.c | 3 +- libdatadog | 2 +- metadata/supported-configurations.json | 18 +- tooling/generate-supported-configurations.sh | 4 - tracer/auto_flush.c | 82 +- tracer/code_origins.c | 16 +- tracer/coms.c | 1 + tracer/configuration.h | 7 +- tracer/configuration_dependencies.h | 13 + tracer/ddtrace.h | 1 + tracer/ddtrace.stub.php | 171 +-- tracer/ddtrace_arginfo.h | 440 +++--- tracer/distributed_tracing_headers.c | 9 +- tracer/endpoint_guessing.c | 11 +- tracer/exception_serialize.c | 28 +- tracer/exception_serialize.h | 2 +- tracer/functions.c | 251 +--- tracer/handlers_http.h | 2 +- tracer/handlers_httpstreams.c | 13 +- tracer/hook/uhook_attributes.c | 63 +- tracer/integrations/exec_integration.c | 9 +- tracer/live_debugger.c | 4 +- tracer/priority_sampling/priority_sampling.c | 47 +- tracer/serializer.c | 1240 +++++++++++------ tracer/serializer.h | 12 +- tracer/span.c | 39 +- tracer/span.h | 33 +- tracer/span_stats.c | 145 +- tracer/span_stats.h | 18 +- tracer/span_tags_view.c | 520 +++++++ tracer/span_tags_view.h | 19 + tracer/trace_filter.c | 40 +- tracer/trace_source.c | 4 +- .../tracer_tag_propagation.c | 12 +- .../tracer_tag_propagation.h | 2 + tracer/tracer_telemetry.c | 12 +- 52 files changed, 3439 insertions(+), 1489 deletions(-) create mode 100644 tracer/span_tags_view.c create mode 100644 tracer/span_tags_view.h diff --git a/Cargo.lock b/Cargo.lock index 08e4cb595f..89d12e7156 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1266,6 +1266,7 @@ dependencies = [ "rand_distr", "regex", "regex-automata", + "rmpv", "rustc-hash", "serde", "serde_json", @@ -2927,6 +2928,7 @@ dependencies = [ "regex", "rmp-serde", "serde", + "serde_ignored", "serde_json", "sha2", "tempfile", @@ -5368,6 +5370,16 @@ dependencies = [ "serde_core", ] +[[package]] +name = "serde_ignored" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "115dffd5f3853e06e746965a20dcbae6ee747ae30b543d91b0e089668bb07798" +dependencies = [ + "serde", + "serde_core", +] + [[package]] name = "serde_json" version = "1.0.150" diff --git a/Cargo.toml b/Cargo.toml index e547c26168..be47eae2e9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -126,6 +126,7 @@ cc = "1.0" [dev-dependencies] criterion = "0.5.1" static_assertions = "1" +rmpv = "1.3.0" [target.'cfg(target_arch = "x86_64")'.dev-dependencies] criterion-perf-events = "0.4.0" @@ -302,6 +303,7 @@ semver = { version = "1.0", default-features = false } serde = { version = "1.0", default-features = false } serde-transcode = { version = "1.1", default-features = false } serde_bytes = { version = "0.11.9", default-features = false } +serde_ignored = { version = "0.1.14", default-features = false } # allow(workspace-deps-features): serde_json requires at least one of `std` or # `alloc`. We set `alloc` here as the minimal working baseline, and to avoid # repeating alloc everywhere. Enabling `std` on top of it is fine. diff --git a/Makefile b/Makefile index ad3e24d8d8..0b0a8d52a2 100644 --- a/Makefile +++ b/Makefile @@ -1289,7 +1289,7 @@ define run_composer_with_retry endef define run_tests_without_coverage - $(TEST_EXTRA_ENV) $(ENV_OVERRIDE) php $(TEST_EXTRA_INI) -d datadog.instrumentation_telemetry_enabled=$(shell (test $(TELEMETRY_ENABLED) && echo 1) || (test $(PHP_MAJOR_MINOR) -ge 83 && echo 1) || echo 0) -d datadog.trace.sidecar_trace_sender=$(shell test $(PHP_MAJOR_MINOR) -ge 83 && echo 1 || echo 0) $(TRACER_SOURCES_INI) $(PHPUNIT) $(1) --filter=$(FILTER) + $(TEST_EXTRA_ENV) $(ENV_OVERRIDE) php $(TEST_EXTRA_INI) -d datadog.instrumentation_telemetry_enabled=$(shell (test $(TELEMETRY_ENABLED) && echo 1) || (test $(PHP_MAJOR_MINOR) -ge 83 && echo 1) || echo 0) $(TRACER_SOURCES_INI) $(PHPUNIT) $(1) --filter=$(FILTER) endef define run_tests_with_coverage diff --git a/appsec/src/extension/ddtrace.c b/appsec/src/extension/ddtrace.c index 5a009ffc1e..f38d8e6c2a 100644 --- a/appsec/src/extension/ddtrace.c +++ b/appsec/src/extension/ddtrace.c @@ -34,6 +34,7 @@ static int _mod_number; static const char *_mod_version; static bool _ddtrace_loaded; static zend_string *_ddtrace_root_span_fname; +static zend_string *_attributes_propname; static zend_string *_meta_propname; static zend_string *_metrics_propname; static zend_string *_meta_struct_propname; @@ -146,6 +147,7 @@ void dd_trace_startup(void) { _ddtrace_root_span_fname = zend_string_init_interned( LSTRARG("ddtrace\\root_span"), 1 /* permanent */); + _attributes_propname = zend_string_init_interned(LSTRARG("attributes"), 1); _meta_propname = zend_string_init_interned(LSTRARG("meta"), 1); _metrics_propname = zend_string_init_interned(LSTRARG("metrics"), 1); _meta_struct_propname = @@ -340,14 +342,30 @@ static zval *_get_span_modifiable_array_property( return res; } +// $meta and $metrics are views onto $attributes, the span's single tag store. zval *nullable dd_trace_span_get_meta(zend_object *nonnull zobj) { - return _get_span_modifiable_array_property(zobj, _meta_propname); + return _get_span_modifiable_array_property(zobj, _attributes_propname); } zval *nullable dd_trace_span_get_metrics(zend_object *nonnull zobj) { - return _get_span_modifiable_array_property(zobj, _metrics_propname); + return _get_span_modifiable_array_property(zobj, _attributes_propname); +} + +// Reads $meta/$metrics through the span's handlers: an array of that bucket. +static zval *_read_span_property( + zend_object *nonnull zobj, zend_string *nonnull propname, zval *nonnull rv) +{ +#if PHP_VERSION_ID >= 80000 + return zobj->handlers->read_property(zobj, propname, BP_VAR_R, NULL, rv); +#else + zval obj; + ZVAL_OBJ(&obj, zobj); + zval prop; + ZVAL_STR(&prop, propname); + return zobj->handlers->read_property(&obj, &prop, BP_VAR_R, NULL, rv); +#endif } zval *nullable dd_trace_span_get_meta_struct(zend_object *nonnull zobj) @@ -621,9 +639,11 @@ static PHP_FUNCTION(datadog_appsec_testing_root_span_get_meta) // NOLINT RETURN_NULL(); } - zval *meta_zv = dd_trace_span_get_meta(root_span); - if (meta_zv) { - RETURN_ZVAL(meta_zv, 1 /* copy */, 0 /* no destroy original */); + zval rv; + zval *meta_zv = _read_span_property(root_span, _meta_propname, &rv); + RETVAL_ZVAL(meta_zv, 1 /* copy */, 0 /* no destroy original */); + if (meta_zv == &rv) { + zval_ptr_dtor(&rv); } } @@ -655,9 +675,11 @@ static PHP_FUNCTION(datadog_appsec_testing_root_span_get_metrics) // NOLINT RETURN_NULL(); } - zval *metrics_zv = dd_trace_span_get_metrics(root_span); - if (metrics_zv) { - RETURN_ZVAL(metrics_zv, 1 /* copy */, 0 /* no destroy original */); + zval rv; + zval *metrics_zv = _read_span_property(root_span, _metrics_propname, &rv); + RETVAL_ZVAL(metrics_zv, 1 /* copy */, 0 /* no destroy original */); + if (metrics_zv == &rv) { + zval_ptr_dtor(&rv); } } diff --git a/appsec/src/extension/ddtrace.h b/appsec/src/extension/ddtrace.h index 632837a4d9..4552ad48cc 100644 --- a/appsec/src/extension/ddtrace.h +++ b/appsec/src/extension/ddtrace.h @@ -55,8 +55,8 @@ void dd_trace_close_all_spans_and_flush(void); void dd_trace_emit_asm_event(void); -// Provides the array zval representing $root_span->meta, if any. -// It is ready for modification, with refcount == 1 +// Provides the array zval representing $root_span->attributes (which $meta +// and $metrics are views onto), if any. Ready for modification, refcount == 1 zval *nullable dd_trace_span_get_meta(zend_object *nonnull); zval *nullable dd_trace_span_get_metrics(zend_object *nonnull); zval *nullable dd_trace_span_get_meta_struct(zend_object *nonnull); diff --git a/components-rs/bytes.rs b/components-rs/bytes.rs index 01e46de90b..c3a67b8b51 100644 --- a/components-rs/bytes.rs +++ b/components-rs/bytes.rs @@ -1,8 +1,8 @@ -use libdd_common_ffi::slice::{AsBytes, CharSlice}; +use datadog_sidecar_ffi::span::{attrs_mut, bytes_string_from_literal, Attributes, SpanNode}; +use libdd_common_ffi::slice::CharSlice; use libdd_tinybytes::{Bytes, BytesString, RefCountedCell, RefCountedCellVTable}; -use libdd_trace_utils::span::v04::SpanBytes; +use libdd_trace_utils::span::v1::AttributeValueBytes; use std::borrow::Cow; -use std::ffi::CStr; use std::os::raw::c_char; use std::ptr::NonNull; @@ -132,212 +132,616 @@ fn convert_zend_to_bytes_string(zend_str: &mut ZendString) -> BytesString { } } -fn convert_char_slice_to_bytes_string(slice: CharSlice) -> BytesString { - match String::from_utf8_lossy(slice.as_bytes().as_ref()) { - Cow::Owned(s) => s.into(), - Cow::Borrowed(_) => unsafe { - BytesString::from_bytes_unchecked(slice.as_bytes().to_vec().into()) - }, - } -} - -fn convert_literal_to_bytes_string(string: *const c_char) -> BytesString { - unsafe { - let cstring = CStr::from_ptr(string); - - match String::from_utf8_lossy(cstring.to_bytes()) { - Cow::Owned(s) => s.into(), - Cow::Borrowed(s) => BytesString::from_static(s), - } - } -} +// PHP-specific additions to the V1 builder FFI (`datadog_sidecar_ffi::span`): zero-copy +// zend_string fields and static C-literal keys. +/// # Safety +/// `span` must be a live span node pointer from `ddog_new_span` (every `*_zstr` span setter). #[no_mangle] -pub extern "C" fn ddog_set_span_service_zstr(ptr: &mut SpanBytes, str: &mut ZendString) { - ptr.service = convert_zend_to_bytes_string(str); +pub unsafe extern "C" fn ddog_set_span_service_zstr(span: *mut SpanNode, str: &mut ZendString) { + (*span).span_mut().service = convert_zend_to_bytes_string(str); } +/// # Safety +/// See [`ddog_set_span_service_zstr`]. #[no_mangle] -pub extern "C" fn ddog_set_span_name_zstr(ptr: &mut SpanBytes, str: &mut ZendString) { - ptr.name = convert_zend_to_bytes_string(str); +pub unsafe extern "C" fn ddog_set_span_name_zstr(span: *mut SpanNode, str: &mut ZendString) { + (*span).span_mut().name = convert_zend_to_bytes_string(str); } +/// # Safety +/// See [`ddog_set_span_service_zstr`]. #[no_mangle] -pub extern "C" fn ddog_set_span_resource_zstr(ptr: &mut SpanBytes, str: &mut ZendString) { - ptr.resource = convert_zend_to_bytes_string(str); +pub unsafe extern "C" fn ddog_set_span_resource_zstr(span: *mut SpanNode, str: &mut ZendString) { + (*span).span_mut().resource = convert_zend_to_bytes_string(str); } +/// # Safety +/// See [`ddog_set_span_service_zstr`]. #[no_mangle] -pub extern "C" fn ddog_set_span_type_zstr(ptr: &mut SpanBytes, str: &mut ZendString) { - ptr.r#type = convert_zend_to_bytes_string(str); +pub unsafe extern "C" fn ddog_set_span_type_zstr(span: *mut SpanNode, str: &mut ZendString) { + (*span).span_mut().r#type = convert_zend_to_bytes_string(str); } +/// String attribute under a static C literal key. +/// +/// # Safety +/// `attrs` must be a live `Attributes` handle and `key` a static NUL-terminated string (applies +/// to every attribute adder below). #[no_mangle] -pub extern "C" fn ddog_add_span_meta_zstr( - ptr: &mut SpanBytes, - key: &mut ZendString, - val: &mut ZendString, +pub unsafe extern "C" fn ddog_attributes_add_lit( + attrs: *mut Attributes, + key: *const c_char, + value: CharSlice, ) { - ptr.meta.insert( - convert_zend_to_bytes_string(key), - convert_zend_to_bytes_string(val), - ); + let value = AttributeValueBytes::String(datadog_sidecar_ffi::span::bytes_string_from_slice(value)); + attrs_mut(attrs).insert(bytes_string_from_literal(key), value); } +/// String attribute sharing both zend strings (zero-copy). +/// +/// # Safety +/// See [`ddog_attributes_add_lit`]. #[no_mangle] -pub extern "C" fn ddog_add_CharSlice_span_meta_zstr( - ptr: &mut SpanBytes, - key: CharSlice, - val: &mut ZendString, -) { - ptr.meta.insert( - convert_char_slice_to_bytes_string(key), - convert_zend_to_bytes_string(val), - ); -} - -#[no_mangle] -pub extern "C" fn ddog_add_zstr_span_meta_str( - ptr: &mut SpanBytes, +pub unsafe extern "C" fn ddog_attributes_add_zstr( + attrs: *mut Attributes, key: &mut ZendString, - val: *const c_char, + value: &mut ZendString, ) { - ptr.meta.insert( + attrs_mut(attrs).insert( convert_zend_to_bytes_string(key), - convert_literal_to_bytes_string(val), + AttributeValueBytes::String(convert_zend_to_bytes_string(value)), ); } +/// Double attribute under a static C literal key. +/// +/// # Safety +/// See [`ddog_attributes_add_lit`]. #[no_mangle] -pub extern "C" fn ddog_add_str_span_meta_str( - ptr: &mut SpanBytes, +pub unsafe extern "C" fn ddog_attributes_add_double_lit( + attrs: *mut Attributes, key: *const c_char, - val: *const c_char, + value: f64, ) { - ptr.meta.insert( - convert_literal_to_bytes_string(key), - convert_literal_to_bytes_string(val), - ); + attrs_mut(attrs).insert(bytes_string_from_literal(key), AttributeValueBytes::Float(value)); } +/// Double attribute under a shared zend string key (zero-copy). +/// +/// # Safety +/// See [`ddog_attributes_add_lit`]. #[no_mangle] -pub extern "C" fn ddog_add_str_span_meta_zstr( - ptr: &mut SpanBytes, - key: *const c_char, - val: &mut ZendString, +pub unsafe extern "C" fn ddog_attributes_add_double_zstr( + attrs: *mut Attributes, + key: &mut ZendString, + value: f64, ) { - ptr.meta.insert( - convert_literal_to_bytes_string(key), - convert_zend_to_bytes_string(val), - ); -} + attrs_mut(attrs).insert(convert_zend_to_bytes_string(key), AttributeValueBytes::Float(value)); +} + +#[cfg(test)] +mod v04_parity_tests { + // Wire-safety gate: the v0.4 downgrade of a NATIVE nested attribute carries the SAME dotted + // `meta` / `metrics` keys+values (and same meta-vs-metrics bucketing) the OLD C dotted flatten + // produced. Each case builds both shapes through the FFI, encodes both to v0.4, and compares the + // decoded `meta` / `metrics` maps order-insensitively — msgpack map key order is not significant + // for v0.4 consumers, and it is the only byte-level difference between the two encodings (it + // stems from `VecMap::dedup` reversing entries, which reorders nested vs flat topologies + // differently; list indices / map members are encoded in the dotted keys, so no data changes). + use datadog_sidecar_ffi::span::*; + use libdd_common_ffi::slice::CharSlice; + use libdd_trace_utils::msgpack_encoder::v04::to_vec_from_v1; + use libdd_trace_utils::span::v1::SpanKind; + use rmpv::Value; + + fn cs(s: &str) -> CharSlice<'_> { + CharSlice::from_bytes(s.as_bytes()) + } -#[no_mangle] -pub extern "C" fn ddog_add_str_span_meta_CharSlice( - ptr: &mut SpanBytes, - key: *const c_char, - val: CharSlice, -) { - ptr.meta.insert( - convert_literal_to_bytes_string(key), - convert_char_slice_to_bytes_string(val), - ); -} + fn one_span_builder() -> (TracerPayloadV1Builder, *mut SpanNode) { + let mut b = TracerPayloadV1Builder::default(); + let c = b.push_chunk(0, 1); + // Safety: `c` is the live chunk node just pushed. + let s = unsafe { (*c).push_span() }; + (b, s) + } -#[no_mangle] -pub extern "C" fn ddog_del_span_meta_zstr(ptr: &mut SpanBytes, key: &mut ZendString) { - ptr.meta.remove_slow(&convert_zend_to_bytes_string(key)); -} + /// Decodes v0.4 bytes (`[[span,...],...]`) and returns the first span's map. + fn first_span(bytes: &[u8]) -> Value { + match rmpv::decode::read_value(&mut &bytes[..]).expect("valid msgpack") { + Value::Array(traces) => match traces.into_iter().next().expect("one trace") { + Value::Array(spans) => spans.into_iter().next().expect("one span"), + other => panic!("trace not an array: {other:?}"), + }, + other => panic!("payload not an array: {other:?}"), + } + } -#[no_mangle] -pub extern "C" fn ddog_del_span_meta_str(ptr: &mut SpanBytes, key: *const c_char) { - ptr.meta.remove_slow(&convert_literal_to_bytes_string(key)); -} + /// Extracts `span[key]` (a `meta`/`metrics` map) as `(key, value)` pairs sorted by key, so two + /// encodings can be compared independently of msgpack map serialization order. + fn sorted_bucket(span: &Value, key: &str) -> Vec<(String, Value)> { + let entries = match span { + Value::Map(entries) => entries, + other => panic!("span not a map: {other:?}"), + }; + let mut out = Vec::new(); + if let Some((_, Value::Map(bucket))) = + entries.iter().find(|(k, _)| k.as_str() == Some(key)) + { + for (k, v) in bucket { + out.push((k.as_str().expect("string key").to_string(), v.clone())); + } + } + out.sort_by(|a, b| a.0.cmp(&b.0)); + out + } -#[no_mangle] -pub extern "C" fn ddog_has_span_meta_zstr(ptr: &mut SpanBytes, key: &mut ZendString) -> bool { - ptr.meta.contains_key(&convert_zend_to_bytes_string(key)) -} + #[test] + fn meta_nested_matches_old_flat_v04() { + // NEW: meta attr "m" = { bar: [ "1", { key: "2" }, "" ], "5": "v" } + // (String leaves, as the meta path stringifies — mirrors the old convert_to_double=false). + let (newb, s) = one_span_builder(); + unsafe { + let bar = ddog_attr_list_new(3); + ddog_attr_list_push_str(bar, cs("1")); + let e = ddog_attr_map_new(1); + ddog_attributes_add_str(ddog_attr_map_get_attributes(e), cs("key"), cs("2")); + ddog_attr_list_push_map(bar, e); + ddog_attr_list_push_str(bar, cs("")); // empty/recursive placeholder equivalent + let m = ddog_attr_map_new(2); + ddog_attributes_add_list(ddog_attr_map_get_attributes(m), cs("bar"), bar); + ddog_attributes_add_str(ddog_attr_map_get_attributes(m), cs("5"), cs("v")); // numeric-keyed member -> "m.5" + ddog_attributes_add_map(ddog_span_get_attributes(s), cs("m"), m); + } -#[no_mangle] -pub extern "C" fn ddog_has_span_meta_str(ptr: &mut SpanBytes, key: *const c_char) -> bool { - ptr.meta.contains_key(&convert_literal_to_bytes_string(key)) -} + // OLD: the identical dotted keys the C flatten wrote, in traversal order. + let (oldb, s) = one_span_builder(); + unsafe { + ddog_attributes_add_str(ddog_span_get_attributes(s), cs("m.bar.0"), cs("1")); + ddog_attributes_add_str(ddog_span_get_attributes(s), cs("m.bar.1.key"), cs("2")); + ddog_attributes_add_str(ddog_span_get_attributes(s), cs("m.bar.2"), cs("")); + ddog_attributes_add_str(ddog_span_get_attributes(s), cs("m.5"), cs("v")); + } -#[no_mangle] -pub extern "C" fn ddog_get_span_meta_str( - span: &mut SpanBytes, - key: *const c_char, -) -> CharSlice<'static> { - match span.meta.get(&convert_literal_to_bytes_string(key)) { - Some(value) => unsafe { - let string_value = value.as_str(); - CharSlice::from_raw_parts(string_value.as_ptr().cast(), string_value.len()) - }, - None => CharSlice::empty(), + let new_span = first_span(&to_vec_from_v1(&newb.into_payload())); + let old_span = first_span(&to_vec_from_v1(&oldb.into_payload())); + assert_eq!( + sorted_bucket(&new_span, "meta"), + sorted_bucket(&old_span, "meta"), + "v0.4 meta keys+values of native nesting must match the old flat dotted meta" + ); + assert_eq!(sorted_bucket(&new_span, "metrics"), sorted_bucket(&old_span, "metrics")); } -} -#[no_mangle] -pub extern "C" fn ddog_add_span_metrics_zstr(ptr: &mut SpanBytes, key: &mut ZendString, val: f64) { - ptr.metrics.insert(convert_zend_to_bytes_string(key), val); -} + #[test] + fn metrics_nested_matches_old_flat_v04() { + // NEW: metrics attr "mm" = { nums: [ 1.0, 2.5 ], deep: { x: 0.0 } } + // (Float leaves, as the metrics path uses zval_get_double -> convert_to_double=true.) + let (newb, s) = one_span_builder(); + unsafe { + let mm = ddog_attr_map_new(2); + let nums = ddog_attr_list_new(2); + ddog_attr_list_push_double(nums, 1.0); + ddog_attr_list_push_double(nums, 2.5); + ddog_attributes_add_list(ddog_attr_map_get_attributes(mm), cs("nums"), nums); + let deep = ddog_attr_map_new(1); + ddog_attributes_add_double(ddog_attr_map_get_attributes(deep), cs("x"), 0.0); // empty/recursive placeholder equivalent + ddog_attributes_add_map(ddog_attr_map_get_attributes(mm), cs("deep"), deep); + ddog_attributes_add_map(ddog_span_get_attributes(s), cs("mm"), mm); + } -#[no_mangle] -pub extern "C" fn ddog_has_span_metrics_zstr(ptr: &mut SpanBytes, key: &mut ZendString) -> bool { - ptr.metrics.contains_key(&convert_zend_to_bytes_string(key)) -} + let (oldb, s) = one_span_builder(); + unsafe { + ddog_attributes_add_double(ddog_span_get_attributes(s), cs("mm.nums.0"), 1.0); + ddog_attributes_add_double(ddog_span_get_attributes(s), cs("mm.nums.1"), 2.5); + ddog_attributes_add_double(ddog_span_get_attributes(s), cs("mm.deep.x"), 0.0); + } -#[no_mangle] -pub extern "C" fn ddog_del_span_metrics_zstr(ptr: &mut SpanBytes, key: &mut ZendString) { - ptr.metrics.remove_slow(&convert_zend_to_bytes_string(key)); -} + let new_span = first_span(&to_vec_from_v1(&newb.into_payload())); + let old_span = first_span(&to_vec_from_v1(&oldb.into_payload())); + assert_eq!( + sorted_bucket(&new_span, "metrics"), + sorted_bucket(&old_span, "metrics"), + "v0.4 metrics keys+values of native nesting must match the old flat dotted metrics" + ); + assert_eq!(sorted_bucket(&new_span, "meta"), sorted_bucket(&old_span, "meta")); + } -#[no_mangle] -pub extern "C" fn ddog_add_span_metrics_str(ptr: &mut SpanBytes, key: *const c_char, val: f64) { - ptr.metrics - .insert(convert_literal_to_bytes_string(key), val); -} + /// `span[key]` (a msgpack map field) as a borrowed value. + fn field<'a>(v: &'a Value, key: &str) -> Option<&'a Value> { + match v { + Value::Map(m) => m.iter().find(|(k, _)| k.as_str() == Some(key)).map(|(_, v)| v), + _ => None, + } + } -#[no_mangle] -pub extern "C" fn ddog_get_span_metrics_str( - ptr: &mut SpanBytes, - key: *const c_char, - result: &mut f64, -) -> bool { - match ptr.metrics.get(&convert_literal_to_bytes_string(key)) { - Some(&value) => { - *result = value; - true + #[test] + fn link_nested_attr_matches_old_json_string_v04() { + // NEW: native nested link attr `nums = [3, 4]` built through the container FFI. + let (newb, s) = one_span_builder(); + unsafe { + let link = ddog_new_link(s); + let nums = ddog_attr_list_new(2); + ddog_attr_list_push_int(nums, 3); + ddog_attr_list_push_int(nums, 4); + ddog_attributes_add_list(ddog_link_get_attributes(link), cs("nums"), nums); + } + // OLD: the JSON string the pre-native serializer produced (json_encode([3,4])). + let (oldb, s) = one_span_builder(); + unsafe { + let link = ddog_new_link(s); + ddog_attributes_add_str(ddog_link_get_attributes(link), cs("nums"), cs("[3,4]")); } - None => false, + + let new_span = first_span(&to_vec_from_v1(&newb.into_payload())); + let old_span = first_span(&to_vec_from_v1(&oldb.into_payload())); + // v0.4 links are native `span_links` with String attributes: the nested value carries the + // old json_encode string. + let nums = |sp: &Value| { + let link = &field(sp, "span_links").unwrap().as_array().unwrap()[0]; + field(field(link, "attributes").unwrap(), "nums").unwrap().clone() + }; + assert_eq!(nums(&new_span).as_str(), Some("[3,4]")); + assert_eq!(nums(&new_span), nums(&old_span)); } -} -#[no_mangle] -pub extern "C" fn ddog_del_span_metrics_str(ptr: &mut SpanBytes, key: *const c_char) { - ptr.metrics - .remove_slow(&convert_literal_to_bytes_string(key)); -} + #[test] + fn event_nested_attr_downgrades_to_legacy_events_meta_native_array() { + // Native nested event attr `nums = [3, 4]` built through the container FFI. On the v0.4 + // downgrade it lands in the legacy `events` meta as a REAL JSON array (event attributes + // keep native JSON types, matching master's json_encode of the PHP attributes array — + // unlike links, which are String → String). No native `span_events` field on the v0.4 wire. + let (newb, s) = one_span_builder(); + unsafe { + let event = ddog_new_event(s); + let nums = ddog_attr_list_new(2); + ddog_attr_list_push_int(nums, 3); + ddog_attr_list_push_int(nums, 4); + ddog_attributes_add_list(ddog_event_get_attributes(event), cs("nums"), nums); + } + let new_span = first_span(&to_vec_from_v1(&newb.into_payload())); + assert!(field(&new_span, "span_events").is_none()); + let events_meta = field(field(&new_span, "meta").unwrap(), "events") + .unwrap() + .as_str() + .unwrap(); + assert!(events_meta.contains(r#""nums":[3,4]"#), "got {events_meta}"); + } -#[no_mangle] -pub extern "C" fn ddog_add_span_meta_struct_zstr( - ptr: &mut SpanBytes, - key: &mut ZendString, - val: &mut ZendString, -) { - ptr.meta_struct - .insert(convert_zend_to_bytes_string(key), convert_to_bytes(val)); + #[test] + fn span_kind_str_process_survives_v04_downgrade() { + // Mirrors tracer/serializer.c: only delete `span.kind` meta when canonical. Fixes + // AMQPIntegration's `Tag::SPAN_KIND = 'process'`, previously destroyed by enum coercion. + let (b, s) = one_span_builder(); + unsafe { + let is_canonical = ddog_set_span_kind_str(s, cs("process")); + assert!( + !is_canonical, + "\"process\" is not one of the 4 canonical kind strings" + ); + ddog_attributes_add_str(ddog_span_get_attributes(s), cs("span.kind"), cs("process")); + } + let span = first_span(&to_vec_from_v1(&b.into_payload())); + assert_eq!( + field(field(&span, "meta").unwrap(), "span.kind") + .unwrap() + .as_str(), + Some("process") + ); + // Exactly once: not duplicated as a generic attribute alongside the promoted field. + let meta_entries = match field(&span, "meta").unwrap() { + Value::Map(m) => m, + other => panic!("expected map, got {other:?}"), + }; + let kind_count = meta_entries + .iter() + .filter(|(k, _)| k.as_str() == Some("span.kind")) + .count(); + assert_eq!( + kind_count, 1, + "duplicate \"span.kind\" key written to the wire" + ); + } + + #[test] + fn span_kind_str_internal_is_canonical_and_survives_v04_downgrade() { + // An explicit "internal" is the Internal kind: serializer.c deletes the tag, and the + // downgrade writes it back from the kind. + let (b, s) = one_span_builder(); + unsafe { + assert!(ddog_set_span_kind_str(s, cs("internal"))); + } + let span = first_span(&to_vec_from_v1(&b.into_payload())); + assert_eq!( + field(field(&span, "meta").unwrap(), "span.kind") + .unwrap() + .as_str(), + Some("internal") + ); + } + + #[test] + fn span_kind_unset_stays_unspecified() { + let (b, _s) = one_span_builder(); + let payload = b.into_payload(); + assert_eq!(payload.chunks[0].spans[0].span_kind, SpanKind::Unspecified); + let span = first_span(&to_vec_from_v1(&payload)); + assert!(field(&span, "meta") + .and_then(|m| field(m, "span.kind")) + .is_none()); + } + + #[test] + fn span_kind_str_known_value_is_canonical_and_not_duplicated() { + let (b, s) = one_span_builder(); + unsafe { + let is_canonical = ddog_set_span_kind_str(s, cs("server")); + assert!(is_canonical); + // serializer.c deletes the meta key in this case; not re-added as an attribute here. + } + let span = first_span(&to_vec_from_v1(&b.into_payload())); + assert_eq!( + field(field(&span, "meta").unwrap(), "span.kind") + .unwrap() + .as_str(), + Some("server") + ); + } } -#[no_mangle] -pub extern "C" fn ddog_add_zstr_span_meta_struct_CharSlice( - ptr: &mut SpanBytes, - key: &mut ZendString, - val: CharSlice, -) { - ptr.meta_struct.insert( - convert_zend_to_bytes_string(key), - Bytes::copy_from_slice(val.as_bytes()), - ); +#[cfg(test)] +mod pointer_handle_miri_tests { + // The crux of Phase 2 comment A: prove the Box-per-node pointer model is UB-clean under Stacked + // AND Tree Borrows for the hazards the old index model was chosen to avoid. Run with + // `cargo +nightly miri test` (Stacked Borrows, the default) and with `-Zmiri-tree-borrows`. + use super::*; + use datadog_sidecar_ffi::span::*; + use libdd_trace_utils::span::v1::AttributeValueBytes; + + fn cs(s: &str) -> CharSlice<'_> { + CharSlice::from_bytes(s.as_bytes()) + } + + // (a) The inferred-span hazard (serializer.c ~2059→2098): after a SECOND span is pushed into the + // same chunk, the outer frame keeps mutating and reading its ROOT span pointer with NO refetch. + #[test] + fn a_root_span_ptr_survives_sibling_push() { + let mut b = TracerPayloadV1Builder::default(); + let chunk = b.push_chunk(0, 1); + unsafe { + let root = ddog_new_span(chunk); + ddog_span_set_id(root, 100); + ddog_span_set_error(root, true); + ddog_attributes_add_lit(ddog_span_get_attributes(root), c"moved".as_ptr(), cs("v")); + + // The sibling push that reallocs `chunk.spans`; `root` must stay valid (own allocation). + let inferred = ddog_new_span(chunk); + ddog_span_set_id(inferred, 200); + + // Use `root` AFTER the sibling push, with no refetch (mirrors the transfers/debug log). + assert!(ddog_transfer_span_attr(root, inferred, c"moved".as_ptr(), true)); + ddog_span_set_error(inferred, ddog_span_get_error(root)); + let log = ddog_v1_span_debug_log(chunk, root); + assert!(!log.is_empty()); + ddog_free_charslice(log); + } + + let payload = b.into_payload(); + let spans = &payload.chunks[0].spans; + assert_eq!(spans.len(), 2); + assert_eq!(spans[0].span_id, 100); + assert_eq!(spans[1].span_id, 200); + assert!(!spans[0].attributes.contains_key("moved"), "attr moved off root"); + assert!(spans[1].attributes.contains_key("moved"), "attr moved onto inferred"); + } + + // (b) A deep nested List/KeyValue built via the container FFI and attached to a span node + // pointer, then folded through into_payload. + #[test] + fn b_nested_attr_build_on_span_ptr() { + let mut b = TracerPayloadV1Builder::default(); + let chunk = b.push_chunk(0, 1); + unsafe { + let span = ddog_new_span(chunk); + let nested = ddog_attr_map_new(1); + ddog_attributes_add_bool(ddog_attr_map_get_attributes(nested), cs("flag"), true); + let items = ddog_attr_list_new(2); + ddog_attr_list_push_str(items, cs("a")); + ddog_attr_list_push_map(items, nested); + let root = ddog_attr_map_new(2); + ddog_attributes_add_int(ddog_attr_map_get_attributes(root), cs("n"), 7); + ddog_attributes_add_list(ddog_attr_map_get_attributes(root), cs("items"), items); + ddog_attributes_add_map(ddog_span_get_attributes(span), cs("root"), root); + } + let payload = b.into_payload(); + match payload.chunks[0].spans[0].attributes.get("root") { + Some(AttributeValueBytes::KeyValue(m)) => assert_eq!(m.len(), 2), + other => panic!("expected KeyValue, got {other:?}"), + } + } + + // (c) Links and events built on a span pointer, each fully built — including a deep nested + // List/KeyValue attribute attached to the link/event node pointer — before the next push; the + // node pointers stay valid across sibling node pushes. + #[test] + fn c_links_and_events_on_span_ptr() { + let mut b = TracerPayloadV1Builder::default(); + let chunk = b.push_chunk(0, 1); + unsafe { + let span = ddog_new_span(chunk); + let l0 = ddog_new_link(span); + ddog_link_set_span_id(l0, 11); + ddog_attributes_add_str(ddog_link_get_attributes(l0), cs("k"), cs("v")); + // Deep nested attr on l0: { tags: [ "a", { deep: 1 } ] } — fully built before l1. + let deep = ddog_attr_map_new(1); + ddog_attributes_add_int(ddog_attr_map_get_attributes(deep), cs("deep"), 1); + let tags = ddog_attr_list_new(2); + ddog_attr_list_push_str(tags, cs("a")); + ddog_attr_list_push_map(tags, deep); + ddog_attributes_add_list(ddog_link_get_attributes(l0), cs("tags"), tags); + + let l1 = ddog_new_link(span); // sibling push; l0 stays valid (own allocation) + ddog_link_set_span_id(l1, 22); + ddog_link_set_span_id(l0, 111); // still valid after the sibling push + + let e0 = ddog_new_event(span); + ddog_event_set_name(e0, cs("evt")); + ddog_attributes_add_int(ddog_event_get_attributes(e0), cs("n"), 5); + // Deep nested attr on e0: { meta: { list: [ true ] } } — fully built before e1. + let list = ddog_attr_list_new(1); + ddog_attr_list_push_bool(list, true); + let meta = ddog_attr_map_new(1); + ddog_attributes_add_list(ddog_attr_map_get_attributes(meta), cs("list"), list); + ddog_attributes_add_map(ddog_event_get_attributes(e0), cs("meta"), meta); + + let e1 = ddog_new_event(span); + ddog_event_set_time(e1, 999); + ddog_event_set_name(e0, cs("evt0")); // e0 valid after e1's push + } + let payload = b.into_payload(); + let span = &payload.chunks[0].spans[0]; + assert_eq!(span.span_links.len(), 2); + assert_eq!(span.span_links[0].span_id, 111); + match span.span_links[0].attributes.get("tags") { + Some(AttributeValueBytes::List(v)) => assert_eq!(v.len(), 2), + other => panic!("expected link List attr, got {other:?}"), + } + assert_eq!(span.span_events.len(), 2); + assert_eq!(span.span_events[0].name.as_str(), "evt0"); + match span.span_events[0].attributes.get("meta") { + Some(AttributeValueBytes::KeyValue(m)) => assert_eq!(m.len(), 1), + other => panic!("expected event KeyValue attr, got {other:?}"), + } + } + + // (d) into_payload dedups duplicate keys, and a builder dropped WITHOUT into_payload frees every + // node box (Miri's leak/double-free checker is the assertion for the drop path). + #[test] + fn d_into_payload_dedup_and_drop() { + let mut b = TracerPayloadV1Builder::default(); + let chunk = b.push_chunk(0, 1); + unsafe { + let span = ddog_new_span(chunk); + ddog_attributes_add_str(ddog_span_get_attributes(span), cs("dup"), cs("first")); + ddog_attributes_add_str(ddog_span_get_attributes(span), cs("dup"), cs("second")); + } + let payload = b.into_payload(); + let attrs = &payload.chunks[0].spans[0].attributes; + assert_eq!(attrs.len(), 1, "duplicate keys deduped in into_payload"); + + // Drop path: build a populated builder and let it fall out of scope unconsumed. + let mut d = TracerPayloadV1Builder::default(); + let c = d.push_chunk(0, 2); + unsafe { + let s = ddog_new_span(c); + ddog_new_link(s); + ddog_new_event(s); + let m = ddog_attr_map_new(1); + ddog_attributes_add_int(ddog_attr_map_get_attributes(m), cs("y"), 1); + ddog_attributes_add_map(ddog_span_get_attributes(s), cs("x"), m); + } + drop(d); + } + + // (e) A deep mixed nest (list in map in list), built once with capacity 0 (forcing regrowth) and + // once with exact capacities; both attach the same value and free cleanly. + #[test] + fn e_deep_mixed_nest_any_capacity() { + unsafe fn build(span: *mut SpanNode, key: &str, cap: impl Fn(usize) -> usize) { + let inner = ddog_attr_list_new(cap(3)); + ddog_attr_list_push_int(inner, 1); + ddog_attr_list_push_bytes(inner, cs("raw")); + ddog_attr_list_push_list(inner, ddog_attr_list_new(cap(0))); + let mid = ddog_attr_map_new(cap(2)); + ddog_attributes_add_list(ddog_attr_map_get_attributes(mid), cs("inner"), inner); + ddog_attributes_add_map(ddog_attr_map_get_attributes(mid), cs("empty"), ddog_attr_map_new(cap(0))); + let outer = ddog_attr_list_new(cap(2)); + ddog_attr_list_push_map(outer, mid); + ddog_attr_list_push_str(outer, cs("tail")); + ddog_attributes_add_list(ddog_span_get_attributes(span), cs(key), outer); + } + let mut b = TracerPayloadV1Builder::default(); + let chunk = b.push_chunk(0, 1); + unsafe { + let span = ddog_new_span(chunk); + build(span, "zero", |_| 0); + build(span, "exact", |n| n); + } + let payload = b.into_payload(); + let attrs = &payload.chunks[0].spans[0].attributes; + let shape = |key: &str| match attrs.get(key) { + Some(AttributeValueBytes::List(outer)) => { + assert_eq!(outer.len(), 2); + assert!(matches!(&outer[1], AttributeValueBytes::String(s) if s.as_str() == "tail")); + match &outer[0] { + AttributeValueBytes::KeyValue(mid) => { + assert!(matches!(mid.get("empty"), Some(AttributeValueBytes::KeyValue(m)) if m.is_empty())); + match mid.get("inner") { + Some(AttributeValueBytes::List(inner)) => { + assert!(matches!(inner[0], AttributeValueBytes::Int(1))); + assert!(matches!(&inner[1], AttributeValueBytes::Bytes(b) if b.as_ref() == b"raw")); + assert!(matches!(&inner[2], AttributeValueBytes::List(l) if l.is_empty())); + } + other => panic!("expected inner List, got {other:?}"), + } + } + other => panic!("expected KeyValue, got {other:?}"), + } + } + other => panic!("expected List, got {other:?}"), + }; + shape("zero"); + shape("exact"); + } + + // (f) Attribute handles stay valid across other calls on their node and sibling pushes, with no + // refetch: the handle shares the node pointer's tag (no intermediate `&mut` in the getter). + #[test] + fn f_attribute_handles_survive_interleaved_node_calls() { + let mut b = TracerPayloadV1Builder::default(); + let chunk = b.push_chunk(0, 1); + unsafe { + let span = ddog_new_span(chunk); + let attrs = ddog_span_get_attributes(span); + ddog_attributes_add_str(attrs, cs("a"), cs("1")); + ddog_span_set_error(span, true); + ddog_span_set_id(span, 7); + let link = ddog_new_link(span); + let link_attrs = ddog_link_get_attributes(link); + let event = ddog_new_event(span); + let event_attrs = ddog_event_get_attributes(event); + ddog_attributes_add_int(attrs, cs("b"), 2); + ddog_link_set_span_id(link, 3); + ddog_attributes_add_str(link_attrs, cs("l"), cs("v")); + let link2 = ddog_new_link(span); // sibling push + ddog_event_set_name(event, cs("e")); + ddog_attributes_add_bool(event_attrs, cs("e"), true); + ddog_attributes_add_str(ddog_link_get_attributes(link2), cs("l2"), cs("v2")); + ddog_attributes_add_double(attrs, cs("c"), 1.5); + assert!(ddog_span_get_error(span)); + let second = ddog_new_span(chunk); // sibling span push + ddog_attributes_add_str(ddog_span_get_attributes(second), cs("s"), cs("2")); + let m = ddog_attr_map_new(0); + let m_attrs = ddog_attr_map_get_attributes(m); + ddog_attributes_add_int(m_attrs, cs("x"), 1); + ddog_attributes_add_str(attrs, cs("d"), cs("4")); + ddog_attributes_add_int(m_attrs, cs("y"), 2); + ddog_attributes_add_map(attrs, cs("m"), m); + } + let payload = b.into_payload(); + let span = &payload.chunks[0].spans[0]; + assert!(span.error); + assert_eq!(span.span_id, 7); + assert_eq!(span.attributes.len(), 5); + match span.attributes.get("m") { + Some(AttributeValueBytes::KeyValue(m)) => assert_eq!(m.len(), 2), + other => panic!("expected KeyValue, got {other:?}"), + } + assert_eq!(span.span_links.len(), 2); + assert!(span.span_links[0].attributes.contains_key("l")); + assert!(span.span_links[1].attributes.contains_key("l2")); + assert!(span.span_events[0].attributes.contains_key("e")); + assert!(payload.chunks[0].spans[1].attributes.contains_key("s")); + } } diff --git a/components-rs/common.h b/components-rs/common.h index 76a53619ba..6a81e55ab6 100644 --- a/components-rs/common.h +++ b/components-rs/common.h @@ -1206,6 +1206,24 @@ typedef struct ddog_AttributeAnyValueBytes ddog_AttributeAnyValueBytes; typedef struct ddog_AttributeArrayValueBytes ddog_AttributeArrayValueBytes; +/** + * Attribute value type tags from [`ddog_v1_value_type`], so a C caller picks the matching typed + * value getter. + */ +#define ddog_DDOG_V1_ATTR_STRING 0 + +#define ddog_DDOG_V1_ATTR_INT 1 + +#define ddog_DDOG_V1_ATTR_DOUBLE 2 + +#define ddog_DDOG_V1_ATTR_BOOL 3 + +#define ddog_DDOG_V1_ATTR_BYTES 4 + +#define ddog_DDOG_V1_ATTR_KEYVALUE 5 + +#define ddog_DDOG_V1_ATTR_LIST 6 + typedef enum ddog_DynamicInstrumentationConfigState { DDOG_DYNAMIC_INSTRUMENTATION_CONFIG_STATE_ENABLED, DDOG_DYNAMIC_INSTRUMENTATION_CONFIG_STATE_DISABLED, @@ -1218,6 +1236,33 @@ typedef struct ddog_AgentRemoteConfigWriter_ShmHandle ddog_AgentRemoteConfigWrit typedef struct ddog_Arc_Target ddog_Arc_Target; +/** + * An owned `List` attribute value under construction. Opaque to C. + */ +typedef struct ddog_AttrList ddog_AttrList; + +/** + * An owned `KeyValue` attribute value under construction. Opaque to C. + */ +typedef struct ddog_AttrMap ddog_AttrMap; + +/** + * Opaque handle to one attribute value inside an [`Attributes`] map or a list. + */ +typedef struct ddog_AttrValue ddog_AttrValue; + +/** + * Opaque handle to an attribute map: the payload's, a chunk's, span's, link's or event's + * (`ddog_*_get_attributes`), or an owned nested map's ([`ddog_attr_map_get_attributes`]). + */ +typedef struct ddog_Attributes ddog_Attributes; + +/** + * A chunk node in the builder: its own heap allocation, so a `*mut ChunkNode` handed to C stays + * valid across sibling chunk pushes. Its spans live as separate `Box` allocations. + */ +typedef struct ddog_ChunkNode ddog_ChunkNode; + /** * Fundamental configuration of the RC client, which always must be set. */ @@ -1252,6 +1297,19 @@ typedef struct ddog_RuntimeMetadata ddog_RuntimeMetadata; typedef struct ddog_ShmHandle ddog_ShmHandle; +/** + * A span node in the builder: its own heap allocation, so a held `*mut SpanNode` stays valid + * across sibling span pushes into the same chunk (the inferred-span case). Links/events are + * likewise separate `Box` allocations. + */ +typedef struct ddog_SpanNode ddog_SpanNode; + +/** + * Builds a native V1 [`TracerPayloadBytes`] holding readable strings. Each node is its own heap + * allocation (see the module docs); the builder owns the top-level chunk pointers. + */ +typedef struct ddog_TracerPayloadV1Builder ddog_TracerPayloadV1Builder; + typedef struct ddog_NativeFile { struct ddog_PlatformHandle_File *handle; } ddog_NativeFile; @@ -1393,6 +1451,14 @@ typedef struct ddog_SenderParameters { ddog_CharSlice url; } ddog_SenderParameters; +/** + * Payload-level tracer metadata for the V1 send path not already carried by the sender's + * `tracer_headers_tags` (lang, tracer_version, container_id live there and are routed from there). + */ +typedef struct ddog_TracerMetadataV1 { + ddog_CharSlice runtime_id; +} ddog_TracerMetadataV1; + /** * Raw AppSec response returned by the AppSec message functions. * diff --git a/components-rs/datadog.h b/components-rs/datadog.h index 494df3b29e..8caf667db9 100644 --- a/components-rs/datadog.h +++ b/components-rs/datadog.h @@ -9,7 +9,6 @@ struct _zend_string; #include "telemetry.h" #include "sidecar.h" - extern void (*ddog_log_callback)(ddog_CharSlice); /** @@ -79,59 +78,66 @@ void ddog_init_span_func(void (*free_func)(ddog_OwnedZendString), void (*addref_func)(struct _zend_string*), ddog_OwnedZendString (*init_func)(ddog_CharSlice)); -void ddog_set_span_service_zstr(ddog_SpanBytes *ptr, struct _zend_string *str); - -void ddog_set_span_name_zstr(ddog_SpanBytes *ptr, struct _zend_string *str); - -void ddog_set_span_resource_zstr(ddog_SpanBytes *ptr, struct _zend_string *str); - -void ddog_set_span_type_zstr(ddog_SpanBytes *ptr, struct _zend_string *str); - -void ddog_add_span_meta_zstr(ddog_SpanBytes *ptr, - struct _zend_string *key, - struct _zend_string *val); - -void ddog_add_CharSlice_span_meta_zstr(ddog_SpanBytes *ptr, - ddog_CharSlice key, - struct _zend_string *val); - -void ddog_add_zstr_span_meta_str(ddog_SpanBytes *ptr, struct _zend_string *key, const char *val); - -void ddog_add_str_span_meta_str(ddog_SpanBytes *ptr, const char *key, const char *val); - -void ddog_add_str_span_meta_zstr(ddog_SpanBytes *ptr, const char *key, struct _zend_string *val); - -void ddog_add_str_span_meta_CharSlice(ddog_SpanBytes *ptr, const char *key, ddog_CharSlice val); - -void ddog_del_span_meta_zstr(ddog_SpanBytes *ptr, struct _zend_string *key); - -void ddog_del_span_meta_str(ddog_SpanBytes *ptr, const char *key); - -bool ddog_has_span_meta_zstr(ddog_SpanBytes *ptr, struct _zend_string *key); - -bool ddog_has_span_meta_str(ddog_SpanBytes *ptr, const char *key); - -ddog_CharSlice ddog_get_span_meta_str(ddog_SpanBytes *span, const char *key); - -void ddog_add_span_metrics_zstr(ddog_SpanBytes *ptr, struct _zend_string *key, double val); +/** + * # Safety + * `span` must be a live span node pointer from `ddog_new_span` (every `*_zstr` span setter). + */ +void ddog_set_span_service_zstr(ddog_SpanNode *span, struct _zend_string *str); -bool ddog_has_span_metrics_zstr(ddog_SpanBytes *ptr, struct _zend_string *key); +/** + * # Safety + * See [`ddog_set_span_service_zstr`]. + */ +void ddog_set_span_name_zstr(ddog_SpanNode *span, struct _zend_string *str); -void ddog_del_span_metrics_zstr(ddog_SpanBytes *ptr, struct _zend_string *key); +/** + * # Safety + * See [`ddog_set_span_service_zstr`]. + */ +void ddog_set_span_resource_zstr(ddog_SpanNode *span, struct _zend_string *str); -void ddog_add_span_metrics_str(ddog_SpanBytes *ptr, const char *key, double val); +/** + * # Safety + * See [`ddog_set_span_service_zstr`]. + */ +void ddog_set_span_type_zstr(ddog_SpanNode *span, struct _zend_string *str); -bool ddog_get_span_metrics_str(ddog_SpanBytes *ptr, const char *key, double *result); +/** + * String attribute under a static C literal key. + * + * # Safety + * `attrs` must be a live `Attributes` handle and `key` a static NUL-terminated string (applies + * to every attribute adder below). + */ +void ddog_attributes_add_lit(ddog_Attributes *attrs, const char *key, ddog_CharSlice value); -void ddog_del_span_metrics_str(ddog_SpanBytes *ptr, const char *key); +/** + * String attribute sharing both zend strings (zero-copy). + * + * # Safety + * See [`ddog_attributes_add_lit`]. + */ +void ddog_attributes_add_zstr(ddog_Attributes *attrs, + struct _zend_string *key, + struct _zend_string *value); -void ddog_add_span_meta_struct_zstr(ddog_SpanBytes *ptr, - struct _zend_string *key, - struct _zend_string *val); +/** + * Double attribute under a static C literal key. + * + * # Safety + * See [`ddog_attributes_add_lit`]. + */ +void ddog_attributes_add_double_lit(ddog_Attributes *attrs, const char *key, double value); -void ddog_add_zstr_span_meta_struct_CharSlice(ddog_SpanBytes *ptr, - struct _zend_string *key, - ddog_CharSlice val); +/** + * Double attribute under a shared zend string key (zero-copy). + * + * # Safety + * See [`ddog_attributes_add_lit`]. + */ +void ddog_attributes_add_double_zstr(ddog_Attributes *attrs, + struct _zend_string *key, + double value); bool ddog_ffe_load_config(ddog_CharSlice json); diff --git a/components-rs/sidecar.h b/components-rs/sidecar.h index f0c04aa09a..7e2879037d 100644 --- a/components-rs/sidecar.h +++ b/components-rs/sidecar.h @@ -242,7 +242,8 @@ ddog_MaybeError ddog_sidecar_session_set_config(struct ddog_SidecarTransport **t ddog_CharSlice hostname, ddog_CharSlice root_service, ddog_CharSlice root_session_id, - ddog_CharSlice parent_session_id); + ddog_CharSlice parent_session_id, + bool force_v04_traces); /** * Updates the process_tags for an existing session. @@ -520,6 +521,25 @@ ddog_CharSlice ddog_get_agent_info_container_tags_hash(struct ddog_AgentInfoRead void ddog_send_traces_to_sidecar(ddog_TracesBytes *traces, struct ddog_SenderParameters *parameters); +/** + * V1 counterpart of `ddog_send_traces_to_sidecar`: sends the [`crate::span`] builder's native V1 + * payload to the agent's `/v1.0/traces`. Consumes `builder`. Payload metadata comes at send time + * from `parameters.tracer_headers_tags` and `metadata`; lang_interpreter/lang_vendor go as + * headers. + */ +void ddog_send_traces_to_sidecar_v1(struct ddog_TracerPayloadV1Builder *builder, + struct ddog_SenderParameters *parameters, + const struct ddog_TracerMetadataV1 *metadata); + +/** + * Downgrades a native V1 builder to the in-memory v0.4 collection for the in-process `coms.c` + * sender (PHP <= 8.2). Consumes `builder`. Returns the collection (not one whole-payload + * CharSlice) so `auto_flush` can frame each trace individually; a single CharSlice would drop + * extra traces of a multi-trace payload. Empty collection on error; free with + * [`crate::span_v04::ddog_free_traces`]. + */ +ddog_TracesBytes *ddog_downgrade_v1_builder_to_v04_traces(struct ddog_TracerPayloadV1Builder *builder); + /** * Drops the agent info reader. */ @@ -644,162 +664,615 @@ void ddog_sidecar_signal_flush_drop(struct ddog_SignalFlush *flush); int32_t ddog_sidecar_signal_flush_run(const struct ddog_SignalFlush *flush); #endif -ddog_TracesBytes *ddog_get_traces(void); +/** + * Creates a new, empty V1 payload builder. Free it with [`ddog_v1_free_builder`], or hand it to + * `ddog_send_traces_to_sidecar_v1`, which consumes it. + */ +struct ddog_TracerPayloadV1Builder *ddog_v1_new_builder(void); -void ddog_free_traces(ddog_TracesBytes *_traces); +/** + * Frees a V1 payload builder. + */ +void ddog_v1_free_builder(struct ddog_TracerPayloadV1Builder *_builder); -uintptr_t ddog_get_traces_size(const ddog_TracesBytes *traces); +/** + * Sets the payload `env` / `app_version` / `hostname` fields (empty = unset). + */ +void ddog_set_payload_metadata(struct ddog_TracerPayloadV1Builder *builder, + ddog_CharSlice env, + ddog_CharSlice app_version, + ddog_CharSlice hostname); -ddog_TraceBytes *ddog_get_trace(ddog_TracesBytes *traces, uintptr_t index); +/** + * Appends a chunk carrying the 128-bit trace id (high/low halves), returning its node pointer. + */ +struct ddog_ChunkNode *ddog_new_chunk(struct ddog_TracerPayloadV1Builder *builder, + uint64_t trace_id_high, + uint64_t trace_id_low); -ddog_TraceBytes *ddog_traces_new_trace(ddog_TracesBytes *traces); +/** + * Number of spans already in `chunk`. + * + * # Safety + * `chunk` must be a live chunk node pointer from [`ddog_new_chunk`] (applies to every chunk fn). + */ +uintptr_t ddog_chunk_span_count(struct ddog_ChunkNode *chunk); -uintptr_t ddog_get_trace_size(const ddog_TraceBytes *trace); +/** + * Appends an empty span to `chunk`, returning its node pointer. + * + * # Safety + * See [`ddog_chunk_span_count`]. + */ +struct ddog_SpanNode *ddog_new_span(struct ddog_ChunkNode *chunk); -ddog_SpanBytes *ddog_get_span(ddog_TraceBytes *trace, uintptr_t index); +/** + * Appends an empty link to `span`, returning its node pointer. + * + * # Safety + * `span` must be a live span node pointer from [`ddog_new_span`] (applies to every span fn). + */ +ddog_SpanLinkBytes *ddog_new_link(struct ddog_SpanNode *span); -ddog_SpanBytes *ddog_trace_new_span(ddog_TraceBytes *trace); +/** + * Appends an empty event to `span`, returning its node pointer. + * + * # Safety + * See [`ddog_new_link`]. + */ +ddog_SpanEventBytes *ddog_new_event(struct ddog_SpanNode *span); -ddog_SpanBytes *ddog_trace_new_span_with_capacities(ddog_TraceBytes *trace, - uintptr_t meta_size, - uintptr_t metrics_size); +/** + * # Safety + * See [`ddog_new_link`] (applies to every `ddog_span_set_*` / `ddog_set_span_*`). + */ +void ddog_span_set_id(struct ddog_SpanNode *span, uint64_t value); /** - * The returned slice is an owned allocation that must be properly freed using - * [`ddog_free_charslice`]. + * # Safety + * See [`ddog_span_set_id`]. */ -ddog_CharSlice ddog_span_debug_log(const ddog_SpanBytes *span); +void ddog_span_set_parent_id(struct ddog_SpanNode *span, uint64_t value); /** - * Frees an owned [`CharSlice`]. Note that some functions of this API return borrowed slices that - * must NOT be freed. Only a few selected functions return slices that must be freed, and this is - * mentioned explicitly in their documentation. + * # Safety + * See [`ddog_span_set_id`]. + */ +void ddog_span_set_start(struct ddog_SpanNode *span, int64_t value); + +/** + * # Safety + * See [`ddog_span_set_id`]. + */ +void ddog_span_set_duration(struct ddog_SpanNode *span, int64_t value); + +/** + * # Safety + * See [`ddog_span_set_id`]. + */ +void ddog_span_set_error(struct ddog_SpanNode *span, bool error); + +/** + * Reads the span error flag (e.g. to mirror it onto an inferred span). * * # Safety + * See [`ddog_new_link`]. + */ +bool ddog_span_get_error(struct ddog_SpanNode *span); + +/** + * # Safety + * See [`ddog_span_get_error`]. + */ +void ddog_set_span_service(struct ddog_SpanNode *span, ddog_CharSlice value); + +/** + * # Safety + * See [`ddog_span_get_error`]. + */ +void ddog_set_span_name(struct ddog_SpanNode *span, ddog_CharSlice value); + +/** + * # Safety + * See [`ddog_span_get_error`]. + */ +void ddog_set_span_resource(struct ddog_SpanNode *span, ddog_CharSlice value); + +/** + * # Safety + * See [`ddog_span_get_error`]. + */ +void ddog_set_span_type(struct ddog_SpanNode *span, ddog_CharSlice value); + +/** + * # Safety + * See [`ddog_span_get_error`]. + */ +void ddog_set_span_env(struct ddog_SpanNode *span, ddog_CharSlice value); + +/** + * # Safety + * See [`ddog_span_get_error`]. + */ +void ddog_set_span_version(struct ddog_SpanNode *span, ddog_CharSlice value); + +/** + * # Safety + * See [`ddog_span_get_error`]. + */ +void ddog_set_span_component(struct ddog_SpanNode *span, ddog_CharSlice value); + +/** + * Sets the span kind from an OTEL wire value (unset/unknown → Unspecified). * - * `slice` must be an owned char slice that has been returned by one of the functions of this API. + * # Safety + * See [`ddog_new_link`]. */ -void ddog_free_charslice(ddog_CharSlice slice); +void ddog_set_span_kind(struct ddog_SpanNode *span, uint32_t kind); + +/** + * Sets the span kind from a v0.4 `span.kind` string. Returns `false` for a non-canonical kind, + * which has no wire slot, so the caller keeps it as a plain attribute. + * + * # Safety + * See [`ddog_new_link`]. + */ +bool ddog_set_span_kind_str(struct ddog_SpanNode *span, ddog_CharSlice value); + +/** + * # Safety + * See [`ddog_chunk_span_count`] (applies to every `ddog_set_chunk_*`). + */ +void ddog_set_chunk_origin(struct ddog_ChunkNode *chunk, ddog_CharSlice origin); + +/** + * # Safety + * See [`ddog_set_chunk_origin`]. + */ +void ddog_set_chunk_sampling_priority(struct ddog_ChunkNode *chunk, int32_t priority); + +/** + * # Safety + * See [`ddog_set_chunk_origin`]. + */ +void ddog_set_chunk_sampling_mechanism(struct ddog_ChunkNode *chunk, uint32_t mechanism); + +/** + * # Safety + * `link` must be a live link node pointer from [`ddog_new_link`] (applies to every + * `ddog_link_*`). + */ +void ddog_link_set_trace_id(ddog_SpanLinkBytes *link, + uint64_t trace_id_high, + uint64_t trace_id_low); + +/** + * # Safety + * See [`ddog_link_set_trace_id`]. + */ +void ddog_link_set_span_id(ddog_SpanLinkBytes *link, uint64_t value); + +/** + * # Safety + * See [`ddog_link_set_trace_id`]. + */ +void ddog_link_set_flags(ddog_SpanLinkBytes *link, uint32_t value); + +/** + * # Safety + * See [`ddog_link_set_trace_id`]. + */ +void ddog_link_set_tracestate(ddog_SpanLinkBytes *link, ddog_CharSlice value); + +/** + * # Safety + * `event` must be a live event node pointer from [`ddog_new_event`] (applies to every + * `ddog_event_*`). + */ +void ddog_event_set_name(ddog_SpanEventBytes *event, ddog_CharSlice value); + +/** + * # Safety + * See [`ddog_event_set_name`]. + */ +void ddog_event_set_time(ddog_SpanEventBytes *event, uint64_t time_unix_nano); + +/** + * The payload's attribute map. + * + * # Safety + * `builder` must be a live builder from [`ddog_v1_new_builder`]. + */ +struct ddog_Attributes *ddog_payload_get_attributes(struct ddog_TracerPayloadV1Builder *builder); + +/** + * # Safety + * See [`ddog_chunk_span_count`]. + */ +struct ddog_Attributes *ddog_chunk_get_attributes(struct ddog_ChunkNode *chunk); + +/** + * # Safety + * See [`ddog_new_link`]. + */ +struct ddog_Attributes *ddog_span_get_attributes(struct ddog_SpanNode *span); + +/** + * # Safety + * See [`ddog_link_set_trace_id`]. + */ +struct ddog_Attributes *ddog_link_get_attributes(ddog_SpanLinkBytes *link); + +/** + * # Safety + * See [`ddog_event_set_name`]. + */ +struct ddog_Attributes *ddog_event_get_attributes(ddog_SpanEventBytes *event); + +/** + * # Safety + * `attrs` must be a live [`Attributes`] handle (applies to every `ddog_attributes_add_*`). + */ +void ddog_attributes_add_str(struct ddog_Attributes *attrs, + ddog_CharSlice key, + ddog_CharSlice value); -void ddog_set_span_service(ddog_SpanBytes *span, ddog_CharSlice slice); +/** + * # Safety + * See [`ddog_attributes_add_str`]. + */ +void ddog_attributes_add_int(struct ddog_Attributes *attrs, ddog_CharSlice key, int64_t value); -ddog_CharSlice ddog_get_span_service(ddog_SpanBytes *span); +/** + * # Safety + * See [`ddog_attributes_add_str`]. + */ +void ddog_attributes_add_double(struct ddog_Attributes *attrs, ddog_CharSlice key, double value); -void ddog_set_span_name(ddog_SpanBytes *span, ddog_CharSlice slice); +/** + * # Safety + * See [`ddog_attributes_add_str`]. + */ +void ddog_attributes_add_bool(struct ddog_Attributes *attrs, ddog_CharSlice key, bool value); -ddog_CharSlice ddog_get_span_name(ddog_SpanBytes *span); +/** + * Bytes attribute (v0.4 `meta_struct`), copied verbatim. + * + * # Safety + * See [`ddog_attributes_add_str`]. + */ +void ddog_attributes_add_bytes(struct ddog_Attributes *attrs, + ddog_CharSlice key, + ddog_CharSlice value); -void ddog_set_span_resource(ddog_SpanBytes *span, ddog_CharSlice slice); +/** + * Sets `attrs[key]` to `list`, which is consumed. + * + * # Safety + * See [`ddog_attributes_add_str`]; `list` must be a live list from [`ddog_attr_list_new`]. + */ +void ddog_attributes_add_list(struct ddog_Attributes *attrs, + ddog_CharSlice key, + struct ddog_AttrList *list); -ddog_CharSlice ddog_get_span_resource(ddog_SpanBytes *span); +/** + * Sets `attrs[key]` to `map`, which is consumed. + * + * # Safety + * See [`ddog_attributes_add_str`]; `map` must be a live map from [`ddog_attr_map_new`], other than + * the one `attrs` belongs to. + */ +void ddog_attributes_add_map(struct ddog_Attributes *attrs, + ddog_CharSlice key, + struct ddog_AttrMap *map); -void ddog_set_span_type(ddog_SpanBytes *span, ddog_CharSlice slice); +/** + * Copies the attribute `key` from `from_span` onto `to_span`, returning whether the source had it; + * removes it from the source when `delete_source` is set. Type-preserving. + * + * # Safety + * `from_span`/`to_span` must be live, distinct span node pointers from [`ddog_new_span`]; `key` + * a static NUL-terminated string. + */ +bool ddog_transfer_span_attr(struct ddog_SpanNode *from_span, + struct ddog_SpanNode *to_span, + const char *key, + bool delete_source); -ddog_CharSlice ddog_get_span_type(ddog_SpanBytes *span); +/** + * Allocates an empty list with room for `capacity` elements, owned by C until it is consumed. + */ +struct ddog_AttrList *ddog_attr_list_new(uintptr_t capacity); -void ddog_set_span_trace_id(ddog_SpanBytes *span, uint64_t value); +/** + * Allocates an empty map with room for `capacity` members, owned by C until it is consumed. + */ +struct ddog_AttrMap *ddog_attr_map_new(uintptr_t capacity); -uint64_t ddog_get_span_trace_id(ddog_SpanBytes *span); +/** + * The attribute map of an owned nested `map`, filled with the `ddog_attributes_add_*` family. + * + * # Safety + * `map` must be a live map from [`ddog_attr_map_new`]. + */ +struct ddog_Attributes *ddog_attr_map_get_attributes(struct ddog_AttrMap *map); -void ddog_set_span_id(ddog_SpanBytes *span, uint64_t value); +/** + * # Safety + * `list` must be a live list from [`ddog_attr_list_new`] (applies to every `ddog_attr_list_*`); + * a `child` is consumed. + */ +void ddog_attr_list_push_str(struct ddog_AttrList *list, ddog_CharSlice value); -uint64_t ddog_get_span_id(ddog_SpanBytes *span); +/** + * # Safety + * See [`ddog_attr_list_push_str`]. + */ +void ddog_attr_list_push_int(struct ddog_AttrList *list, int64_t value); -void ddog_set_span_parent_id(ddog_SpanBytes *span, uint64_t value); +/** + * # Safety + * See [`ddog_attr_list_push_str`]. + */ +void ddog_attr_list_push_double(struct ddog_AttrList *list, double value); -uint64_t ddog_get_span_parent_id(ddog_SpanBytes *span); +/** + * # Safety + * See [`ddog_attr_list_push_str`]. + */ +void ddog_attr_list_push_bool(struct ddog_AttrList *list, bool value); -void ddog_set_span_start(ddog_SpanBytes *span, int64_t value); +/** + * # Safety + * See [`ddog_attr_list_push_str`]. + */ +void ddog_attr_list_push_bytes(struct ddog_AttrList *list, ddog_CharSlice value); -int64_t ddog_get_span_start(ddog_SpanBytes *span); +/** + * # Safety + * See [`ddog_attr_list_push_str`]. + */ +void ddog_attr_list_push_list(struct ddog_AttrList *list, struct ddog_AttrList *child); -void ddog_set_span_duration(ddog_SpanBytes *span, int64_t value); +/** + * # Safety + * See [`ddog_attr_list_push_str`]. + */ +void ddog_attr_list_push_map(struct ddog_AttrList *list, struct ddog_AttrMap *child); -int64_t ddog_get_span_duration(ddog_SpanBytes *span); +/** + * The builder's chunk node pointers; `len` receives their count. + */ +struct ddog_ChunkNode *const *ddog_v1_get_chunks(const struct ddog_TracerPayloadV1Builder *builder, + uintptr_t *len); -void ddog_set_span_error(ddog_SpanBytes *span, int32_t value); +/** + * Number of chunks in the builder. + */ +uintptr_t ddog_v1_get_chunk_count(const struct ddog_TracerPayloadV1Builder *builder); + +/** + * The chunk's span node pointers; `len` receives their count. + */ +struct ddog_SpanNode *const *ddog_v1_get_spans(const struct ddog_ChunkNode *chunk, uintptr_t *len); -int32_t ddog_get_span_error(ddog_SpanBytes *span); +/** + * The chunk's local-root span, as the v0.4 wire picks it (`local_root_idx`), or null if empty. + * Chunk-level trace tags (trace_id_high, sampling priority/mechanism, origin) belong on it only. + */ +struct ddog_SpanNode *ddog_v1_get_chunk_root_span(const struct ddog_ChunkNode *chunk); + +/** + * The span's link node pointers; `len` receives their count. + */ +ddog_SpanLinkBytes *const *ddog_v1_get_links(const struct ddog_SpanNode *span, uintptr_t *len); -void ddog_add_span_meta(ddog_SpanBytes *span, ddog_CharSlice key, ddog_CharSlice value); +/** + * The span's event node pointers; `len` receives their count. + */ +ddog_SpanEventBytes *const *ddog_v1_get_events(const struct ddog_SpanNode *span, uintptr_t *len); -void ddog_del_span_meta(ddog_SpanBytes *span, ddog_CharSlice key); +uint64_t ddog_v1_get_chunk_trace_id_high(const struct ddog_ChunkNode *chunk); -ddog_CharSlice ddog_get_span_meta(ddog_SpanBytes *span, ddog_CharSlice key); +uint64_t ddog_v1_get_chunk_trace_id_low(const struct ddog_ChunkNode *chunk); -bool ddog_has_span_meta(ddog_SpanBytes *span, ddog_CharSlice key); +/** + * Reads the chunk sampling priority; returns `false` (and leaves `out` untouched) when unset. + */ +bool ddog_v1_get_chunk_sampling_priority(const struct ddog_ChunkNode *chunk, int32_t *out); /** - * The return value is an owned array of slices (`Box<[CharSlice]>`) that must be freed explicitly - * through [`ddog_span_free_keys_ptr`]. + * Reads the chunk sampling mechanism; returns `false` (and leaves `out` untouched) when unset. */ -ddog_CharSlice *ddog_span_meta_get_keys(ddog_SpanBytes *span, uintptr_t *out_count); +bool ddog_v1_get_chunk_sampling_mechanism(const struct ddog_ChunkNode *chunk, uint32_t *out); + +ddog_CharSlice ddog_v1_get_chunk_origin(const struct ddog_ChunkNode *chunk); + +ddog_CharSlice ddog_v1_get_span_service(const struct ddog_SpanNode *span); + +ddog_CharSlice ddog_v1_get_span_name(const struct ddog_SpanNode *span); + +ddog_CharSlice ddog_v1_get_span_resource(const struct ddog_SpanNode *span); -void ddog_add_span_metrics(ddog_SpanBytes *span, ddog_CharSlice key, double val); +ddog_CharSlice ddog_v1_get_span_type(const struct ddog_SpanNode *span); -void ddog_del_span_metrics(ddog_SpanBytes *span, ddog_CharSlice key); +ddog_CharSlice ddog_v1_get_span_env(const struct ddog_SpanNode *span); -bool ddog_get_span_metrics(ddog_SpanBytes *span, ddog_CharSlice key, double *result); +ddog_CharSlice ddog_v1_get_span_version(const struct ddog_SpanNode *span); -bool ddog_has_span_metrics(ddog_SpanBytes *span, ddog_CharSlice key); +ddog_CharSlice ddog_v1_get_span_component(const struct ddog_SpanNode *span); -ddog_CharSlice *ddog_span_metrics_get_keys(ddog_SpanBytes *span, uintptr_t *out_count); +uint64_t ddog_v1_get_span_id(const struct ddog_SpanNode *span); -void ddog_add_span_meta_struct(ddog_SpanBytes *span, ddog_CharSlice key, ddog_CharSlice val); +uint64_t ddog_v1_get_span_parent_id(const struct ddog_SpanNode *span); -void ddog_del_span_meta_struct(ddog_SpanBytes *span, ddog_CharSlice key); +int64_t ddog_v1_get_span_start(const struct ddog_SpanNode *span); -ddog_CharSlice ddog_get_span_meta_struct(ddog_SpanBytes *span, ddog_CharSlice key); +int64_t ddog_v1_get_span_duration(const struct ddog_SpanNode *span); -bool ddog_has_span_meta_struct(ddog_SpanBytes *span, ddog_CharSlice key); +bool ddog_v1_get_span_error(const struct ddog_SpanNode *span); /** - * The return value is an array of slices (`Box<[CharSlice]>`) that must be freed explicitly - * through [`ddog_span_free_keys_ptr`]. + * The span kind as its OTEL wire value. */ -ddog_CharSlice *ddog_span_meta_struct_get_keys(ddog_SpanBytes *span, uintptr_t *out_count); +uint32_t ddog_v1_get_span_kind(const struct ddog_SpanNode *span); + +uint64_t ddog_v1_get_link_trace_id_high(const ddog_SpanLinkBytes *link); + +uint64_t ddog_v1_get_link_trace_id_low(const ddog_SpanLinkBytes *link); + +uint64_t ddog_v1_get_link_span_id(const ddog_SpanLinkBytes *link); + +uint32_t ddog_v1_get_link_flags(const ddog_SpanLinkBytes *link); + +ddog_CharSlice ddog_v1_get_link_tracestate(const ddog_SpanLinkBytes *link); + +uint64_t ddog_v1_get_event_time(const ddog_SpanEventBytes *event); + +ddog_CharSlice ddog_v1_get_event_name(const ddog_SpanEventBytes *event); /** + * Number of entries in `attrs`, including not-yet-deduped repeated keys (the last one wins). + * * # Safety + * `attrs` must be a live [`Attributes`] handle (applies to every `ddog_v1_attributes_*`). + */ +uintptr_t ddog_v1_attributes_len(const struct ddog_Attributes *attrs); + +/** + * Key of the entry at `idx` (empty if out of range). * - * `keys_ptr` must have been returned by one of the `ddog_xxx_get_keys()` functions, and must not - * have been already freed. + * # Safety + * See [`ddog_v1_attributes_len`]. */ -void ddog_span_free_keys_ptr(ddog_CharSlice *keys_ptr, uintptr_t count); +ddog_CharSlice ddog_v1_attributes_key(const struct ddog_Attributes *attrs, uintptr_t idx); -ddog_SpanLinkBytes *ddog_span_new_link(ddog_SpanBytes *span); +/** + * Value of the entry at `idx` (null if out of range). + * + * # Safety + * See [`ddog_v1_attributes_len`]. + */ +const struct ddog_AttrValue *ddog_v1_attributes_value(const struct ddog_Attributes *attrs, + uintptr_t idx); -void ddog_set_link_tracestate(ddog_SpanLinkBytes *link, ddog_CharSlice slice); +/** + * Value of `key` (null if absent). + * + * # Safety + * See [`ddog_v1_attributes_len`]. + */ +const struct ddog_AttrValue *ddog_v1_attributes_get(const struct ddog_Attributes *attrs, + ddog_CharSlice key); + +/** + * [`DDOG_V1_ATTR_*`] type tag of `value`. + * + * # Safety + * `value` must be a live [`AttrValue`] handle (applies to every `ddog_v1_value_*`). + */ +uint32_t ddog_v1_value_type(const struct ddog_AttrValue *value); + +/** + * The string (empty unless a `String`). + * + * # Safety + * See [`ddog_v1_value_type`]. + */ +ddog_CharSlice ddog_v1_value_str(const struct ddog_AttrValue *value); -void ddog_set_link_trace_id(ddog_SpanLinkBytes *link, uint64_t value); +/** + * The bytes (empty unless `Bytes`). + * + * # Safety + * See [`ddog_v1_value_type`]. + */ +ddog_CharSlice ddog_v1_value_bytes(const struct ddog_AttrValue *value); -void ddog_set_link_trace_id_high(ddog_SpanLinkBytes *link, uint64_t value); +/** + * The integer (0 unless an `Int`). + * + * # Safety + * See [`ddog_v1_value_type`]. + */ +int64_t ddog_v1_value_int(const struct ddog_AttrValue *value); -void ddog_set_link_span_id(ddog_SpanLinkBytes *link, uint64_t value); +/** + * The double (0.0 unless a `Float`). + * + * # Safety + * See [`ddog_v1_value_type`]. + */ +double ddog_v1_value_double(const struct ddog_AttrValue *value); -void ddog_set_link_flags(ddog_SpanLinkBytes *link, uint32_t value); +/** + * The boolean (false unless a true `Bool`). + * + * # Safety + * See [`ddog_v1_value_type`]. + */ +bool ddog_v1_value_bool(const struct ddog_AttrValue *value); -void ddog_add_link_attributes(ddog_SpanLinkBytes *link, ddog_CharSlice key, ddog_CharSlice val); +/** + * Number of elements (0 unless a `List`). + * + * # Safety + * See [`ddog_v1_value_type`]. + */ +uintptr_t ddog_v1_value_list_len(const struct ddog_AttrValue *value); -ddog_SpanEventBytes *ddog_span_new_event(ddog_SpanBytes *span); +/** + * Element `idx` (null unless a `List` with that element). + * + * # Safety + * See [`ddog_v1_value_type`]. + */ +const struct ddog_AttrValue *ddog_v1_value_list_get(const struct ddog_AttrValue *value, + uintptr_t idx); -void ddog_set_event_name(ddog_SpanEventBytes *event, ddog_CharSlice slice); +/** + * The members of a `KeyValue`, read with the `ddog_v1_attributes_*` family (null otherwise). + * + * # Safety + * See [`ddog_v1_value_type`]. + */ +const struct ddog_Attributes *ddog_v1_value_map(const struct ddog_AttrValue *value); -void ddog_set_event_time(ddog_SpanEventBytes *event, uint64_t val); +/** + * Renders a span for dd-trace-php's `DD_TRACE_DEBUG` "Encoding span" line. Takes the owning + * chunk/span node pointers (the outer frame's still-live handles), so it works mid-build before + * the nodes are folded into the inline payload. The returned owned slice must be freed with + * [`ddog_free_charslice`]. + * + * # Safety + * `chunk`/`span` must be live node pointers previously returned by + * `ddog_new_chunk`/`ddog_new_span` (with `span` a span of `chunk`). + */ +ddog_CharSlice ddog_v1_span_debug_log(struct ddog_ChunkNode *chunk, struct ddog_SpanNode *span); -void ddog_add_event_attributes_str(ddog_SpanEventBytes *event, - ddog_CharSlice key, - ddog_CharSlice val); +/** + * Frees an owned [`CharSlice`]. Only the few functions that document it return owned slices (the + * V1 [`ddog_v1_span_debug_log`] and the v0.4 + * [`crate::span_v04::ddog_serialize_trace_into_charslice`]); borrowed slices must NOT be passed + * here. An owned slice allocates `len + 1` bytes (payload + NUL), reclaimed here with that exact + * shape; a zero-length slice is always borrowed and owns nothing. + * + * # Safety + * + * `slice` must be an owned char slice that has been returned by one of the functions of this API. + */ +void ddog_free_charslice(ddog_CharSlice slice); -void ddog_add_event_attributes_bool(ddog_SpanEventBytes *event, ddog_CharSlice key, bool val); +void ddog_free_traces(ddog_TracesBytes *_traces); -void ddog_add_event_attributes_int(ddog_SpanEventBytes *event, ddog_CharSlice key, int64_t val); +uintptr_t ddog_get_traces_size(const ddog_TracesBytes *traces); -void ddog_add_event_attributes_float(ddog_SpanEventBytes *event, ddog_CharSlice key, double val); +ddog_TraceBytes *ddog_get_trace(ddog_TracesBytes *traces, uintptr_t index); /** - * The returned slice is an owned allocation that must be properly freed using - * [`ddog_free_charslice`]. + * Serializes one v0.4 trace as a msgpack array-of-1, the framing the background sender + * (`ddtrace_send_traces_via_thread`) expects. Returns an owned slice; free with + * [`crate::span::ddog_free_charslice`]. */ ddog_CharSlice ddog_serialize_trace_into_charslice(ddog_TraceBytes *trace); diff --git a/components-rs/sidecar.rs b/components-rs/sidecar.rs index eae5a19357..dfbe83d67c 100644 --- a/components-rs/sidecar.rs +++ b/components-rs/sidecar.rs @@ -3,11 +3,11 @@ use datadog_sidecar::service::blocking::{acquire_exception_hash_rate_limiter, Si use datadog_sidecar::service::exception_hash_rate_limiter::ExceptionHashRateLimiter; use datadog_sidecar::tracer::shm_limiter_path; use lazy_static::lazy_static; -use libdd_common::rate_limiter::{Limiter, LocalLimiter}; +use libdd_common::rate_limiter::LocalLimiter; use libdd_common::Endpoint; use libdd_common_ffi::slice::AsBytes; use libdd_common_ffi::{self as ffi, CharSlice, MaybeError}; -use libdd_ipc::rate_limiter::{AnyLimiter, ShmLimiterMemory}; +use libdd_ipc::rate_limiter::{ShmLimiter, ShmLimiterMemory}; use libdd_telemetry_ffi::try_c; #[cfg(windows)] use spawn_worker::{get_trampoline_target_data, LibDependency}; @@ -289,6 +289,14 @@ static SHM_LIMITER: LazyLock> = static EXCEPTION_HASH_LIMITER: LazyLock = LazyLock::new(ExceptionHashRateLimiter::new_reader); +enum AnyLimiter { + Local(LocalLimiter), + Shm(ShmLimiter<()>), +} + +/// Probe rate limits are per second. +const LIMITER_GRANULARITY: Duration = Duration::from_secs(1); + pub struct MaybeShmLimiter(Option); impl MaybeShmLimiter { @@ -307,7 +315,10 @@ impl MaybeShmLimiter { pub fn inc(&self, limit: u32) -> bool { if let Some(ref limiter) = self.0 { - limiter.inc(limit) + match limiter { + AnyLimiter::Local(local) => local.inc(limit, LIMITER_GRANULARITY), + AnyLimiter::Shm(shm) => shm.inc(limit, LIMITER_GRANULARITY), + } } else { true } @@ -325,10 +336,10 @@ pub extern "C" fn ddog_exception_hash_limiter_inc( hash: u64, granularity_seconds: u32, ) -> bool { - if let Some(limiter) = EXCEPTION_HASH_LIMITER.find(hash) { + let granularity = Duration::from_secs(granularity_seconds as u64); + if let Some(limiter) = EXCEPTION_HASH_LIMITER.find(hash, granularity) { return limiter.inc(); } - let granularity = Duration::from_secs(granularity_seconds as u64); let _ = acquire_exception_hash_rate_limiter(connection, hash, granularity); true } diff --git a/config.m4 b/config.m4 index 7aa29ce311..b5776ac4cb 100644 --- a/config.m4 +++ b/config.m4 @@ -344,6 +344,7 @@ if test "$PHP_DDTRACE" != "no" && test "$PHP_DDTRACE_PROFILING" = "no"; then tracer/standalone_limiter.c \ tracer/span.c \ tracer/span_stats.c \ + tracer/span_tags_view.c \ tracer/trace_filter.c \ tracer/trace_source.c \ tracer/tracer_startup_logging.c \ diff --git a/config.w32 b/config.w32 index ee7fb4237c..5cbfea5c24 100644 --- a/config.w32 +++ b/config.w32 @@ -78,6 +78,7 @@ if (PHP_DDTRACE != 'no') { DDTRACE_TRACER_SOURCES += " serializer.c"; DDTRACE_TRACER_SOURCES += " span.c"; DDTRACE_TRACER_SOURCES += " span_stats.c"; + DDTRACE_TRACER_SOURCES += " span_tags_view.c"; DDTRACE_TRACER_SOURCES += " standalone_limiter.c"; DDTRACE_TRACER_SOURCES += " trace_filter.c"; DDTRACE_TRACER_SOURCES += " trace_source.c"; diff --git a/ext/agent_info.h b/ext/agent_info.h index 476248ef58..abf9a3e777 100644 --- a/ext/agent_info.h +++ b/ext/agent_info.h @@ -1,6 +1,7 @@ #ifndef DATADOG_AGENT_INFO_H #define DATADOG_AGENT_INFO_H +#include #include #include "Zend/zend_types.h" diff --git a/ext/compatibility.h b/ext/compatibility.h index 048cf5e493..afc2d51510 100644 --- a/ext/compatibility.h +++ b/ext/compatibility.h @@ -264,9 +264,11 @@ static inline HashTable *zend_new_array(uint32_t nSize) { #define GC_PROTECT_RECURSION(gc) (++(gc)->u.v.nApplyCount) #define GC_UNPROTECT_RECURSION(gc) (--(gc)->u.v.nApplyCount) -#define Z_IS_RECURSIVE_P(zv) GC_IS_RECURSIVE(Z_OBJPROP_P(zv)) -#define Z_PROTECT_RECURSION_P(zv) GC_PROTECT_RECURSION(Z_OBJPROP_P(zv)) -#define Z_UNPROTECT_RECURSION_P(zv) GC_UNPROTECT_RECURSION(Z_OBJPROP_P(zv)) +// Like 7.3+ (which marks the zval's own counted): arrays are marked on themselves, objects on their property table. +#define DD_RECURSION_HT_P(zv) (Z_TYPE_P(zv) == IS_ARRAY ? Z_ARR_P(zv) : Z_OBJPROP_P(zv)) +#define Z_IS_RECURSIVE_P(zv) GC_IS_RECURSIVE(DD_RECURSION_HT_P(zv)) +#define Z_PROTECT_RECURSION_P(zv) GC_PROTECT_RECURSION(DD_RECURSION_HT_P(zv)) +#define Z_UNPROTECT_RECURSION_P(zv) GC_UNPROTECT_RECURSION(DD_RECURSION_HT_P(zv)) #define ZEND_CLOSURE_OBJECT(op_array) \ ((zend_object*)((char*)(op_array) - sizeof(zend_object))) @@ -417,6 +419,7 @@ static inline int datadog_declare_property_ex(zend_class_entry *ce, zend_string #endif #define ZEND_TYPE_INIT_MASK(type) NULL +#define ZEND_TYPE_INIT_NONE(extra_flags) NULL #define ZEND_TYPE_INIT_CLASS(class_name, allow_null, extra_flags) NULL; zend_string_release(class_name) #define ZEND_ARG_INFO_WITH_DEFAULT_VALUE(pass_by_ref, name, default_value) ZEND_ARG_INFO(pass_by_ref, name) @@ -730,6 +733,9 @@ static inline zend_string *zend_ini_str(const char *name, size_t name_length, bo #define ZEND_GUARD_PROPERTY_MASK 0xf +// Pre-8.3 php-src used a bare GC_DELREF here; also free on zero, which it leaked. +#define GC_DTOR_NO_REF(p) do { if (GC_DELREF(p) == 0) rc_dtor_func((zend_refcounted *)(p)); } while (0) + // strip const #if PHP_VERSION_ID < 70300 #undef zval_get_double diff --git a/ext/configuration.h b/ext/configuration.h index 667c9c4976..8e572f0e26 100644 --- a/ext/configuration.h +++ b/ext/configuration.h @@ -18,6 +18,11 @@ enum datadog_sidecar_connection_mode { DD_TRACE_SIDECAR_CONNECTION_MODE_THREAD = 2, // Force thread only }; +enum datadog_trace_agent_protocol_version { + DD_TRACE_AGENT_PROTOCOL_VERSION_V1 = 0, // Default: V1 when the agent advertises /v1.0/traces, else v0.4 + DD_TRACE_AGENT_PROTOCOL_VERSION_V04 = 1, // Always v0.4 +}; + /* From the curl docs on CONNECT_TIMEOUT_MS: * If libcurl is built to use the standard system name resolver, that * portion of the transfer will still use full-second resolution for @@ -98,6 +103,8 @@ enum datadog_sidecar_connection_mode { CONFIG(INT, DD_TRACE_SIDECAR_BACKPRESSURE_QUEUE, "100", .ini_change = zai_config_system_ini_change) \ CONFIG(STRING, DD_TRACE_AGENT_TEST_SESSION_TOKEN, "", .ini_change = datadog_alter_test_session_token) \ CONFIG(CUSTOM(INT), DD_TRACE_SIDECAR_CONNECTION_MODE, "auto", .parser = dd_parse_sidecar_connection_mode) \ + CONFIG(CUSTOM(INT), DD_TRACE_AGENT_PROTOCOL_VERSION, "1.0", \ + .parser = dd_parse_trace_agent_protocol_version, .ini_change = zai_config_system_ini_change) \ CONFIG(STRING, DD_TRACE_LOG_FILE, "", .ini_change = zai_config_system_ini_change) \ CONFIG(STRING, DD_TRACE_LOG_LEVEL, "error", .ini_change = datadog_alter_dd_trace_log_level, \ .env_config_fallback = ddtrace_conf_otel_log_level) \ diff --git a/ext/ffi_utils.h b/ext/ffi_utils.h index 5ee2c166e7..7893c77402 100644 --- a/ext/ffi_utils.h +++ b/ext/ffi_utils.h @@ -12,8 +12,13 @@ static inline ddog_CharSlice dd_zai_string_to_CharSlice(zai_string str) { return (ddog_CharSlice){ .len = str.len, .ptr = str.ptr }; } +// An empty Rust slice carries a dangling (e.g. 0x1) ptr; never hand it to a Zend API. +static inline const char *dd_CharSlice_ptr(ddog_CharSlice slice) { + return slice.len ? slice.ptr : ""; +} + static inline zend_string *dd_CharSlice_to_zend_string(ddog_CharSlice slice) { - return zend_string_init(slice.ptr, slice.len, 0); + return zend_string_init(dd_CharSlice_ptr(slice), slice.len, 0); } static inline bool datadog_ffi_try(const char *msg, ddog_MaybeError maybe_error) { diff --git a/ext/sidecar.c b/ext/sidecar.c index ee6f5745b5..f2b3bd2909 100644 --- a/ext/sidecar.c +++ b/ext/sidecar.c @@ -166,7 +166,8 @@ static void dd_sidecar_post_connect(ddog_SidecarTransport **transport, bool is_f dd_zend_string_to_CharSlice(get_global_DD_HOSTNAME()), dd_zend_string_to_CharSlice(get_global_DD_SERVICE()), root_session_id, - parent_session_id + parent_session_id, + get_global_DD_TRACE_AGENT_PROTOCOL_VERSION() == DD_TRACE_AGENT_PROTOCOL_VERSION_V04 ); if (otlp_metrics_endpoint) { ddog_endpoint_drop(otlp_metrics_endpoint); diff --git a/libdatadog b/libdatadog index d120c1090a..89d5b1fac3 160000 --- a/libdatadog +++ b/libdatadog @@ -1 +1 @@ -Subproject commit d120c1090a03fa7274fed4121344d25660081895 +Subproject commit 89d5b1fac3f42516d15e2576b325896e1334eace diff --git a/metadata/supported-configurations.json b/metadata/supported-configurations.json index b36ce1f478..f9be651082 100644 --- a/metadata/supported-configurations.json +++ b/metadata/supported-configurations.json @@ -757,6 +757,13 @@ "default": "8126" } ], + "DD_TRACE_AGENT_PROTOCOL_VERSION": [ + { + "implementation": "B", + "type": "string", + "default": "1.0" + } + ], "DD_TRACE_AGENT_RETRIES": [ { "implementation": "A", @@ -2275,9 +2282,9 @@ ], "DD_TRACE_SIDECAR_TRACE_SENDER": [ { - "implementation": "A", + "implementation": "B", "type": "boolean", - "default": "false" + "default": "true" } ], "DD_TRACE_SLIM_ANALYTICS_ENABLED": [ @@ -2505,13 +2512,6 @@ "default": "true" } ], - "DD_TRACE_WARN_LEGACY_DD_TRACE": [ - { - "implementation": "A", - "type": "boolean", - "default": "true" - } - ], "DD_TRACE_WEBSOCKET_MESSAGES_ENABLED": [ { "implementation": "A", diff --git a/tooling/generate-supported-configurations.sh b/tooling/generate-supported-configurations.sh index 0a70d2c261..c95651382c 100755 --- a/tooling/generate-supported-configurations.sh +++ b/tooling/generate-supported-configurations.sh @@ -476,11 +476,7 @@ extract_c_supported_configurations() { #undef PHP_VERSION_ID #define PHP_VERSION_ID $PHP_VERSION_ID #undef DD_SIDECAR_TRACE_SENDER_DEFAULT -#if PHP_VERSION_ID >= 80300 #define DD_SIDECAR_TRACE_SENDER_DEFAULT true -#else -#define DD_SIDECAR_TRACE_SENDER_DEFAULT false -#endif // Do not expand CALIASES() directly, otherwise parameter counting in macros is broken. #define ALTCALIASES(...) ,##__VA_ARGS__ #define ALT diff --git a/tracer/auto_flush.c b/tracer/auto_flush.c index e0985f2c11..ce86fdaa62 100644 --- a/tracer/auto_flush.c +++ b/tracer/auto_flush.c @@ -7,6 +7,8 @@ #include "coms.h" #endif #include "configuration.h" +#include +#include #include #include "serializer.h" #include "span.h" @@ -23,23 +25,33 @@ ZEND_EXTERN_MODULE_GLOBALS(datadog); ZEND_RESULT_CODE ddtrace_flush_tracer(bool force_on_startup, bool collect_cycles, bool fast_shutdown) { bool success = true; - ddog_TracesBytes *traces = ddog_get_traces(); + // Serialization fills the native V1 builder directly (no v0.4 intermediate). The sidecar + // negotiates V1-vs-v0.4; the in-process (<=8.2) sender downgrades to v0.4 at flush time. + ddtrace_serialize_ctx serialize_ctx = { + .builder = ddog_v1_new_builder(), + .chunk = DD_CHUNK_NONE, + .mark_top_level = get_global_DD_TRACE_SIDECAR_TRACE_SENDER(), + }; + ddtrace_serialize_ctx *ctx = &serialize_ctx; + if (collect_cycles) { - ddtrace_serialize_closed_spans_with_cycle(traces, fast_shutdown); + ddtrace_serialize_closed_spans_with_cycle(ctx, fast_shutdown); } else { - ddtrace_serialize_closed_spans(traces, fast_shutdown); + ddtrace_serialize_closed_spans(ctx, fast_shutdown); } // Prevent traces from requests not executing any PHP code: // PG(during_request_startup) will only be set to 0 upon execution of any PHP code. // e.g. php-fpm call with uri pointing to non-existing file, fpm status page, ... if (!force_on_startup && PG(during_request_startup)) { - ddog_free_traces(traces); + ddog_v1_free_builder(ctx->builder); return SUCCESS; } - if (!ddog_get_traces_size(traces)) { - ddog_free_traces(traces); + // Spans are built into the builder, not the (empty) V0.4 traces, so gate on the chunk count. + size_t payload_count = ddog_v1_get_chunk_count(ctx->builder); + if (!payload_count) { + ddog_v1_free_builder(ctx->builder); LOG(INFO, "No finished traces to be sent to the agent"); return SUCCESS; } @@ -57,7 +69,7 @@ ZEND_RESULT_CODE ddtrace_flush_tracer(bool force_on_startup, bool collect_cycles .lang_vendor = DDOG_CHARSLICE_C_BARE(""), .tracer_version = DDOG_CHARSLICE_C_BARE(PHP_DDTRACE_VERSION), .lang_version = php_version_rt, - .client_computed_top_level = get_DD_TRACE_STATS_COMPUTATION_ENABLED(), + .client_computed_top_level = true, // the serializer marked them (mark_top_level) .client_computed_stats = !get_global_DD_APM_TRACING_ENABLED() || (get_DD_TRACE_STATS_COMPUTATION_ENABLED() && ddog_agent_has_stats_computation()), }, .transport = DATADOG_G(sidecar), @@ -67,46 +79,60 @@ ZEND_RESULT_CODE ddtrace_flush_tracer(bool force_on_startup, bool collect_cycles .buffer_size = get_global_DD_TRACE_BUFFER_SIZE(), .url = (ddog_CharSlice) {.ptr = url, .len = strlen(url)}, }; - ddog_send_traces_to_sidecar(traces, ¶meters); + // lang/tracer_version/container_id come from parameters.tracer_headers_tags; process + // tags travel as the payload attribute "_dd.tags.process". + uint8_t formatted_runtime_id[36]; + datadog_format_runtime_id(&formatted_runtime_id); + // env/app_version/hostname/git were set on the builder from the first root span. + ddog_TracerMetadataV1 metadata = { + .runtime_id = (ddog_CharSlice) {.ptr = (char *) formatted_runtime_id, .len = sizeof(formatted_runtime_id)}, + }; + ddog_send_traces_to_sidecar_v1(ctx->builder, ¶meters, &metadata); // consumes the builder } else { + ddog_v1_free_builder(ctx->builder); // not handed to any FFI on this path LOGEV(INFO, { log("Skipping flushing trace as connection to sidecar failed"); }); } } else { #ifndef _WIN32 - success = true; - size_t length = ddog_get_traces_size(traces); - for (size_t i = 0; i < length; i++) { - ddog_TraceBytes *trace = ddog_get_trace(traces, i); - ddog_CharSlice serialized_trace = ddog_serialize_trace_into_charslice(trace); - - if (serialized_trace.len > 0) { - if (serialized_trace.len > limit) { - LOG(ERROR, "Agent request payload of %zu bytes exceeds configured %zu byte limit; dropping request", serialized_trace.len, limit); + // Removable v0.4 bolt-on: the in-process (<=8.2) background sender's array-of-1 framing can't + // parse a native V1 payload (one msgpack MAP), so it downgrades to v0.4 traces. Delete to revert. + // Consumes ctx->builder; returns a v0.4 collection to free below. + ddog_TracesBytes *v04_traces = ddog_downgrade_v1_builder_to_v04_traces(ctx->builder); + size_t trace_count = ddog_get_traces_size(v04_traces); + for (size_t i = 0; i < trace_count; i++) { + // One msgpack array-of-1 per trace, matching the background sender's framing. + ddog_CharSlice payload = ddog_serialize_trace_into_charslice(ddog_get_trace(v04_traces, i)); + if (payload.len > 0 && payload.len <= limit) { + if (!ddtrace_send_traces_via_thread(1, payload.ptr, payload.len)) { success = false; - } else { - success = ddtrace_send_traces_via_thread(1, serialized_trace.ptr, serialized_trace.len); - if (success) { - LOGEV(INFO, { - log("Flushing trace of size %d to send-queue for %s", ddog_get_trace_size(trace), url); - }); - } - dd_prepare_for_new_trace(); } - - ddog_free_charslice(serialized_trace); + // Bump the coms group id per trace: the background sender sizes the outer msgpack + // array by the number of distinct group ids, so each trace needs its own id or N>1 + // traces collapse to array-of-1 and the agent keeps only the first. + dd_prepare_for_new_trace(); } else { + if (payload.len > limit) { + LOG(ERROR, "Agent request payload of %zu bytes exceeds configured %zu byte limit; dropping request", payload.len, limit); + } success = false; } + ddog_free_charslice(payload); + } + if (success) { + LOGEV(INFO, { + log("Flushing %zu v0.4 trace(s) to send-queue for %s", trace_count, url); + }); } + ddog_free_traces(v04_traces); #else + ddog_v1_free_builder(ctx->builder); // in-process sender unavailable on Windows; not consumed success = false; #endif } free(url); - ddog_free_traces(traces); return success ? SUCCESS : FAILURE; } diff --git a/tracer/code_origins.c b/tracer/code_origins.c index 44977c41b2..0b91c93e70 100644 --- a/tracer/code_origins.c +++ b/tracer/code_origins.c @@ -12,7 +12,7 @@ static inline bool dd_is_dir_sep(const char c) { } void ddtrace_add_code_origin_information(ddtrace_span_data *span, int skip_frames) { - zend_array *meta = ddtrace_property_array(&span->property_meta); + zend_array *meta = ddtrace_property_array(&span->property_attributes); zend_long max_frames = get_DD_CODE_ORIGIN_MAX_USER_FRAMES(); int current_frame = 0, collected_frames = 0; @@ -42,7 +42,10 @@ void ddtrace_add_code_origin_information(ddtrace_span_data *span, int skip_frame } if (collected_frames == 0) { - zval type, *kind = zend_hash_str_find_deref(meta, ZEND_STRL("span.kind")); + zval type, *kind = ddtrace_span_find_tag(span, ZEND_STRL("span.kind")); + if (kind) { + ZVAL_DEREF(kind); + } ZVAL_STRING(&type, (kind && Z_TYPE_P(kind) == IS_STRING ? zend_string_equals_literal(Z_STR_P(kind), "server") || zend_string_equals_literal(Z_STR_P(kind), "producer") : &span->root->span == span) ? "entry" : "exit"); if (!zend_hash_str_add(meta, ZEND_STRL("_dd.code_origin.type"), &type)) { zend_string_release(Z_STR(type)); @@ -59,7 +62,8 @@ void ddtrace_add_code_origin_information(ddtrace_span_data *span, int skip_frame zend_string_release(key); key = zend_strpprintf(0, "_dd.code_origin.frames.%d.line", current_frame); - ZVAL_LONG(&zv, current_frame == 0 ? EX(func)->op_array.line_start : EX(opline)->lineno); + // A string, as the tag was when it lived in meta. + ZVAL_STR(&zv, zend_long_to_str(current_frame == 0 ? EX(func)->op_array.line_start : EX(opline)->lineno)); zend_hash_update(meta, key, &zv); zend_string_release(key); @@ -89,11 +93,9 @@ void ddtrace_maybe_add_code_origin_information(ddtrace_span_data *span, int skip if (Z_TYPE_P(type) == IS_STRING && Z_STRLEN_P(type) != 0) { // If it's identical, we don't add it to the child so that only the parent span will be added the code origin information if (span->parent && zend_is_identical(type, &span->parent->property_type)) { - zend_array *meta = ddtrace_property_array(&span->property_meta); - zval *kind = zend_hash_str_find(meta, ZEND_STRL("span.kind")); + zval *kind = ddtrace_span_find_tag(span, ZEND_STRL("span.kind")); if (kind) { - zend_array *parent_meta = ddtrace_property_array(&span->parent->property_meta); - zval *parent_kind = zend_hash_str_find(parent_meta, ZEND_STRL("span.kind")); + zval *parent_kind = ddtrace_span_find_tag(SPANDATA(span->parent), ZEND_STRL("span.kind")); // span.kind must match, otherwise websocket has false positives for example, where both entry and exit span have type websocket if (!parent_kind || zend_is_identical(kind, parent_kind)) { return; diff --git a/tracer/coms.c b/tracer/coms.c index d241fd2c34..f0e2a6d107 100644 --- a/tracer/coms.c +++ b/tracer/coms.c @@ -916,6 +916,7 @@ static void ddtrace_curl_set_hostname_generic(CURL *curl, const char *path) { } void ddtrace_curl_set_hostname(CURL *curl) { + // The in-process (<=8.2) background sender is v0.4-only. ddtrace_curl_set_hostname_generic(curl, TRACE_PATH_STR); } diff --git a/tracer/configuration.h b/tracer/configuration.h index 892cdce071..21de4fc3af 100644 --- a/tracer/configuration.h +++ b/tracer/configuration.h @@ -11,11 +11,9 @@ #define DD_INTEGRATION_ANALYTICS_ENABLED_DEFAULT false #define DD_INTEGRATION_ANALYTICS_SAMPLE_RATE_DEFAULT 1.0 -#if PHP_VERSION_ID >= 80300 || defined(_WIN32) +// Sidecar is the default trace sender on all PHP versions (in-process coms.c sender is the +// DD_TRACE_SIDECAR_TRACE_SENDER=0 opt-in). Thread mode isn't pcntl_fork()-safe; auto falls back. #define DD_SIDECAR_TRACE_SENDER_DEFAULT true -#else -#define DD_SIDECAR_TRACE_SENDER_DEFAULT false -#endif #if _BUILD_FROM_PECL_ #define DD_DEFAULT_SOURCES_PATH "@php_dir@/datadog_trace/src/" @@ -117,7 +115,6 @@ CONFIG(BOOL, DD_TRACE_AGENT_DEBUG_VERBOSE_CURL, "false", .ini_change = zai_config_system_ini_change) \ CONFIG(BOOL, DD_TRACE_DEBUG_CURL_OUTPUT, "false", .ini_change = zai_config_system_ini_change) \ CONFIG(INT, DD_TRACE_BETA_HIGH_MEMORY_PRESSURE_PERCENT, "80", .ini_change = zai_config_system_ini_change) \ - CONFIG(BOOL, DD_TRACE_WARN_LEGACY_DD_TRACE, "true") \ CONFIG(BOOL, DD_TRACE_RETAIN_THREAD_CAPABILITIES, "false", .ini_change = zai_config_system_ini_change) \ CONFIG(STRING, DD_TRACE_OBFUSCATION_QUERY_STRING_REGEXP, DD_TRACE_OBFUSCATION_QUERY_STRING_REGEXP_DEFAULT) \ CONFIG(BOOL, DD_TRACE_MEMCACHED_OBFUSCATION, "true") \ diff --git a/tracer/configuration_dependencies.h b/tracer/configuration_dependencies.h index 4518e2c583..bc662c47ac 100644 --- a/tracer/configuration_dependencies.h +++ b/tracer/configuration_dependencies.h @@ -66,6 +66,19 @@ static bool dd_parse_sidecar_connection_mode(zai_str value, zval *decoded_value, return true; } +static bool dd_parse_trace_agent_protocol_version(zai_str value, zval *decoded_value, bool persistent) { + UNUSED(persistent); + if (zai_str_eq_ci_cstr(value, "1.0") || zai_str_eq_ci_cstr(value, "1")) { + ZVAL_LONG(decoded_value, DD_TRACE_AGENT_PROTOCOL_VERSION_V1); + } else if (zai_str_eq_ci_cstr(value, "0.4")) { + ZVAL_LONG(decoded_value, DD_TRACE_AGENT_PROTOCOL_VERSION_V04); + } else { + return false; + } + + return true; +} + static bool dd_parse_tags(zai_str value, zval *decoded_value, bool persistent) { ZVAL_ARR(decoded_value, pemalloc(sizeof(HashTable), persistent)); zend_hash_init(Z_ARR_P(decoded_value), 8, NULL, persistent ? ZVAL_INTERNAL_PTR_DTOR : ZVAL_PTR_DTOR, persistent); diff --git a/tracer/ddtrace.h b/tracer/ddtrace.h index 3a3bf90f9c..7f24c17dbf 100644 --- a/tracer/ddtrace.h +++ b/tracer/ddtrace.h @@ -16,6 +16,7 @@ extern zend_class_entry *ddtrace_ce_span_event; extern zend_class_entry *ddtrace_ce_exception_span_event; extern zend_class_entry *ddtrace_ce_integration; extern zend_class_entry *ddtrace_ce_git_metadata; +extern zend_class_entry *ddtrace_ce_span_kind; typedef struct ddtrace_span_ids_t ddtrace_span_ids_t; typedef struct ddtrace_span_data ddtrace_span_data; diff --git a/tracer/ddtrace.stub.php b/tracer/ddtrace.stub.php index adac5b1f10..6f483cf590 100644 --- a/tracer/ddtrace.stub.php +++ b/tracer/ddtrace.stub.php @@ -73,7 +73,7 @@ final class FfeResult { public ?int $configVersion = null; } - class SpanEvent implements \JsonSerializable { + class SpanEvent { /** * SpanEvent constructor. * @@ -97,11 +97,6 @@ public function __construct(string $name, array $attributes = [], ?int $timestam * @var int The event start time in nanoseconds, if not provided set the current Unix timestamp */ public int $timestamp; - - /** - * @return mixed - */ - public function jsonSerialize(): mixed {} } class ExceptionSpanEvent extends SpanEvent { @@ -119,7 +114,7 @@ public function __construct(\Throwable $exception, array $attributes = []) {} public \Throwable $exception; } - class SpanLink implements \JsonSerializable { + class SpanLink { /** * @var string $traceId A 32-character, lower-case hexadecimal encoded string of the linked trace ID. This field * shouldn't be directly assigned an id from SpanData. Use the SpanData::getLink() method instead. @@ -147,11 +142,6 @@ class SpanLink implements \JsonSerializable { */ public int $droppedAttributesCount; - /** - * @return mixed - */ - public function jsonSerialize(): mixed {} - /** * Consumes distributed tracing headers, from which a span link will be constructed. * @@ -173,6 +163,21 @@ class GitMetadata { public string $repositoryUrl = ""; } + class SpanKind { + /** @var int */ + const UNSPECIFIED = 0; + /** @var int */ + const INTERNAL = 1; + /** @var int */ + const SERVER = 2; + /** @var int */ + const CLIENT = 3; + /** @var int */ + const PRODUCER = 4; + /** @var int */ + const CONSUMER = 5; + } + class SpanData { /** * @var string|null The span name @@ -190,18 +195,6 @@ class SpanData { */ public string|null $service = ""; - /** - * @var string The environment you are tracing. Defaults to active environment at the time of span creation - * (i.e., the parent span), or datadog.env initialization settings if no parent exists - */ - public string $env = ""; - - /** - * @var string The version of the application you are tracing. Defaults to active version at the time of - * span creation (i.e., the parent span), or datadog.version initialization settings if no parent exists - */ - public string $version = ""; - /** * @var string[] Meta struct can be used to send any data to the backend. The peculiarity of meta struct is * that the values are encoded with msgpack when sent to the agent. The values are first encoded to msgpack @@ -216,14 +209,16 @@ class SpanData { public string|null $type = ""; /** - * @var string[] $meta An array of key-value span metadata; keys and values must be strings. + * @var string[] $meta A view onto the non-numeric entries of $attributes; values are stored as strings. + * @deprecated Use $attributes. Setting meta['error.ignored'] is deprecated too: use $ignoreError. */ - public array $meta = []; + public $meta = []; /** - * @var float[] $metrics An array of key-value span metrics; keys must be strings and values must be floats. + * @var float[] $metrics A view onto the numeric entries of $attributes; values are stored as floats. + * @deprecated Use $attributes. */ - public array $metrics = []; + public $metrics = []; /** * @var \Throwable|null $exception An exception generated during the execution of the original function, if any. @@ -296,6 +291,34 @@ public function hexId(): string {} * Baggage is a key-value store, which means it lets you propagate any data you like alongside context regardless of trace ids existence. */ public array $baggage = []; + + /** + * @var string The environment you are tracing. Defaults to active environment at the time of span creation + * (i.e., the parent span), or datadog.env initialization settings if no parent exists + */ + public string $env = ""; + + /** + * @var string The version of the application you are tracing. Defaults to active version at the time of + * span creation (i.e., the parent span), or datadog.version initialization settings if no parent exists + */ + public string $version = ""; + + public string $component = ""; + + public int $spanKind = 0; + + /** + * @var array $attributes Span attributes, keeping their type: bool, int, float, string, or nested arrays + * and objects. Null values are skipped. + */ + public array $attributes = []; + + /** + * @var bool $ignoreError Set to true to not report this span as an error, even if it has an exception or + * error tags. + */ + public bool $ignoreError = false; } class InferredSpanData extends SpanData {} @@ -316,6 +339,8 @@ class RootSpanData extends SpanData { */ public int $samplingPriority = \DD_TRACE_PRIORITY_SAMPLING_UNKNOWN; + public int $samplingMechanism = 0; + /** * @var int The unmodified sampling priority as inherited directly through distributed tracing. */ @@ -353,6 +378,8 @@ class RootSpanData extends SpanData { public GitMetadata|null $gitMetadata = null; public InferredSpanData|null $inferredSpan = null; + + public string $hostname = ""; } /** @@ -386,6 +413,8 @@ class SpanStack { * removal. */ public array $spanCreationObservers = []; + + public array $attributes = []; } interface Integration { @@ -537,7 +566,7 @@ function hook_method( // phpcs:enable Generic.Files.LineLength.TooLong /** - * Add a tag to be automatically applied to every span that is created, if tracing is enabled. + * Add a tag to be automatically applied to every spanStack that is created, if tracing is enabled. * * @param string $key Tag key * @param string $value Tag Value @@ -754,6 +783,7 @@ function startup_logs(): string {} /** * Return the id of the current trace * + * @deprecated This function is deprecated and should not be used. * @return string The id of the current trace */ function trace_id(): string {} @@ -773,6 +803,7 @@ function logs_correlation_trace_id(): string {} /** * Get information on the current context * + * @deprecated This function is deprecated and should not be used. * @return array{trace_id: string, span_id: string, version: string, env: string} */ function current_context(): array {} @@ -783,7 +814,7 @@ function current_context(): array {} * * The distributed tracing context can be reset by calling 'set_distributed_tracing_context("0", "0")' * - * @param string $traceId The unique integer (128-bit unsigned) ID of the trace containing this span + * @param string $traceId The unique integer (128-bit hex unsigned) ID of the trace containing this span * @param string $parentId The span integer ID of the parent span * @param string|null $origin The distributed tracing origin * @param array|string|null $propagated_tags If provided, propagated tags from the root span will be cleared and @@ -949,25 +980,6 @@ function container_id(): string|null {} function process_tags_base_hash(): string|null {} } -namespace DDTrace\Config { - - /** - * Check if the app analytics of an app is enabled for a given integration - * - * @param string $integrationName The name of the integration (e.g., mysqli) - * @return bool The status of the app analytics of the integration - */ - function integration_analytics_enabled(string $integrationName): bool {} - - /** - * Check the app analytics sample rate of a given integration - * - * @param string $integrationName The name of the integration (e.g., mysqli) - * @return float The sample rate of the app analytics of the integration - */ - function integration_analytics_sample_rate(string $integrationName): float {} -} - namespace DDTrace\UserRequest { /** * If there are any listeners of user request events. @@ -1177,31 +1189,6 @@ function dd_trace_env_config(string $envName): mixed {} */ function dd_trace_disable_in_request(): bool {} - /** - * (Noop/To do) Untrace traced functions and methods - * - * @internal - * @return bool 'true' if reset was successful, else 'false' - */ - function dd_trace_reset(): bool {} - - /** - * If tracing is enabled, serialize the trace into a string to send to the agent - * - * @internal - * @param array $traceArray Serialize values must be of type array, string, int, float, bool or null - * @return bool|string The serialized array, else 'false' if an error was encountered - */ - function dd_trace_serialize_msgpack(array $traceArray): bool|string {} - - /** - * Null function to easily breakpoint the execution at specific PHP line in GDB - * - * @internal - * @return bool Return 'true' if tracing is enabled, else 'false' - */ - function dd_trace_noop(mixed ...$args): bool {} - /** * Get the parsed value of the memory limit DD_TRACE_MEMORY_LIMIT in binary bytes * @@ -1219,6 +1206,7 @@ function dd_trace_check_memory_under_limit(): bool {} /** * Get the name of the app (DD_SERVICE) * + * @deprecated This function is deprecated and should not be used. * @param string|null $fallbackName Fallback name if the app's name wasn't set * @return string|null The app name, else the fallback name. Return 'null' if the app name isn't set and no * fallback name is provided. @@ -1228,6 +1216,7 @@ function ddtrace_config_app_name(?string $fallbackName = null): null|string {} /** * Check if distributed tracing is enabled (DD_DISTRIBUTED_TRACING) * + * @deprecated This function is deprecated and should not be used. * @return bool 'true' if distributed tracing is enabled, else 'false' */ function ddtrace_config_distributed_tracing_enabled(): bool {} @@ -1235,6 +1224,7 @@ function ddtrace_config_distributed_tracing_enabled(): bool {} /** * Check if tracing is enabled (DD_TRACE_ENABLED) * + * @deprecated This function is deprecated and should not be used. * @return bool 'true' is tracing is enabled, else 'false' */ function ddtrace_config_trace_enabled(): bool {} @@ -1247,35 +1237,6 @@ function ddtrace_config_trace_enabled(): bool {} */ function ddtrace_config_integration_enabled(string $integrationName): bool {} - /** - * Send payload to background sender's buffer - * - * @internal - * @param int $numTraces Trace count. Note that at the moment, the background sender is only capable of sending - * exactly one trace - * @param array $curlHeaders HTTP Headers - * @param string $payload HTTP Body - * @return bool 'true' if tracers were successfully sent or if the tracer is disabled, and 'false' if not exactly - * one trace was sent or if the procedure was unsuccessful - */ - function dd_trace_send_traces_via_thread(int $numTraces, array $curlHeaders, string $payload): bool {} - - /** - * Serializes and sends traces to the agent (in the format dd_trace_serialize_closed_spans() returns spans). - * - * @internal - * @param array $traceArray Array in the format returned by dd_trace_serialize_closed_spans() - */ - function dd_trace_buffer_span(array $traceArray): bool {} - - /** - * Used to send any already buffered spans to the agent - * - * @internal - * @return int - */ - function dd_trace_coms_trigger_writer_flush(): int {} - /** * Execute a given internal function * @@ -1293,6 +1254,7 @@ function dd_trace_internal_fn(string $functionName, mixed ...$args) {} /** * Set the distributed trace id * + * @deprecated This function is deprecated and should not be used. * @param string|null $traceId New trace id * @return bool 'true' if the change was properly applied, else 'false' */ @@ -1315,6 +1277,7 @@ function dd_trace_tracer_is_limited(): bool {} /** * Get the compiling time of all files compiled up to now (in µs) * + * @deprecated This function is deprecated and should not be used. * @return int Compile time */ function dd_trace_compile_time_microseconds(): int {} @@ -1342,11 +1305,13 @@ function dd_trace_peek_span_id(): string {} function dd_trace_close_all_spans_and_flush(): void {} /** + * @deprecated This function is deprecated and should not be used. * @alias DDTrace_trace_function */ function dd_trace_function(string $functionName, \Closure|array|null $tracingClosureOrConfigArray): bool {} /** + * @deprecated This function is deprecated and should not be used. * @alias DDTrace_trace_method */ function dd_trace_method( diff --git a/tracer/ddtrace_arginfo.h b/tracer/ddtrace_arginfo.h index afa0f62d9f..ddfe7a6dd7 100644 --- a/tracer/ddtrace_arginfo.h +++ b/tracer/ddtrace_arginfo.h @@ -1,5 +1,5 @@ -/* This is a generated file, edit ddtrace.stub.php instead. - * Stub hash: b3087c1f239d5aa8ea38f875b7236f47e56a1ca7 */ +/* This is a generated file, edit the .stub.php file instead. + * Stub hash: f24f35fb55682e040fd9c2e3e6ec535f0e365194 */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_DDTrace_trace_method, 0, 3, _IS_BOOL, 0) ZEND_ARG_TYPE_INFO(0, className, IS_STRING, 0) @@ -184,31 +184,16 @@ ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_DDTrace_ffe_evaluate, 0, 4, DDTra ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, recordMetric, _IS_BOOL, 0, "true") ZEND_END_ARG_INFO() -ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_DDTrace_ffe_has_config, 0, 0, _IS_BOOL, 0) -ZEND_END_ARG_INFO() +#define arginfo_DDTrace_ffe_has_config arginfo_DDTrace_are_endpoints_collected ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_DDTrace_ffe_config_version, 0, 0, IS_LONG, 0) ZEND_END_ARG_INFO() -ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_DDTrace_Testing_ffe_load_config, 0, 1, _IS_BOOL, 0) - ZEND_ARG_TYPE_INFO(0, json, IS_STRING, 0) -ZEND_END_ARG_INFO() - -#define arginfo_DDTrace_Testing_flush_ffe_exposures arginfo_DDTrace_are_endpoints_collected - ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_DDTrace_System_container_id, 0, 0, IS_STRING, 1) ZEND_END_ARG_INFO() #define arginfo_DDTrace_System_process_tags_base_hash arginfo_DDTrace_System_container_id -ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_DDTrace_Config_integration_analytics_enabled, 0, 1, _IS_BOOL, 0) - ZEND_ARG_TYPE_INFO(0, integrationName, IS_STRING, 0) -ZEND_END_ARG_INFO() - -ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_DDTrace_Config_integration_analytics_sample_rate, 0, 1, IS_DOUBLE, 0) - ZEND_ARG_TYPE_INFO(0, integrationName, IS_STRING, 0) -ZEND_END_ARG_INFO() - #define arginfo_DDTrace_UserRequest_has_listeners arginfo_DDTrace_are_endpoints_collected ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_DDTrace_UserRequest_notify_start, 0, 2, IS_ARRAY, 1) @@ -229,6 +214,12 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_DDTrace_UserRequest_set_blocking ZEND_ARG_TYPE_INFO(0, blockingFunction, IS_CALLABLE, 0) ZEND_END_ARG_INFO() +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_DDTrace_Testing_ffe_load_config, 0, 1, _IS_BOOL, 0) + ZEND_ARG_TYPE_INFO(0, json, IS_STRING, 0) +ZEND_END_ARG_INFO() + +#define arginfo_DDTrace_Testing_flush_ffe_exposures arginfo_DDTrace_are_endpoints_collected + ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_DDTrace_Testing_trigger_error, 0, 2, IS_VOID, 0) ZEND_ARG_TYPE_INFO(0, message, IS_STRING, 0) ZEND_ARG_TYPE_INFO(0, errorType, IS_LONG, 0) @@ -255,8 +246,7 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_DDTrace_Internal_record_ffe_eval ZEND_ARG_TYPE_INFO(0, allocationKey, IS_STRING, 1) ZEND_END_ARG_INFO() -ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_DDTrace_Internal_flush_ffe_evaluation_metrics, 0, 0, _IS_BOOL, 0) -ZEND_END_ARG_INFO() +#define arginfo_DDTrace_Internal_flush_ffe_evaluation_metrics arginfo_DDTrace_are_endpoints_collected ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_datadog_appsec_v2_track_user_login_success, 0, 1, IS_VOID, 0) ZEND_ARG_TYPE_INFO(0, login, IS_STRING, 0) @@ -276,18 +266,7 @@ ZEND_END_ARG_INFO() #define arginfo_dd_trace_disable_in_request arginfo_DDTrace_are_endpoints_collected -#define arginfo_dd_trace_reset arginfo_DDTrace_are_endpoints_collected - -ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_dd_trace_serialize_msgpack, 0, 1, MAY_BE_BOOL|MAY_BE_STRING) - ZEND_ARG_TYPE_INFO(0, traceArray, IS_ARRAY, 0) -ZEND_END_ARG_INFO() - -ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_dd_trace_noop, 0, 0, _IS_BOOL, 0) - ZEND_ARG_VARIADIC_TYPE_INFO(0, args, IS_MIXED, 0) -ZEND_END_ARG_INFO() - -ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_dd_trace_dd_get_memory_limit, 0, 0, IS_LONG, 0) -ZEND_END_ARG_INFO() +#define arginfo_dd_trace_dd_get_memory_limit arginfo_DDTrace_ffe_config_version #define arginfo_dd_trace_check_memory_under_limit arginfo_DDTrace_are_endpoints_collected @@ -299,20 +278,10 @@ ZEND_END_ARG_INFO() #define arginfo_ddtrace_config_trace_enabled arginfo_DDTrace_are_endpoints_collected -#define arginfo_ddtrace_config_integration_enabled arginfo_DDTrace_Config_integration_analytics_enabled - -ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_dd_trace_send_traces_via_thread, 0, 3, _IS_BOOL, 0) - ZEND_ARG_TYPE_INFO(0, numTraces, IS_LONG, 0) - ZEND_ARG_TYPE_INFO(0, curlHeaders, IS_ARRAY, 0) - ZEND_ARG_TYPE_INFO(0, payload, IS_STRING, 0) -ZEND_END_ARG_INFO() - -ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_dd_trace_buffer_span, 0, 1, _IS_BOOL, 0) - ZEND_ARG_TYPE_INFO(0, traceArray, IS_ARRAY, 0) +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_ddtrace_config_integration_enabled, 0, 1, _IS_BOOL, 0) + ZEND_ARG_TYPE_INFO(0, integrationName, IS_STRING, 0) ZEND_END_ARG_INFO() -#define arginfo_dd_trace_coms_trigger_writer_flush arginfo_dd_trace_dd_get_memory_limit - ZEND_BEGIN_ARG_INFO_EX(arginfo_dd_trace_internal_fn, 0, 0, 1) ZEND_ARG_TYPE_INFO(0, functionName, IS_STRING, 0) ZEND_ARG_VARIADIC_TYPE_INFO(0, args, IS_MIXED, 0) @@ -322,11 +291,11 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_dd_trace_set_trace_id, 0, 0, _IS ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, traceId, IS_STRING, 1, "null") ZEND_END_ARG_INFO() -#define arginfo_dd_trace_closed_spans_count arginfo_dd_trace_dd_get_memory_limit +#define arginfo_dd_trace_closed_spans_count arginfo_DDTrace_ffe_config_version #define arginfo_dd_trace_tracer_is_limited arginfo_DDTrace_are_endpoints_collected -#define arginfo_dd_trace_compile_time_microseconds arginfo_dd_trace_dd_get_memory_limit +#define arginfo_dd_trace_compile_time_microseconds arginfo_DDTrace_ffe_config_version #define arginfo_dd_trace_serialize_closed_spans arginfo_DDTrace_current_context @@ -357,30 +326,25 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_DDTrace_SpanEvent___construct, 0, 0, 1) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, timestamp, IS_LONG, 1, "null") ZEND_END_ARG_INFO() -ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_DDTrace_SpanEvent_jsonSerialize, 0, 0, IS_MIXED, 0) -ZEND_END_ARG_INFO() - ZEND_BEGIN_ARG_INFO_EX(arginfo_class_DDTrace_ExceptionSpanEvent___construct, 0, 0, 1) ZEND_ARG_OBJ_INFO(0, exception, Throwable, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, attributes, IS_ARRAY, 0, "[]") ZEND_END_ARG_INFO() -#define arginfo_class_DDTrace_SpanLink_jsonSerialize arginfo_class_DDTrace_SpanEvent_jsonSerialize - ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_DDTrace_SpanLink_fromHeaders, 0, 1, DDTrace\\SpanLink, 0) ZEND_ARG_TYPE_MASK(0, headersOrCallback, MAY_BE_ARRAY|MAY_BE_CALLABLE, NULL) ZEND_END_ARG_INFO() -#define arginfo_class_DDTrace_SpanData_getDuration arginfo_dd_trace_dd_get_memory_limit +#define arginfo_class_DDTrace_SpanData_getDuration arginfo_DDTrace_ffe_config_version -#define arginfo_class_DDTrace_SpanData_getStartTime arginfo_dd_trace_dd_get_memory_limit +#define arginfo_class_DDTrace_SpanData_getStartTime arginfo_DDTrace_ffe_config_version ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_DDTrace_SpanData_getLink, 0, 0, DDTrace\\SpanLink, 0) ZEND_END_ARG_INFO() #define arginfo_class_DDTrace_SpanData_hexId arginfo_DDTrace_startup_logs -#define arginfo_class_DDTrace_Integration_init arginfo_dd_trace_dd_get_memory_limit +#define arginfo_class_DDTrace_Integration_init arginfo_DDTrace_ffe_config_version ZEND_FUNCTION(DDTrace_trace_method); ZEND_FUNCTION(DDTrace_trace_function); @@ -428,16 +392,14 @@ ZEND_FUNCTION(DDTrace_flush_endpoints); ZEND_FUNCTION(DDTrace_ffe_evaluate); ZEND_FUNCTION(DDTrace_ffe_has_config); ZEND_FUNCTION(DDTrace_ffe_config_version); -ZEND_FUNCTION(DDTrace_Testing_ffe_load_config); -ZEND_FUNCTION(DDTrace_Testing_flush_ffe_exposures); ZEND_FUNCTION(DDTrace_System_container_id); ZEND_FUNCTION(DDTrace_System_process_tags_base_hash); -ZEND_FUNCTION(DDTrace_Config_integration_analytics_enabled); -ZEND_FUNCTION(DDTrace_Config_integration_analytics_sample_rate); ZEND_FUNCTION(DDTrace_UserRequest_has_listeners); ZEND_FUNCTION(DDTrace_UserRequest_notify_start); ZEND_FUNCTION(DDTrace_UserRequest_notify_commit); ZEND_FUNCTION(DDTrace_UserRequest_set_blocking_function); +ZEND_FUNCTION(DDTrace_Testing_ffe_load_config); +ZEND_FUNCTION(DDTrace_Testing_flush_ffe_exposures); ZEND_FUNCTION(DDTrace_Testing_trigger_error); ZEND_FUNCTION(DDTrace_Testing_emit_asm_event); ZEND_FUNCTION(DDTrace_Testing_normalize_tag_value); @@ -449,18 +411,12 @@ ZEND_FUNCTION(datadog_appsec_v2_track_user_login_success); ZEND_FUNCTION(datadog_appsec_v2_track_user_login_failure); ZEND_FUNCTION(dd_trace_env_config); ZEND_FUNCTION(dd_trace_disable_in_request); -ZEND_FUNCTION(dd_trace_reset); -ZEND_FUNCTION(dd_trace_serialize_msgpack); -ZEND_FUNCTION(dd_trace_noop); ZEND_FUNCTION(dd_trace_dd_get_memory_limit); ZEND_FUNCTION(dd_trace_check_memory_under_limit); ZEND_FUNCTION(ddtrace_config_app_name); ZEND_FUNCTION(ddtrace_config_distributed_tracing_enabled); ZEND_FUNCTION(ddtrace_config_trace_enabled); ZEND_FUNCTION(ddtrace_config_integration_enabled); -ZEND_FUNCTION(dd_trace_send_traces_via_thread); -ZEND_FUNCTION(dd_trace_buffer_span); -ZEND_FUNCTION(dd_trace_coms_trigger_writer_flush); ZEND_FUNCTION(dd_trace_internal_fn); ZEND_FUNCTION(dd_trace_set_trace_id); ZEND_FUNCTION(dd_trace_closed_spans_count); @@ -474,9 +430,7 @@ ZEND_FUNCTION(DDTrace_trace_method); ZEND_FUNCTION(dd_untrace); ZEND_FUNCTION(dd_trace_synchronous_flush); ZEND_METHOD(DDTrace_SpanEvent, __construct); -ZEND_METHOD(DDTrace_SpanEvent, jsonSerialize); ZEND_METHOD(DDTrace_ExceptionSpanEvent, __construct); -ZEND_METHOD(DDTrace_SpanLink, jsonSerialize); ZEND_METHOD(DDTrace_SpanLink, fromHeaders); ZEND_METHOD(DDTrace_SpanData, getDuration); ZEND_METHOD(DDTrace_SpanData, getStartTime); @@ -532,8 +486,6 @@ static const zend_function_entry ext_functions[] = { ZEND_RAW_FENTRY(ZEND_NS_NAME("DDTrace", "ffe_config_version"), zif_DDTrace_ffe_config_version, arginfo_DDTrace_ffe_config_version, 0, NULL, NULL) ZEND_RAW_FENTRY(ZEND_NS_NAME("DDTrace\\System", "container_id"), zif_DDTrace_System_container_id, arginfo_DDTrace_System_container_id, 0, NULL, NULL) ZEND_RAW_FENTRY(ZEND_NS_NAME("DDTrace\\System", "process_tags_base_hash"), zif_DDTrace_System_process_tags_base_hash, arginfo_DDTrace_System_process_tags_base_hash, 0, NULL, NULL) - ZEND_RAW_FENTRY(ZEND_NS_NAME("DDTrace\\Config", "integration_analytics_enabled"), zif_DDTrace_Config_integration_analytics_enabled, arginfo_DDTrace_Config_integration_analytics_enabled, 0, NULL, NULL) - ZEND_RAW_FENTRY(ZEND_NS_NAME("DDTrace\\Config", "integration_analytics_sample_rate"), zif_DDTrace_Config_integration_analytics_sample_rate, arginfo_DDTrace_Config_integration_analytics_sample_rate, 0, NULL, NULL) ZEND_RAW_FENTRY(ZEND_NS_NAME("DDTrace\\UserRequest", "has_listeners"), zif_DDTrace_UserRequest_has_listeners, arginfo_DDTrace_UserRequest_has_listeners, 0, NULL, NULL) ZEND_RAW_FENTRY(ZEND_NS_NAME("DDTrace\\UserRequest", "notify_start"), zif_DDTrace_UserRequest_notify_start, arginfo_DDTrace_UserRequest_notify_start, 0, NULL, NULL) ZEND_RAW_FENTRY(ZEND_NS_NAME("DDTrace\\UserRequest", "notify_commit"), zif_DDTrace_UserRequest_notify_commit, arginfo_DDTrace_UserRequest_notify_commit, 0, NULL, NULL) @@ -551,23 +503,17 @@ static const zend_function_entry ext_functions[] = { ZEND_RAW_FENTRY(ZEND_NS_NAME("datadog\\appsec\\v2", "track_user_login_failure"), zif_datadog_appsec_v2_track_user_login_failure, arginfo_datadog_appsec_v2_track_user_login_failure, 0, NULL, NULL) ZEND_FE(dd_trace_env_config, arginfo_dd_trace_env_config) ZEND_FE(dd_trace_disable_in_request, arginfo_dd_trace_disable_in_request) - ZEND_FE(dd_trace_reset, arginfo_dd_trace_reset) - ZEND_FE(dd_trace_serialize_msgpack, arginfo_dd_trace_serialize_msgpack) - ZEND_FE(dd_trace_noop, arginfo_dd_trace_noop) ZEND_FE(dd_trace_dd_get_memory_limit, arginfo_dd_trace_dd_get_memory_limit) ZEND_FE(dd_trace_check_memory_under_limit, arginfo_dd_trace_check_memory_under_limit) - ZEND_FE(ddtrace_config_app_name, arginfo_ddtrace_config_app_name) - ZEND_FE(ddtrace_config_distributed_tracing_enabled, arginfo_ddtrace_config_distributed_tracing_enabled) - ZEND_FE(ddtrace_config_trace_enabled, arginfo_ddtrace_config_trace_enabled) + ZEND_RAW_FENTRY("ddtrace_config_app_name", zif_ddtrace_config_app_name, arginfo_ddtrace_config_app_name, 0, NULL, NULL) + ZEND_RAW_FENTRY("ddtrace_config_distributed_tracing_enabled", zif_ddtrace_config_distributed_tracing_enabled, arginfo_ddtrace_config_distributed_tracing_enabled, 0, NULL, NULL) + ZEND_RAW_FENTRY("ddtrace_config_trace_enabled", zif_ddtrace_config_trace_enabled, arginfo_ddtrace_config_trace_enabled, 0, NULL, NULL) ZEND_FE(ddtrace_config_integration_enabled, arginfo_ddtrace_config_integration_enabled) - ZEND_FE(dd_trace_send_traces_via_thread, arginfo_dd_trace_send_traces_via_thread) - ZEND_FE(dd_trace_buffer_span, arginfo_dd_trace_buffer_span) - ZEND_FE(dd_trace_coms_trigger_writer_flush, arginfo_dd_trace_coms_trigger_writer_flush) ZEND_FE(dd_trace_internal_fn, arginfo_dd_trace_internal_fn) - ZEND_FE(dd_trace_set_trace_id, arginfo_dd_trace_set_trace_id) + ZEND_RAW_FENTRY("dd_trace_set_trace_id", zif_dd_trace_set_trace_id, arginfo_dd_trace_set_trace_id, 0, NULL, NULL) ZEND_FE(dd_trace_closed_spans_count, arginfo_dd_trace_closed_spans_count) ZEND_FE(dd_trace_tracer_is_limited, arginfo_dd_trace_tracer_is_limited) - ZEND_FE(dd_trace_compile_time_microseconds, arginfo_dd_trace_compile_time_microseconds) + ZEND_RAW_FENTRY("dd_trace_compile_time_microseconds", zif_dd_trace_compile_time_microseconds, arginfo_dd_trace_compile_time_microseconds, 0, NULL, NULL) ZEND_FE(dd_trace_serialize_closed_spans, arginfo_dd_trace_serialize_closed_spans) ZEND_FE(dd_trace_peek_span_id, arginfo_dd_trace_peek_span_id) ZEND_FE(dd_trace_close_all_spans_and_flush, arginfo_dd_trace_close_all_spans_and_flush) @@ -580,7 +526,6 @@ static const zend_function_entry ext_functions[] = { static const zend_function_entry class_DDTrace_SpanEvent_methods[] = { ZEND_ME(DDTrace_SpanEvent, __construct, arginfo_class_DDTrace_SpanEvent___construct, ZEND_ACC_PUBLIC) - ZEND_ME(DDTrace_SpanEvent, jsonSerialize, arginfo_class_DDTrace_SpanEvent_jsonSerialize, ZEND_ACC_PUBLIC) ZEND_FE_END }; @@ -590,7 +535,6 @@ static const zend_function_entry class_DDTrace_ExceptionSpanEvent_methods[] = { }; static const zend_function_entry class_DDTrace_SpanLink_methods[] = { - ZEND_ME(DDTrace_SpanLink, jsonSerialize, arginfo_class_DDTrace_SpanLink_jsonSerialize, ZEND_ACC_PUBLIC) ZEND_ME(DDTrace_SpanLink, fromHeaders, arginfo_class_DDTrace_SpanLink_fromHeaders, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) ZEND_FE_END }; @@ -639,39 +583,39 @@ static zend_class_entry *register_class_DDTrace_FfeResult(void) zval property_valueJson_default_value; ZVAL_NULL(&property_valueJson_default_value); - zend_string *property_valueJson_name = zend_string_init("valueJson", sizeof("valueJson") - 1, true); + zend_string *property_valueJson_name = zend_string_init("valueJson", sizeof("valueJson") - 1, 1); zend_declare_typed_property(class_entry, property_valueJson_name, &property_valueJson_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING|MAY_BE_NULL)); - zend_string_release_ex(property_valueJson_name, true); + zend_string_release(property_valueJson_name); zval property_variant_default_value; ZVAL_NULL(&property_variant_default_value); - zend_string *property_variant_name = zend_string_init("variant", sizeof("variant") - 1, true); + zend_string *property_variant_name = zend_string_init("variant", sizeof("variant") - 1, 1); zend_declare_typed_property(class_entry, property_variant_name, &property_variant_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING|MAY_BE_NULL)); - zend_string_release_ex(property_variant_name, true); + zend_string_release(property_variant_name); zval property_allocationKey_default_value; ZVAL_NULL(&property_allocationKey_default_value); - zend_string *property_allocationKey_name = zend_string_init("allocationKey", sizeof("allocationKey") - 1, true); + zend_string *property_allocationKey_name = zend_string_init("allocationKey", sizeof("allocationKey") - 1, 1); zend_declare_typed_property(class_entry, property_allocationKey_name, &property_allocationKey_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING|MAY_BE_NULL)); - zend_string_release_ex(property_allocationKey_name, true); + zend_string_release(property_allocationKey_name); zval property_reason_default_value; ZVAL_LONG(&property_reason_default_value, 0); - zend_string *property_reason_name = zend_string_init("reason", sizeof("reason") - 1, true); + zend_string *property_reason_name = zend_string_init("reason", sizeof("reason") - 1, 1); zend_declare_typed_property(class_entry, property_reason_name, &property_reason_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); - zend_string_release_ex(property_reason_name, true); + zend_string_release(property_reason_name); zval property_errorCode_default_value; ZVAL_LONG(&property_errorCode_default_value, 0); - zend_string *property_errorCode_name = zend_string_init("errorCode", sizeof("errorCode") - 1, true); + zend_string *property_errorCode_name = zend_string_init("errorCode", sizeof("errorCode") - 1, 1); zend_declare_typed_property(class_entry, property_errorCode_name, &property_errorCode_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); - zend_string_release_ex(property_errorCode_name, true); + zend_string_release(property_errorCode_name); zval property_doLog_default_value; ZVAL_FALSE(&property_doLog_default_value); - zend_string *property_doLog_name = zend_string_init("doLog", sizeof("doLog") - 1, true); + zend_string *property_doLog_name = zend_string_init("doLog", sizeof("doLog") - 1, 1); zend_declare_typed_property(class_entry, property_doLog_name, &property_doLog_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_BOOL)); - zend_string_release_ex(property_doLog_name, true); + zend_string_release(property_doLog_name); zval property_serialId_default_value; ZVAL_NULL(&property_serialId_default_value); @@ -681,54 +625,55 @@ static zend_class_entry *register_class_DDTrace_FfeResult(void) zval property_providerState_default_value; ZVAL_EMPTY_ARRAY(&property_providerState_default_value); - zend_string *property_providerState_name = zend_string_init("providerState", sizeof("providerState") - 1, true); + zend_string *property_providerState_name = zend_string_init("providerState", sizeof("providerState") - 1, 1); zend_declare_typed_property(class_entry, property_providerState_name, &property_providerState_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_ARRAY)); - zend_string_release_ex(property_providerState_name, true); + zend_string_release(property_providerState_name); zval property_errorMessage_default_value; ZVAL_NULL(&property_errorMessage_default_value); - zend_string *property_errorMessage_name = zend_string_init("errorMessage", sizeof("errorMessage") - 1, true); + zend_string *property_errorMessage_name = zend_string_init("errorMessage", sizeof("errorMessage") - 1, 1); zend_declare_typed_property(class_entry, property_errorMessage_name, &property_errorMessage_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING|MAY_BE_NULL)); - zend_string_release_ex(property_errorMessage_name, true); + zend_string_release(property_errorMessage_name); zval property_hasConfig_default_value; ZVAL_NULL(&property_hasConfig_default_value); - zend_string *property_hasConfig_name = zend_string_init("hasConfig", sizeof("hasConfig") - 1, true); + zend_string *property_hasConfig_name = zend_string_init("hasConfig", sizeof("hasConfig") - 1, 1); zend_declare_typed_property(class_entry, property_hasConfig_name, &property_hasConfig_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_BOOL|MAY_BE_NULL)); - zend_string_release_ex(property_hasConfig_name, true); + zend_string_release(property_hasConfig_name); zval property_configVersion_default_value; ZVAL_NULL(&property_configVersion_default_value); - zend_string *property_configVersion_name = zend_string_init("configVersion", sizeof("configVersion") - 1, true); + zend_string *property_configVersion_name = zend_string_init("configVersion", sizeof("configVersion") - 1, 1); zend_declare_typed_property(class_entry, property_configVersion_name, &property_configVersion_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG|MAY_BE_NULL)); - zend_string_release_ex(property_configVersion_name, true); + zend_string_release(property_configVersion_name); return class_entry; } -static zend_class_entry *register_class_DDTrace_SpanEvent(zend_class_entry *class_entry_JsonSerializable) +static zend_class_entry *register_class_DDTrace_SpanEvent(void) { zend_class_entry ce, *class_entry; INIT_NS_CLASS_ENTRY(ce, "DDTrace", "SpanEvent", class_DDTrace_SpanEvent_methods); class_entry = zend_register_internal_class_with_flags(&ce, NULL, 0); - zend_class_implements(class_entry, 1, class_entry_JsonSerializable); zval property_name_default_value; ZVAL_UNDEF(&property_name_default_value); - zend_declare_typed_property(class_entry, ZSTR_KNOWN(ZEND_STR_NAME), &property_name_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING)); + zend_string *property_name_name = zend_string_init("name", sizeof("name") - 1, 1); + zend_declare_typed_property(class_entry, property_name_name, &property_name_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING)); + zend_string_release(property_name_name); zval property_attributes_default_value; ZVAL_UNDEF(&property_attributes_default_value); - zend_string *property_attributes_name = zend_string_init("attributes", sizeof("attributes") - 1, true); + zend_string *property_attributes_name = zend_string_init("attributes", sizeof("attributes") - 1, 1); zend_declare_typed_property(class_entry, property_attributes_name, &property_attributes_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_ARRAY)); - zend_string_release_ex(property_attributes_name, true); + zend_string_release(property_attributes_name); zval property_timestamp_default_value; ZVAL_UNDEF(&property_timestamp_default_value); - zend_string *property_timestamp_name = zend_string_init("timestamp", sizeof("timestamp") - 1, true); + zend_string *property_timestamp_name = zend_string_init("timestamp", sizeof("timestamp") - 1, 1); zend_declare_typed_property(class_entry, property_timestamp_name, &property_timestamp_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); - zend_string_release_ex(property_timestamp_name, true); + zend_string_release(property_timestamp_name); return class_entry; } @@ -742,51 +687,50 @@ static zend_class_entry *register_class_DDTrace_ExceptionSpanEvent(zend_class_en zval property_exception_default_value; ZVAL_UNDEF(&property_exception_default_value); - zend_string *property_exception_name = zend_string_init("exception", sizeof("exception") - 1, true); + zend_string *property_exception_name = zend_string_init("exception", sizeof("exception") - 1, 1); zend_string *property_exception_class_Throwable = zend_string_init("Throwable", sizeof("Throwable")-1, 1); zend_declare_typed_property(class_entry, property_exception_name, &property_exception_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_CLASS(property_exception_class_Throwable, 0, 0)); - zend_string_release_ex(property_exception_name, true); + zend_string_release(property_exception_name); return class_entry; } -static zend_class_entry *register_class_DDTrace_SpanLink(zend_class_entry *class_entry_JsonSerializable) +static zend_class_entry *register_class_DDTrace_SpanLink(void) { zend_class_entry ce, *class_entry; INIT_NS_CLASS_ENTRY(ce, "DDTrace", "SpanLink", class_DDTrace_SpanLink_methods); class_entry = zend_register_internal_class_with_flags(&ce, NULL, 0); - zend_class_implements(class_entry, 1, class_entry_JsonSerializable); zval property_traceId_default_value; ZVAL_UNDEF(&property_traceId_default_value); - zend_string *property_traceId_name = zend_string_init("traceId", sizeof("traceId") - 1, true); + zend_string *property_traceId_name = zend_string_init("traceId", sizeof("traceId") - 1, 1); zend_declare_typed_property(class_entry, property_traceId_name, &property_traceId_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING)); - zend_string_release_ex(property_traceId_name, true); + zend_string_release(property_traceId_name); zval property_spanId_default_value; ZVAL_UNDEF(&property_spanId_default_value); - zend_string *property_spanId_name = zend_string_init("spanId", sizeof("spanId") - 1, true); + zend_string *property_spanId_name = zend_string_init("spanId", sizeof("spanId") - 1, 1); zend_declare_typed_property(class_entry, property_spanId_name, &property_spanId_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING)); - zend_string_release_ex(property_spanId_name, true); + zend_string_release(property_spanId_name); zval property_traceState_default_value; ZVAL_UNDEF(&property_traceState_default_value); - zend_string *property_traceState_name = zend_string_init("traceState", sizeof("traceState") - 1, true); + zend_string *property_traceState_name = zend_string_init("traceState", sizeof("traceState") - 1, 1); zend_declare_typed_property(class_entry, property_traceState_name, &property_traceState_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING)); - zend_string_release_ex(property_traceState_name, true); + zend_string_release(property_traceState_name); zval property_attributes_default_value; ZVAL_UNDEF(&property_attributes_default_value); - zend_string *property_attributes_name = zend_string_init("attributes", sizeof("attributes") - 1, true); + zend_string *property_attributes_name = zend_string_init("attributes", sizeof("attributes") - 1, 1); zend_declare_typed_property(class_entry, property_attributes_name, &property_attributes_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_ARRAY)); - zend_string_release_ex(property_attributes_name, true); + zend_string_release(property_attributes_name); zval property_droppedAttributesCount_default_value; ZVAL_UNDEF(&property_droppedAttributesCount_default_value); - zend_string *property_droppedAttributesCount_name = zend_string_init("droppedAttributesCount", sizeof("droppedAttributesCount") - 1, true); + zend_string *property_droppedAttributesCount_name = zend_string_init("droppedAttributesCount", sizeof("droppedAttributesCount") - 1, 1); zend_declare_typed_property(class_entry, property_droppedAttributesCount_name, &property_droppedAttributesCount_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); - zend_string_release_ex(property_droppedAttributesCount_name, true); + zend_string_release(property_droppedAttributesCount_name); return class_entry; } @@ -800,15 +744,61 @@ static zend_class_entry *register_class_DDTrace_GitMetadata(void) zval property_commitSha_default_value; ZVAL_EMPTY_STRING(&property_commitSha_default_value); - zend_string *property_commitSha_name = zend_string_init("commitSha", sizeof("commitSha") - 1, true); + zend_string *property_commitSha_name = zend_string_init("commitSha", sizeof("commitSha") - 1, 1); zend_declare_typed_property(class_entry, property_commitSha_name, &property_commitSha_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING)); - zend_string_release_ex(property_commitSha_name, true); + zend_string_release(property_commitSha_name); zval property_repositoryUrl_default_value; ZVAL_EMPTY_STRING(&property_repositoryUrl_default_value); - zend_string *property_repositoryUrl_name = zend_string_init("repositoryUrl", sizeof("repositoryUrl") - 1, true); + zend_string *property_repositoryUrl_name = zend_string_init("repositoryUrl", sizeof("repositoryUrl") - 1, 1); zend_declare_typed_property(class_entry, property_repositoryUrl_name, &property_repositoryUrl_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING)); - zend_string_release_ex(property_repositoryUrl_name, true); + zend_string_release(property_repositoryUrl_name); + + return class_entry; +} + +static zend_class_entry *register_class_DDTrace_SpanKind(void) +{ + zend_class_entry ce, *class_entry; + + INIT_NS_CLASS_ENTRY(ce, "DDTrace", "SpanKind", NULL); + class_entry = zend_register_internal_class_with_flags(&ce, NULL, 0); + + zval const_UNSPECIFIED_value; + ZVAL_LONG(&const_UNSPECIFIED_value, 0); + zend_string *const_UNSPECIFIED_name = zend_string_init_interned("UNSPECIFIED", sizeof("UNSPECIFIED") - 1, 1); + zend_declare_class_constant_ex(class_entry, const_UNSPECIFIED_name, &const_UNSPECIFIED_value, ZEND_ACC_PUBLIC, NULL); + zend_string_release(const_UNSPECIFIED_name); + + zval const_INTERNAL_value; + ZVAL_LONG(&const_INTERNAL_value, 1); + zend_string *const_INTERNAL_name = zend_string_init_interned("INTERNAL", sizeof("INTERNAL") - 1, 1); + zend_declare_class_constant_ex(class_entry, const_INTERNAL_name, &const_INTERNAL_value, ZEND_ACC_PUBLIC, NULL); + zend_string_release(const_INTERNAL_name); + + zval const_SERVER_value; + ZVAL_LONG(&const_SERVER_value, 2); + zend_string *const_SERVER_name = zend_string_init_interned("SERVER", sizeof("SERVER") - 1, 1); + zend_declare_class_constant_ex(class_entry, const_SERVER_name, &const_SERVER_value, ZEND_ACC_PUBLIC, NULL); + zend_string_release(const_SERVER_name); + + zval const_CLIENT_value; + ZVAL_LONG(&const_CLIENT_value, 3); + zend_string *const_CLIENT_name = zend_string_init_interned("CLIENT", sizeof("CLIENT") - 1, 1); + zend_declare_class_constant_ex(class_entry, const_CLIENT_name, &const_CLIENT_value, ZEND_ACC_PUBLIC, NULL); + zend_string_release(const_CLIENT_name); + + zval const_PRODUCER_value; + ZVAL_LONG(&const_PRODUCER_value, 4); + zend_string *const_PRODUCER_name = zend_string_init_interned("PRODUCER", sizeof("PRODUCER") - 1, 1); + zend_declare_class_constant_ex(class_entry, const_PRODUCER_name, &const_PRODUCER_value, ZEND_ACC_PUBLIC, NULL); + zend_string_release(const_PRODUCER_name); + + zval const_CONSUMER_value; + ZVAL_LONG(&const_CONSUMER_value, 5); + zend_string *const_CONSUMER_name = zend_string_init_interned("CONSUMER", sizeof("CONSUMER") - 1, 1); + zend_declare_class_constant_ex(class_entry, const_CONSUMER_name, &const_CONSUMER_value, ZEND_ACC_PUBLIC, NULL); + zend_string_release(const_CONSUMER_name); return class_entry; } @@ -822,106 +812,138 @@ static zend_class_entry *register_class_DDTrace_SpanData(void) zval property_name_default_value; ZVAL_EMPTY_STRING(&property_name_default_value); - zend_declare_typed_property(class_entry, ZSTR_KNOWN(ZEND_STR_NAME), &property_name_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING|MAY_BE_NULL)); + zend_string *property_name_name = zend_string_init("name", sizeof("name") - 1, 1); + zend_declare_typed_property(class_entry, property_name_name, &property_name_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING|MAY_BE_NULL)); + zend_string_release(property_name_name); zval property_resource_default_value; ZVAL_EMPTY_STRING(&property_resource_default_value); - zend_declare_typed_property(class_entry, ZSTR_KNOWN(ZEND_STR_RESOURCE), &property_resource_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING|MAY_BE_NULL)); + zend_string *property_resource_name = zend_string_init("resource", sizeof("resource") - 1, 1); + zend_declare_typed_property(class_entry, property_resource_name, &property_resource_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING|MAY_BE_NULL)); + zend_string_release(property_resource_name); zval property_service_default_value; ZVAL_EMPTY_STRING(&property_service_default_value); - zend_string *property_service_name = zend_string_init("service", sizeof("service") - 1, true); + zend_string *property_service_name = zend_string_init("service", sizeof("service") - 1, 1); zend_declare_typed_property(class_entry, property_service_name, &property_service_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING|MAY_BE_NULL)); - zend_string_release_ex(property_service_name, true); - - zval property_env_default_value; - ZVAL_EMPTY_STRING(&property_env_default_value); - zend_string *property_env_name = zend_string_init("env", sizeof("env") - 1, true); - zend_declare_typed_property(class_entry, property_env_name, &property_env_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING)); - zend_string_release_ex(property_env_name, true); - - zval property_version_default_value; - ZVAL_EMPTY_STRING(&property_version_default_value); - zend_string *property_version_name = zend_string_init("version", sizeof("version") - 1, true); - zend_declare_typed_property(class_entry, property_version_name, &property_version_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING)); - zend_string_release_ex(property_version_name, true); + zend_string_release(property_service_name); zval property_meta_struct_default_value; ZVAL_EMPTY_ARRAY(&property_meta_struct_default_value); - zend_string *property_meta_struct_name = zend_string_init("meta_struct", sizeof("meta_struct") - 1, true); + zend_string *property_meta_struct_name = zend_string_init("meta_struct", sizeof("meta_struct") - 1, 1); zend_declare_typed_property(class_entry, property_meta_struct_name, &property_meta_struct_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_ARRAY)); - zend_string_release_ex(property_meta_struct_name, true); + zend_string_release(property_meta_struct_name); zval property_type_default_value; ZVAL_EMPTY_STRING(&property_type_default_value); - zend_declare_typed_property(class_entry, ZSTR_KNOWN(ZEND_STR_TYPE), &property_type_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING|MAY_BE_NULL)); + zend_string *property_type_name = zend_string_init("type", sizeof("type") - 1, 1); + zend_declare_typed_property(class_entry, property_type_name, &property_type_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING|MAY_BE_NULL)); + zend_string_release(property_type_name); zval property_meta_default_value; ZVAL_EMPTY_ARRAY(&property_meta_default_value); - zend_string *property_meta_name = zend_string_init("meta", sizeof("meta") - 1, true); - zend_declare_typed_property(class_entry, property_meta_name, &property_meta_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_ARRAY)); - zend_string_release_ex(property_meta_name, true); + zend_string *property_meta_name = zend_string_init("meta", sizeof("meta") - 1, 1); + zend_declare_typed_property(class_entry, property_meta_name, &property_meta_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_NONE(0)); + zend_string_release(property_meta_name); zval property_metrics_default_value; ZVAL_EMPTY_ARRAY(&property_metrics_default_value); - zend_string *property_metrics_name = zend_string_init("metrics", sizeof("metrics") - 1, true); - zend_declare_typed_property(class_entry, property_metrics_name, &property_metrics_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_ARRAY)); - zend_string_release_ex(property_metrics_name, true); + zend_string *property_metrics_name = zend_string_init("metrics", sizeof("metrics") - 1, 1); + zend_declare_typed_property(class_entry, property_metrics_name, &property_metrics_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_NONE(0)); + zend_string_release(property_metrics_name); zval property_exception_default_value; ZVAL_NULL(&property_exception_default_value); - zend_string *property_exception_name = zend_string_init("exception", sizeof("exception") - 1, true); + zend_string *property_exception_name = zend_string_init("exception", sizeof("exception") - 1, 1); zend_string *property_exception_class_Throwable = zend_string_init("Throwable", sizeof("Throwable")-1, 1); zend_declare_typed_property(class_entry, property_exception_name, &property_exception_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_CLASS(property_exception_class_Throwable, 0, MAY_BE_NULL)); - zend_string_release_ex(property_exception_name, true); + zend_string_release(property_exception_name); zval property_id_default_value; ZVAL_UNDEF(&property_id_default_value); - zend_string *property_id_name = zend_string_init("id", sizeof("id") - 1, true); + zend_string *property_id_name = zend_string_init("id", sizeof("id") - 1, 1); zend_declare_typed_property(class_entry, property_id_name, &property_id_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING)); - zend_string_release_ex(property_id_name, true); + zend_string_release(property_id_name); zval property_links_default_value; ZVAL_EMPTY_ARRAY(&property_links_default_value); - zend_string *property_links_name = zend_string_init("links", sizeof("links") - 1, true); + zend_string *property_links_name = zend_string_init("links", sizeof("links") - 1, 1); zend_declare_typed_property(class_entry, property_links_name, &property_links_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_ARRAY)); - zend_string_release_ex(property_links_name, true); + zend_string_release(property_links_name); zval property_events_default_value; ZVAL_EMPTY_ARRAY(&property_events_default_value); - zend_string *property_events_name = zend_string_init("events", sizeof("events") - 1, true); + zend_string *property_events_name = zend_string_init("events", sizeof("events") - 1, 1); zend_declare_typed_property(class_entry, property_events_name, &property_events_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_ARRAY)); - zend_string_release_ex(property_events_name, true); + zend_string_release(property_events_name); zval property_peerServiceSources_default_value; ZVAL_EMPTY_ARRAY(&property_peerServiceSources_default_value); - zend_string *property_peerServiceSources_name = zend_string_init("peerServiceSources", sizeof("peerServiceSources") - 1, true); + zend_string *property_peerServiceSources_name = zend_string_init("peerServiceSources", sizeof("peerServiceSources") - 1, 1); zend_declare_typed_property(class_entry, property_peerServiceSources_name, &property_peerServiceSources_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_ARRAY)); - zend_string_release_ex(property_peerServiceSources_name, true); + zend_string_release(property_peerServiceSources_name); zval property_parent_default_value; ZVAL_UNDEF(&property_parent_default_value); + zend_string *property_parent_name = zend_string_init("parent", sizeof("parent") - 1, 1); zend_string *property_parent_class_DDTrace_SpanData = zend_string_init("DDTrace\\SpanData", sizeof("DDTrace\\SpanData")-1, 1); - zend_declare_typed_property(class_entry, ZSTR_KNOWN(ZEND_STR_PARENT), &property_parent_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_CLASS(property_parent_class_DDTrace_SpanData, 0, MAY_BE_NULL)); + zend_declare_typed_property(class_entry, property_parent_name, &property_parent_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_CLASS(property_parent_class_DDTrace_SpanData, 0, MAY_BE_NULL)); + zend_string_release(property_parent_name); zval property_stack_default_value; ZVAL_UNDEF(&property_stack_default_value); - zend_string *property_stack_name = zend_string_init("stack", sizeof("stack") - 1, true); + zend_string *property_stack_name = zend_string_init("stack", sizeof("stack") - 1, 1); zend_string *property_stack_class_DDTrace_SpanStack = zend_string_init("DDTrace\\SpanStack", sizeof("DDTrace\\SpanStack")-1, 1); zend_declare_typed_property(class_entry, property_stack_name, &property_stack_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_CLASS(property_stack_class_DDTrace_SpanStack, 0, 0)); - zend_string_release_ex(property_stack_name, true); + zend_string_release(property_stack_name); zval property_onClose_default_value; ZVAL_EMPTY_ARRAY(&property_onClose_default_value); - zend_string *property_onClose_name = zend_string_init("onClose", sizeof("onClose") - 1, true); + zend_string *property_onClose_name = zend_string_init("onClose", sizeof("onClose") - 1, 1); zend_declare_typed_property(class_entry, property_onClose_name, &property_onClose_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_ARRAY)); - zend_string_release_ex(property_onClose_name, true); + zend_string_release(property_onClose_name); zval property_baggage_default_value; ZVAL_EMPTY_ARRAY(&property_baggage_default_value); - zend_string *property_baggage_name = zend_string_init("baggage", sizeof("baggage") - 1, true); + zend_string *property_baggage_name = zend_string_init("baggage", sizeof("baggage") - 1, 1); zend_declare_typed_property(class_entry, property_baggage_name, &property_baggage_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_ARRAY)); - zend_string_release_ex(property_baggage_name, true); + zend_string_release(property_baggage_name); + + zval property_env_default_value; + ZVAL_EMPTY_STRING(&property_env_default_value); + zend_string *property_env_name = zend_string_init("env", sizeof("env") - 1, 1); + zend_declare_typed_property(class_entry, property_env_name, &property_env_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING)); + zend_string_release(property_env_name); + + zval property_version_default_value; + ZVAL_EMPTY_STRING(&property_version_default_value); + zend_string *property_version_name = zend_string_init("version", sizeof("version") - 1, 1); + zend_declare_typed_property(class_entry, property_version_name, &property_version_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING)); + zend_string_release(property_version_name); + + zval property_component_default_value; + ZVAL_EMPTY_STRING(&property_component_default_value); + zend_string *property_component_name = zend_string_init("component", sizeof("component") - 1, 1); + zend_declare_typed_property(class_entry, property_component_name, &property_component_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING)); + zend_string_release(property_component_name); + + zval property_spanKind_default_value; + ZVAL_LONG(&property_spanKind_default_value, 0); + zend_string *property_spanKind_name = zend_string_init("spanKind", sizeof("spanKind") - 1, 1); + zend_declare_typed_property(class_entry, property_spanKind_name, &property_spanKind_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_string_release(property_spanKind_name); + + zval property_attributes_default_value; + ZVAL_EMPTY_ARRAY(&property_attributes_default_value); + zend_string *property_attributes_name = zend_string_init("attributes", sizeof("attributes") - 1, 1); + zend_declare_typed_property(class_entry, property_attributes_name, &property_attributes_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_ARRAY)); + zend_string_release(property_attributes_name); + + zval property_ignoreError_default_value; + ZVAL_FALSE(&property_ignoreError_default_value); + zend_string *property_ignoreError_name = zend_string_init("ignoreError", sizeof("ignoreError") - 1, 1); + zend_declare_typed_property(class_entry, property_ignoreError_name, &property_ignoreError_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_BOOL)); + zend_string_release(property_ignoreError_name); return class_entry; } @@ -945,65 +967,77 @@ static zend_class_entry *register_class_DDTrace_RootSpanData(zend_class_entry *c zval property_origin_default_value; ZVAL_UNDEF(&property_origin_default_value); - zend_string *property_origin_name = zend_string_init("origin", sizeof("origin") - 1, true); + zend_string *property_origin_name = zend_string_init("origin", sizeof("origin") - 1, 1); zend_declare_typed_property(class_entry, property_origin_name, &property_origin_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING)); - zend_string_release_ex(property_origin_name, true); + zend_string_release(property_origin_name); zval property_propagatedTags_default_value; ZVAL_EMPTY_ARRAY(&property_propagatedTags_default_value); - zend_string *property_propagatedTags_name = zend_string_init("propagatedTags", sizeof("propagatedTags") - 1, true); + zend_string *property_propagatedTags_name = zend_string_init("propagatedTags", sizeof("propagatedTags") - 1, 1); zend_declare_typed_property(class_entry, property_propagatedTags_name, &property_propagatedTags_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_ARRAY)); - zend_string_release_ex(property_propagatedTags_name, true); + zend_string_release(property_propagatedTags_name); zval property_samplingPriority_default_value; ZVAL_LONG(&property_samplingPriority_default_value, DDTRACE_PRIORITY_SAMPLING_UNKNOWN); - zend_string *property_samplingPriority_name = zend_string_init("samplingPriority", sizeof("samplingPriority") - 1, true); + zend_string *property_samplingPriority_name = zend_string_init("samplingPriority", sizeof("samplingPriority") - 1, 1); zend_declare_typed_property(class_entry, property_samplingPriority_name, &property_samplingPriority_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); - zend_string_release_ex(property_samplingPriority_name, true); + zend_string_release(property_samplingPriority_name); + + zval property_samplingMechanism_default_value; + ZVAL_LONG(&property_samplingMechanism_default_value, 0); + zend_string *property_samplingMechanism_name = zend_string_init("samplingMechanism", sizeof("samplingMechanism") - 1, 1); + zend_declare_typed_property(class_entry, property_samplingMechanism_name, &property_samplingMechanism_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_string_release(property_samplingMechanism_name); zval property_propagatedSamplingPriority_default_value; ZVAL_UNDEF(&property_propagatedSamplingPriority_default_value); - zend_string *property_propagatedSamplingPriority_name = zend_string_init("propagatedSamplingPriority", sizeof("propagatedSamplingPriority") - 1, true); + zend_string *property_propagatedSamplingPriority_name = zend_string_init("propagatedSamplingPriority", sizeof("propagatedSamplingPriority") - 1, 1); zend_declare_typed_property(class_entry, property_propagatedSamplingPriority_name, &property_propagatedSamplingPriority_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); - zend_string_release_ex(property_propagatedSamplingPriority_name, true); + zend_string_release(property_propagatedSamplingPriority_name); zval property_tracestate_default_value; ZVAL_UNDEF(&property_tracestate_default_value); - zend_string *property_tracestate_name = zend_string_init("tracestate", sizeof("tracestate") - 1, true); + zend_string *property_tracestate_name = zend_string_init("tracestate", sizeof("tracestate") - 1, 1); zend_declare_typed_property(class_entry, property_tracestate_name, &property_tracestate_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING)); - zend_string_release_ex(property_tracestate_name, true); + zend_string_release(property_tracestate_name); zval property_tracestateTags_default_value; ZVAL_EMPTY_ARRAY(&property_tracestateTags_default_value); - zend_string *property_tracestateTags_name = zend_string_init("tracestateTags", sizeof("tracestateTags") - 1, true); + zend_string *property_tracestateTags_name = zend_string_init("tracestateTags", sizeof("tracestateTags") - 1, 1); zend_declare_typed_property(class_entry, property_tracestateTags_name, &property_tracestateTags_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_ARRAY)); - zend_string_release_ex(property_tracestateTags_name, true); + zend_string_release(property_tracestateTags_name); zval property_parentId_default_value; ZVAL_UNDEF(&property_parentId_default_value); - zend_string *property_parentId_name = zend_string_init("parentId", sizeof("parentId") - 1, true); + zend_string *property_parentId_name = zend_string_init("parentId", sizeof("parentId") - 1, 1); zend_declare_typed_property(class_entry, property_parentId_name, &property_parentId_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING)); - zend_string_release_ex(property_parentId_name, true); + zend_string_release(property_parentId_name); zval property_traceId_default_value; ZVAL_EMPTY_STRING(&property_traceId_default_value); - zend_string *property_traceId_name = zend_string_init("traceId", sizeof("traceId") - 1, true); + zend_string *property_traceId_name = zend_string_init("traceId", sizeof("traceId") - 1, 1); zend_declare_typed_property(class_entry, property_traceId_name, &property_traceId_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING)); - zend_string_release_ex(property_traceId_name, true); + zend_string_release(property_traceId_name); zval property_gitMetadata_default_value; ZVAL_NULL(&property_gitMetadata_default_value); - zend_string *property_gitMetadata_name = zend_string_init("gitMetadata", sizeof("gitMetadata") - 1, true); + zend_string *property_gitMetadata_name = zend_string_init("gitMetadata", sizeof("gitMetadata") - 1, 1); zend_string *property_gitMetadata_class_DDTrace_GitMetadata = zend_string_init("DDTrace\\GitMetadata", sizeof("DDTrace\\GitMetadata")-1, 1); zend_declare_typed_property(class_entry, property_gitMetadata_name, &property_gitMetadata_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_CLASS(property_gitMetadata_class_DDTrace_GitMetadata, 0, MAY_BE_NULL)); - zend_string_release_ex(property_gitMetadata_name, true); + zend_string_release(property_gitMetadata_name); zval property_inferredSpan_default_value; ZVAL_NULL(&property_inferredSpan_default_value); - zend_string *property_inferredSpan_name = zend_string_init("inferredSpan", sizeof("inferredSpan") - 1, true); + zend_string *property_inferredSpan_name = zend_string_init("inferredSpan", sizeof("inferredSpan") - 1, 1); zend_string *property_inferredSpan_class_DDTrace_InferredSpanData = zend_string_init("DDTrace\\InferredSpanData", sizeof("DDTrace\\InferredSpanData")-1, 1); zend_declare_typed_property(class_entry, property_inferredSpan_name, &property_inferredSpan_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_CLASS(property_inferredSpan_class_DDTrace_InferredSpanData, 0, MAY_BE_NULL)); - zend_string_release_ex(property_inferredSpan_name, true); + zend_string_release(property_inferredSpan_name); + + zval property_hostname_default_value; + ZVAL_EMPTY_STRING(&property_hostname_default_value); + zend_string *property_hostname_name = zend_string_init("hostname", sizeof("hostname") - 1, 1); + zend_declare_typed_property(class_entry, property_hostname_name, &property_hostname_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING)); + zend_string_release(property_hostname_name); return class_entry; } @@ -1017,21 +1051,29 @@ static zend_class_entry *register_class_DDTrace_SpanStack(void) zval property_parent_default_value; ZVAL_UNDEF(&property_parent_default_value); + zend_string *property_parent_name = zend_string_init("parent", sizeof("parent") - 1, 1); zend_string *property_parent_class_DDTrace_SpanStack = zend_string_init("DDTrace\\SpanStack", sizeof("DDTrace\\SpanStack")-1, 1); - zend_declare_typed_property(class_entry, ZSTR_KNOWN(ZEND_STR_PARENT), &property_parent_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_CLASS(property_parent_class_DDTrace_SpanStack, 0, MAY_BE_NULL)); + zend_declare_typed_property(class_entry, property_parent_name, &property_parent_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_CLASS(property_parent_class_DDTrace_SpanStack, 0, MAY_BE_NULL)); + zend_string_release(property_parent_name); zval property_active_default_value; ZVAL_NULL(&property_active_default_value); - zend_string *property_active_name = zend_string_init("active", sizeof("active") - 1, true); + zend_string *property_active_name = zend_string_init("active", sizeof("active") - 1, 1); zend_string *property_active_class_DDTrace_SpanData = zend_string_init("DDTrace\\SpanData", sizeof("DDTrace\\SpanData")-1, 1); zend_declare_typed_property(class_entry, property_active_name, &property_active_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_CLASS(property_active_class_DDTrace_SpanData, 0, MAY_BE_NULL)); - zend_string_release_ex(property_active_name, true); + zend_string_release(property_active_name); zval property_spanCreationObservers_default_value; ZVAL_EMPTY_ARRAY(&property_spanCreationObservers_default_value); - zend_string *property_spanCreationObservers_name = zend_string_init("spanCreationObservers", sizeof("spanCreationObservers") - 1, true); + zend_string *property_spanCreationObservers_name = zend_string_init("spanCreationObservers", sizeof("spanCreationObservers") - 1, 1); zend_declare_typed_property(class_entry, property_spanCreationObservers_name, &property_spanCreationObservers_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_ARRAY)); - zend_string_release_ex(property_spanCreationObservers_name, true); + zend_string_release(property_spanCreationObservers_name); + + zval property_attributes_default_value; + ZVAL_EMPTY_ARRAY(&property_attributes_default_value); + zend_string *property_attributes_name = zend_string_init("attributes", sizeof("attributes") - 1, 1); + zend_declare_typed_property(class_entry, property_attributes_name, &property_attributes_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_ARRAY)); + zend_string_release(property_attributes_name); return class_entry; } @@ -1045,21 +1087,21 @@ static zend_class_entry *register_class_DDTrace_Integration(void) zval const_NOT_LOADED_value; ZVAL_LONG(&const_NOT_LOADED_value, DD_TRACE_INTEGRATION_NOT_LOADED); - zend_string *const_NOT_LOADED_name = zend_string_init_interned("NOT_LOADED", sizeof("NOT_LOADED") - 1, true); + zend_string *const_NOT_LOADED_name = zend_string_init_interned("NOT_LOADED", sizeof("NOT_LOADED") - 1, 1); zend_declare_class_constant_ex(class_entry, const_NOT_LOADED_name, &const_NOT_LOADED_value, ZEND_ACC_PUBLIC, NULL); - zend_string_release_ex(const_NOT_LOADED_name, true); + zend_string_release(const_NOT_LOADED_name); zval const_LOADED_value; ZVAL_LONG(&const_LOADED_value, DD_TRACE_INTEGRATION_LOADED); - zend_string *const_LOADED_name = zend_string_init_interned("LOADED", sizeof("LOADED") - 1, true); + zend_string *const_LOADED_name = zend_string_init_interned("LOADED", sizeof("LOADED") - 1, 1); zend_declare_class_constant_ex(class_entry, const_LOADED_name, &const_LOADED_value, ZEND_ACC_PUBLIC, NULL); - zend_string_release_ex(const_LOADED_name, true); + zend_string_release(const_LOADED_name); zval const_NOT_AVAILABLE_value; ZVAL_LONG(&const_NOT_AVAILABLE_value, DD_TRACE_INTEGRATION_NOT_AVAILABLE); - zend_string *const_NOT_AVAILABLE_name = zend_string_init_interned("NOT_AVAILABLE", sizeof("NOT_AVAILABLE") - 1, true); + zend_string *const_NOT_AVAILABLE_name = zend_string_init_interned("NOT_AVAILABLE", sizeof("NOT_AVAILABLE") - 1, 1); zend_declare_class_constant_ex(class_entry, const_NOT_AVAILABLE_name, &const_NOT_AVAILABLE_value, ZEND_ACC_PUBLIC, NULL); - zend_string_release_ex(const_NOT_AVAILABLE_name, true); + zend_string_release(const_NOT_AVAILABLE_name); return class_entry; } diff --git a/tracer/distributed_tracing_headers.c b/tracer/distributed_tracing_headers.c index f6eef1b68f..40940d53ad 100644 --- a/tracer/distributed_tracing_headers.c +++ b/tracer/distributed_tracing_headers.c @@ -731,12 +731,9 @@ void ddtrace_apply_distributed_tracing_result(ddtrace_distributed_tracing_result break; } - zend_array *root_meta = span ? ddtrace_property_array(&span->property_meta) : &DDTRACE_G(root_span_tags_preset); + zend_array *root_meta = span ? ddtrace_property_array(&span->property_attributes) : &DDTRACE_G(root_span_tags_preset); if (span) { - zend_string *tagname; - ZEND_HASH_FOREACH_STR_KEY(ddtrace_property_array(&span->property_propagated_tags), tagname) { - zend_hash_del(root_meta, tagname); - } ZEND_HASH_FOREACH_END(); + ddtrace_drop_propagated_tags(root_meta, ddtrace_property_array(&span->property_propagated_tags)); ZVAL_ARR(&zv, emalloc(sizeof(HashTable))); *Z_ARR(zv) = result->propagated_tags; @@ -745,7 +742,7 @@ void ddtrace_apply_distributed_tracing_result(ddtrace_distributed_tracing_result zend_hash_copy(root_meta, &result->meta_tags, NULL); ddtrace_span_data *inferred_span = ddtrace_get_inferred_span(span); if (inferred_span) { - zend_array *inferred_meta = ddtrace_property_array(&inferred_span->property_meta); + zend_array *inferred_meta = ddtrace_property_array(&inferred_span->property_attributes); zend_hash_copy(inferred_meta, &result->meta_tags, (copy_ctor_func_t)zval_add_ref); } diff --git a/tracer/endpoint_guessing.c b/tracer/endpoint_guessing.c index a4db744bb3..d1ccee3710 100644 --- a/tracer/endpoint_guessing.c +++ b/tracer/endpoint_guessing.c @@ -197,10 +197,10 @@ void ddtrace_maybe_add_guessed_endpoint_tag(ddtrace_root_span_data *span) return; } - zend_array* meta = ddtrace_property_array(&span->property_meta); + zend_array* attributes = ddtrace_property_array(&span->property_attributes); if (!get_DD_TRACE_RESOURCE_RENAMING_ALWAYS_SIMPLIFIED_ENDPOINT()) { - zval* route = zend_hash_str_find(meta, ZEND_STRL("http.route")); + zval* route = ddtrace_span_find_tag(&span->span, ZEND_STRL("http.route")); // unless we have always_simplified_endpoiont set, // we skip the calculation if http.route is set if (route && Z_TYPE_P(route) == IS_STRING) { @@ -209,8 +209,11 @@ void ddtrace_maybe_add_guessed_endpoint_tag(ddtrace_root_span_data *span) } zval* endpoint; - if ((endpoint = zend_hash_str_add(meta, ZEND_STRL("http.endpoint"), &(zval){0}))) { - zval* url = zend_hash_str_find_deref(meta, ZEND_STRL("http.url")); + if ((endpoint = zend_hash_str_add(attributes, ZEND_STRL("http.endpoint"), &(zval){0}))) { + zval* url = ddtrace_span_find_tag(&span->span, ZEND_STRL("http.url")); + if (url) { + ZVAL_DEREF(url); + } if (!url || Z_TYPE_P(url) != IS_STRING) { // "In case the url is not available, a default value of / should be used for the endpoint tag." ZVAL_STRING(endpoint, "/"); diff --git a/tracer/exception_serialize.c b/tracer/exception_serialize.c index 738dd4e917..2bb2e246d2 100644 --- a/tracer/exception_serialize.c +++ b/tracer/exception_serialize.c @@ -16,7 +16,7 @@ ZEND_EXTERN_MODULE_GLOBALS(datadog); -static void dd_exception_to_error_msg(zend_object *exception, ddog_SpanBytes *span, enum dd_exception exception_state) { +static void dd_exception_to_error_msg(zend_object *exception, ddog_SpanNode *span, enum dd_exception exception_state) { zend_string *msg = zai_exception_message(exception); zend_long line = zval_get_long(zai_exception_read_property(exception, ZSTR_KNOWN(ZEND_STR_LINE))); zend_string *file = datadog_convert_to_str(zai_exception_read_property(exception, ZSTR_KNOWN(ZEND_STR_FILE))); @@ -42,14 +42,14 @@ static void dd_exception_to_error_msg(zend_object *exception, ddog_SpanBytes *sp ZSTR_VAL(exception->ce->name), status_line ? status_line : "", ZSTR_LEN(msg) > 0 ? ": " : "", ZSTR_VAL(msg), ZSTR_VAL(file), line); - ddog_add_str_span_meta_CharSlice(span, "error.message", (ddog_CharSlice){.ptr = error_text, .len = len}); + ddog_attributes_add_lit(ddog_span_get_attributes(span), "error.message", (ddog_CharSlice){.ptr = error_text, .len = len}); zend_string_release(file); free(error_text); free(status_line); } -static void dd_exception_to_error_type(zend_object *exception, ddog_SpanBytes *span) { +static void dd_exception_to_error_type(zend_object *exception, ddog_SpanNode *span) { if (instanceof_function(exception->ce, ddtrace_ce_fatal_error)) { zval *code = zai_exception_read_property(exception, ZSTR_KNOWN(ZEND_STR_CODE)); const char *error_type_string = "{unknown error}"; @@ -76,14 +76,14 @@ static void dd_exception_to_error_type(zend_object *exception, ddog_SpanBytes *s LOG_UNREACHABLE("Exception was a DDTrace\\FatalError but failed to get an exception code"); } - ddog_add_str_span_meta_str(span, "error.type", error_type_string); + dd_span_attr_str(span, "error.type", error_type_string); } else { - ddog_add_str_span_meta_zstr(span, "error.type", exception->ce->name); + dd_span_attr_zstr(span, "error.type", exception->ce->name); } } -static void dd_exception_trace_to_error_stack(zend_string *trace, ddog_SpanBytes *span) { - ddog_add_str_span_meta_zstr(span, "error.stack", trace); +static void dd_exception_trace_to_error_stack(zend_string *trace, ddog_SpanNode *span) { + dd_span_attr_zstr(span, "error.stack", trace); zend_string_release(trace); } @@ -309,13 +309,13 @@ void ddtrace_create_capture_value(zval *zv, struct ddog_CaptureValue *value, con #define uuid_len 36 #define hash_len 16 -static ddog_DebuggerCapture *dd_create_frame_and_collect_locals(char *exception_id, char *exception_hash, int frame_num, ddog_CharSlice class_slice, ddog_CharSlice func_slice, zval *locals, zend_string *service_name, const ddog_CaptureConfiguration *capture_config, uint64_t time, ddog_SpanBytes *span) { +static ddog_DebuggerCapture *dd_create_frame_and_collect_locals(char *exception_id, char *exception_hash, int frame_num, ddog_CharSlice class_slice, ddog_CharSlice func_slice, zval *locals, zend_string *service_name, const ddog_CaptureConfiguration *capture_config, uint64_t time, ddog_SpanNode *span) { char *snapshot_id = zend_arena_alloc(&DDTRACE_G(debugger_capture_arena).arena, uuid_len); ddog_snapshot_format_new_uuid((uint8_t(*)[uuid_len])snapshot_id); char *msg = zend_arena_alloc(&DDTRACE_G(debugger_capture_arena).arena, 40); int len = sprintf(msg, "_dd.debug.error.%d.snapshot_id", frame_num); - ddog_add_span_meta(span, (ddog_CharSlice){.ptr = msg, .len = len}, (ddog_CharSlice){.ptr = snapshot_id, .len = uuid_len}); + ddog_attributes_add_str(ddog_span_get_attributes(span), (ddog_CharSlice){.ptr = msg, .len = len}, (ddog_CharSlice){.ptr = snapshot_id, .len = uuid_len}); ddog_DebuggerCapture *capture = ddog_create_exception_snapshot(&DDTRACE_G(exception_debugger_buffer), (ddog_CharSlice){ .ptr = ZSTR_VAL(service_name), .len = ZSTR_LEN(service_name) }, @@ -388,7 +388,7 @@ static bool ddtrace_exception_debugging_is_active(void) { return DATADOG_G(sidecar) && datadog_sidecar_instance_id && get_DD_EXCEPTION_REPLAY_ENABLED(); } -static void ddtrace_collect_exception_debug_data(zend_object *exception, zend_object *throwable, zend_string *service_name, uint64_t time, ddog_SpanBytes *span) { +static void ddtrace_collect_exception_debug_data(zend_object *exception, zend_object *throwable, zend_string *service_name, uint64_t time, ddog_SpanNode *span) { if (!ddtrace_exception_debugging_is_active()) { return; } @@ -412,8 +412,8 @@ static void ddtrace_collect_exception_debug_data(zend_object *exception, zend_ob zend_ulong exception_long_hash = ddtrace_compute_exception_hash(exception); php_hash_bin2hex(exception_hash, (unsigned char *)&exception_long_hash, sizeof(exception_long_hash)); - ddog_add_str_span_meta_str(span, "error.debug_info_captured", "true"); - ddog_add_str_span_meta_CharSlice(span, "_dd.debug.error.exception_hash", (ddog_CharSlice){.ptr = exception_hash, .len = hash_len}); + dd_span_attr_str(span, "error.debug_info_captured", "true"); + ddog_attributes_add_lit(ddog_span_get_attributes(span), "_dd.debug.error.exception_hash", (ddog_CharSlice){.ptr = exception_hash, .len = hash_len}); if (!ddog_exception_hash_limiter_inc(DATADOG_G(sidecar), (uint64_t)exception_long_hash, get_DD_EXCEPTION_REPLAY_CAPTURE_INTERVAL_SECONDS())) { LOG(TRACE, "Skipping exception replay capture due to hash %.*s already recently hit", hash_len, exception_hash); @@ -423,7 +423,7 @@ static void ddtrace_collect_exception_debug_data(zend_object *exception, zend_ob char *exception_id = zend_arena_alloc(&DDTRACE_G(debugger_capture_arena).arena, uuid_len); ddog_snapshot_format_new_uuid((uint8_t(*)[uuid_len])exception_id); - ddog_add_str_span_meta_CharSlice(span, "_dd.debug.error.exception_id", (ddog_CharSlice){.ptr = exception_id, .len = uuid_len}); + ddog_attributes_add_lit(ddog_span_get_attributes(span), "_dd.debug.error.exception_id", (ddog_CharSlice){.ptr = exception_id, .len = uuid_len}); memset(&DDTRACE_G(exception_debugger_buffer), 0, sizeof(DDTRACE_G(exception_debugger_buffer))); @@ -536,7 +536,7 @@ static void ddtrace_collect_exception_debug_data(zend_object *exception, zend_ob } // Guarantees that tag will only be added once, will stop trying to add tags if it fails. -void ddtrace_exception_to_meta(zend_object *exception, zend_string *service_name, uint64_t time, ddog_SpanBytes *span, enum dd_exception exception_state) { +void ddtrace_exception_to_meta(zend_object *exception, zend_string *service_name, uint64_t time, ddog_SpanNode *span, enum dd_exception exception_state) { zend_object *exception_root = exception; zend_string *full_trace = zai_get_trace_without_args_from_exception(exception); diff --git a/tracer/exception_serialize.h b/tracer/exception_serialize.h index 38f1a1fb3f..345106e561 100644 --- a/tracer/exception_serialize.h +++ b/tracer/exception_serialize.h @@ -9,7 +9,7 @@ enum dd_exception { DD_EXCEPTION_UNCAUGHT, }; -void ddtrace_exception_to_meta(zend_object *exception, zend_string *service_name, uint64_t time, ddog_SpanBytes *context, enum dd_exception exception_state); +void ddtrace_exception_to_meta(zend_object *exception, zend_string *service_name, uint64_t time, ddog_SpanNode *span, enum dd_exception exception_state); void ddtrace_create_capture_value(zval *zv, struct ddog_CaptureValue *value, const ddog_CaptureConfiguration *config, int remaining_nesting); #endif // DD_EXCEPTION_REPLAY_H diff --git a/tracer/functions.c b/tracer/functions.c index f0fa8a57d7..0ec30f4444 100644 --- a/tracer/functions.c +++ b/tracer/functions.c @@ -12,9 +12,11 @@ #ifdef __linux__ #include "otel_context.h" #include +#include #endif #include "random.h" #include "serializer.h" +#include "span_tags_view.h" #include "trace_context.h" #include "weak_resources.h" #include @@ -105,53 +107,6 @@ static void dd_span_event_construct(ddtrace_span_event *event, zend_string *name /* DDTrace\SpanEvent */ zend_class_entry *ddtrace_ce_span_event; -PHP_METHOD(DDTrace_SpanEvent, jsonSerialize) { - ddtrace_span_event *event = (ddtrace_span_event*)Z_OBJ_P(ZEND_THIS); - - zval array; - array_init(&array); - - Z_TRY_ADDREF(event->property_name); - add_assoc_zval_ex(&array, ZEND_STRL("name"), &event->property_name); - Z_TRY_ADDREF(event->property_timestamp); - add_assoc_zval_ex(&array, ZEND_STRL("time_unix_nano"), &event->property_timestamp); - - // Handle attributes dynamically - zval *attributes = &event->property_attributes; - zval combined_attributes; - array_init(&combined_attributes); - - if (instanceof_function(event->std.ce, ddtrace_ce_exception_span_event)) { - // Handle exception attributes dynamically if an exception property exists - ddtrace_exception_span_event *exception_event = (ddtrace_exception_span_event *) event; - zval *exception = &exception_event->property_exception; - if (Z_TYPE_P(exception) == IS_OBJECT && instanceof_function(Z_OBJCE_P(exception), zend_ce_throwable)) { - // Get exception message, type, and stack trace directly - zend_string *message = zai_exception_message(Z_OBJ_P(exception)); - if (ZSTR_LEN(message)) { - add_assoc_str_ex(&combined_attributes, ZEND_STRL("exception.message"), zend_string_copy(message)); - } - add_assoc_str_ex(&combined_attributes, ZEND_STRL("exception.type"), zend_string_copy(Z_OBJCE_P(exception)->name)); - - // Get the exception stack trace using zai_get_trace_without_args_from_exception - zend_string *stacktrace = zai_get_trace_without_args_from_exception(Z_OBJ_P(exception)); - add_assoc_str_ex(&combined_attributes, ZEND_STRL("exception.stacktrace"), stacktrace); - } - } - - if (Z_TYPE_P(attributes) == IS_ARRAY) { - zend_hash_copy(Z_ARRVAL(combined_attributes), Z_ARRVAL_P(attributes), (copy_ctor_func_t)zval_add_ref); - } - - if (zend_hash_num_elements(Z_ARRVAL(combined_attributes)) > 0) { - add_assoc_zval_ex(&array, ZEND_STRL("attributes"), &combined_attributes); - } else { - zval_ptr_dtor(&combined_attributes); // Clean up if no elements - } - - RETURN_ARR(Z_ARR(array)); // Return the array -} - PHP_METHOD(DDTrace_SpanEvent, __construct) { UNUSED(return_value); @@ -205,37 +160,6 @@ PHP_METHOD(DDTrace_ExceptionSpanEvent, __construct) /* DDTrace\SpanLink */ zend_class_entry *ddtrace_ce_span_link; -PHP_METHOD(DDTrace_SpanLink, jsonSerialize) { - ddtrace_span_link *link = (ddtrace_span_link *)Z_OBJ_P(ZEND_THIS); - - zend_array *array = zend_new_array(5); - - zend_string *trace_id = zend_string_init("trace_id", sizeof("trace_id") - 1, 0); - zend_string *span_id = zend_string_init("span_id", sizeof("span_id") - 1, 0); - zend_string *trace_state = zend_string_init("trace_state", sizeof("trace_state") - 1, 0); - zend_string *attributes = zend_string_init("attributes", sizeof("attributes") - 1, 0); - zend_string *dropped_attributes_count = zend_string_init("dropped_attributes_count", sizeof("dropped_attributes_count") - 1, 0); - - Z_TRY_ADDREF(link->property_trace_id); - zend_hash_add(array, trace_id, &link->property_trace_id); - Z_TRY_ADDREF(link->property_span_id); - zend_hash_add(array, span_id, &link->property_span_id); - Z_TRY_ADDREF(link->property_trace_state); - zend_hash_add(array, trace_state, &link->property_trace_state); - Z_TRY_ADDREF(link->property_attributes); - zend_hash_add(array, attributes, &link->property_attributes); - Z_TRY_ADDREF(link->property_dropped_attributes_count); - zend_hash_add(array, dropped_attributes_count, &link->property_dropped_attributes_count); - - zend_string_release(trace_id); - zend_string_release(span_id); - zend_string_release(trace_state); - zend_string_release(attributes); - zend_string_release(dropped_attributes_count); - - RETURN_ARR(array); -} - void ddtrace_build_span_link_from_result(ddtrace_distributed_tracing_result *result, ddtrace_span_link *link) { ZVAL_STR(&link->property_trace_id, datadog_trace_id_as_hex_string(result->trace_id)); ZVAL_STR(&link->property_span_id, ddtrace_span_id_as_hex_string(result->parent_id)); @@ -317,6 +241,7 @@ static zend_object *dd_init_span_data_object(zend_class_entry *class_type, ddtra array_init(&span->property_events); array_init(&span->property_peer_service_sources); array_init(&span->property_on_close); + array_init(&span->property_attributes); #endif // Explicitly assign property-mapped NULLs span->stack = NULL; @@ -366,6 +291,7 @@ static zend_object *ddtrace_span_stack_create(zend_class_entry *class_type) { #if PHP_VERSION_ID < 80000 // Not handled in arginfo on these old versions array_init(&stack->property_span_creation_observers); + array_init(&stack->property_attributes); #endif return &stack->std; } @@ -434,6 +360,7 @@ static zend_object *ddtrace_span_stack_clone_obj(zend_object *old_obj) { } static void ddtrace_span_data_free_storage(zend_object *object) { + ddtrace_span_tags_views_release(OBJ_SPANDATA(object)); zend_object_std_dtor(object); // Prevent use after free after zend_objects_store_free_object_storage is called (e.g. preloading) [PHP < 8.1] memset(object->properties_table, 0, sizeof(ddtrace_span_data) - XtOffsetOf(ddtrace_span_data, std.properties_table)); @@ -502,6 +429,14 @@ static zval *ddtrace_span_data_readonly(zend_object *object, zend_string *member #endif } + if (ddtrace_span_tags_view_write_property(obj, prop_name, value)) { +#if PHP_VERSION_ID >= 70400 + return value; +#else + return; +#endif + } + ddtrace_span_data *span = OBJ_SPANDATA(obj); // As per unified service tagging spec if a span is created with a service name different from the global // service name it will not inherit the global version value, unless it has no ancestor traces. @@ -523,7 +458,7 @@ static zval *ddtrace_span_data_readonly(zend_object *object, zend_string *member } } if (Z_TYPE_P(value) == IS_STRING && !zend_is_identical(&span->property_service, value)) { - zend_array *meta = ddtrace_property_array(&span->property_meta); + zend_array *meta = ddtrace_property_array(&span->property_attributes); zval val; ZVAL_NEW_STR(&val, zend_string_init("m", 1, 0)); zend_hash_str_update(meta, ZEND_STRL("_dd.svc_src"), &val); @@ -770,6 +705,7 @@ static void dd_register_span_data_ce(void) { ddtrace_span_data_handlers.free_obj = ddtrace_span_data_free_storage; ddtrace_span_data_handlers.write_property = ddtrace_span_data_readonly; ddtrace_span_data_handlers.get_constructor = ddtrace_span_data_get_constructor; + ddtrace_span_tags_view_install(&ddtrace_span_data_handlers); ddtrace_ce_inferred_span_data = register_class_DDTrace_InferredSpanData(ddtrace_ce_span_data); ddtrace_ce_inferred_span_data->create_object = ddtrace_inferred_span_data_create; @@ -824,6 +760,7 @@ static void dd_register_fatal_error_ce(void) { zend_class_entry *ddtrace_ce_integration; zend_class_entry *ddtrace_ce_git_metadata; +zend_class_entry *ddtrace_ce_span_kind; zend_object_handlers datadog_git_metadata_handlers; static zend_object *datadog_git_metadata_create(zend_class_entry *class_type) { @@ -841,12 +778,14 @@ void ddtrace_register_functions_and_classes(int module_number) { register_ddtrace_symbols(module_number); dd_register_span_data_ce(); + ddtrace_register_span_tags_view(); dd_register_fatal_error_ce(); ddtrace_ce_integration = register_class_DDTrace_Integration(); ddtrace_ce_ffe_result = register_class_DDTrace_FfeResult(); - ddtrace_ce_span_link = register_class_DDTrace_SpanLink(php_json_serializable_ce); - ddtrace_ce_span_event = register_class_DDTrace_SpanEvent(php_json_serializable_ce); + ddtrace_ce_span_link = register_class_DDTrace_SpanLink(); + ddtrace_ce_span_event = register_class_DDTrace_SpanEvent(); ddtrace_ce_exception_span_event = register_class_DDTrace_ExceptionSpanEvent(ddtrace_ce_span_event); + ddtrace_ce_span_kind = register_class_DDTrace_SpanKind(); ddtrace_ce_git_metadata = register_class_DDTrace_GitMetadata(); ddtrace_ce_git_metadata->create_object = datadog_git_metadata_create; @@ -909,7 +848,7 @@ PHP_FUNCTION(DDTrace_add_distributed_tag) { zend_array *target_table, *propagated; if (DDTRACE_G(active_stack)->root_span) { - target_table = ddtrace_property_array(&DDTRACE_G(active_stack)->root_span->property_meta); + target_table = ddtrace_property_array(&DDTRACE_G(active_stack)->root_span->property_attributes); propagated = ddtrace_property_array(&DDTRACE_G(active_stack)->root_span->property_propagated_tags); } else { target_table = &DDTRACE_G(root_span_tags_preset); @@ -930,7 +869,7 @@ PHP_FUNCTION(DDTrace_add_distributed_tag) { static void _ddtrace_set_user(zend_string *user_id, zend_array *metadata, zend_bool propagate) { zend_array *target_table, *propagated; if (DDTRACE_G(active_stack)->root_span) { - target_table = ddtrace_property_array(&DDTRACE_G(active_stack)->root_span->property_meta); + target_table = ddtrace_property_array(&DDTRACE_G(active_stack)->root_span->property_attributes); propagated = ddtrace_property_array(&DDTRACE_G(active_stack)->root_span->property_propagated_tags); } else { target_table = &DDTRACE_G(root_span_tags_preset); @@ -1012,7 +951,7 @@ PHP_FUNCTION(datadog_appsec_v2_track_user_login_success) { zend_array *target_table; if (DDTRACE_G(active_stack)->root_span) { - target_table = ddtrace_property_array(&DDTRACE_G(active_stack)->root_span->property_meta); + target_table = ddtrace_property_array(&DDTRACE_G(active_stack)->root_span->property_attributes); } else { target_table = &DDTRACE_G(root_span_tags_preset); } @@ -1125,7 +1064,7 @@ PHP_FUNCTION(datadog_appsec_v2_track_user_login_failure) { zend_array *target_table; if (DDTRACE_G(active_stack)->root_span) { - target_table = ddtrace_property_array(&DDTRACE_G(active_stack)->root_span->property_meta); + target_table = ddtrace_property_array(&DDTRACE_G(active_stack)->root_span->property_attributes); } else { target_table = &DDTRACE_G(root_span_tags_preset); } @@ -1197,10 +1136,15 @@ PHP_FUNCTION(dd_trace_serialize_closed_spans) { ddtrace_mark_all_span_stacks_flushable(); - ddog_TracesBytes *traces = ddog_get_traces(); - ddtrace_serialize_closed_spans_with_cycle(traces, false); + // Introspection is a debug view: always finalize into the in-memory V1 builder (no sidecar + // needed) and read it back via the V1 getters, so the shape is uniform across versions/senders. + ddtrace_serialize_ctx serialize_ctx = {.builder = ddog_v1_new_builder(), .chunk = DD_CHUNK_NONE}; + ddtrace_serialize_ctx *ctx = &serialize_ctx; + + ddtrace_serialize_closed_spans_with_cycle(ctx, false); - zval traces_zv = dd_serialize_rust_traces_to_zval(traces); + zval traces_zv = dd_serialize_rust_to_zval(ctx->builder); + ddog_v1_free_builder(ctx->builder); if (zend_hash_num_elements(Z_ARR(traces_zv)) == 1) { ZVAL_COPY(return_value, zend_hash_get_current_data(Z_ARR(traces_zv))); @@ -1216,7 +1160,6 @@ PHP_FUNCTION(dd_trace_serialize_closed_spans) { } ZEND_HASH_FOREACH_END(); } - ddog_free_traces(traces); zval_ptr_dtor(&traces_zv); ddtrace_free_span_stacks(false); @@ -1249,47 +1192,6 @@ PHP_FUNCTION(dd_trace_disable_in_request) { RETURN_BOOL(1); } -PHP_FUNCTION(dd_trace_reset) { - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } - - if (datadog_disable) { - RETURN_BOOL(0); - } - - // TODO ?? - RETURN_BOOL(1); -} - -/* {{{ proto string dd_trace_serialize_msgpack(array trace_array) */ -PHP_FUNCTION(dd_trace_serialize_msgpack) { - zval *trace_array; - - if (zend_parse_parameters(ZEND_NUM_ARGS(), "a", &trace_array) == FAILURE) { - RETURN_THROWS(); - } - - if (!get_DD_TRACE_ENABLED()) { - RETURN_BOOL(0); - } - - if (ddtrace_serialize_simple_array(trace_array, return_value) != 1) { - RETURN_BOOL(0); - } -} /* }}} */ - -// method used to be able to easily breakpoint the execution at specific PHP line in GDB -PHP_FUNCTION(dd_trace_noop) { - UNUSED(execute_data); - - if (!get_DD_TRACE_ENABLED()) { - RETURN_BOOL(0); - } - - RETURN_BOOL(1); -} - /* {{{ proto int dd_trace_dd_get_memory_limit() */ PHP_FUNCTION(dd_trace_dd_get_memory_limit) { if (zend_parse_parameters_none() == FAILURE) { @@ -1354,30 +1256,6 @@ PHP_FUNCTION(ddtrace_config_integration_enabled) { RETVAL_BOOL(ddtrace_integrations[integration->name].is_enabled()); } -PHP_FUNCTION(DDTrace_Config_integration_analytics_enabled) { - zend_string *name; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &name) != SUCCESS) { - RETURN_NULL(); - } - ddtrace_integration *integration = ddtrace_get_integration_from_string(name); - if (integration == NULL) { - RETURN_FALSE; - } - RETVAL_BOOL(integration->is_analytics_enabled()); -} - -PHP_FUNCTION(DDTrace_Config_integration_analytics_sample_rate) { - zend_string *name; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &name) != SUCCESS) { - RETURN_NULL(); - } - ddtrace_integration *integration = ddtrace_get_integration_from_string(name); - if (integration == NULL) { - RETURN_DOUBLE(DD_INTEGRATION_ANALYTICS_SAMPLE_RATE_DEFAULT); - } - RETVAL_DOUBLE(integration->get_sample_rate()); -} - /* This is only exposed to serialize the container ID into an HTTP Agent header for the userland transport * (`DDTrace\Transport\Http`). The background sender (extension-level transport) is decoupled from userland * code to create any HTTP Agent headers. Once the dependency on the userland transport has been removed, @@ -1944,69 +1822,6 @@ PHP_FUNCTION(DDTrace_ffe_evaluate) { ddtrace_ffe_update_empty_array_property(return_value, ZEND_STRL("providerState")); } -PHP_FUNCTION(dd_trace_send_traces_via_thread) { - char *payload = NULL; - zend_long num_traces = 0; - size_t payload_len = 0; - zval *curl_headers = NULL; - - // Agent HTTP headers are now set at the extension level so 'curl_headers' from userland is ignored - if (zend_parse_parameters(ZEND_NUM_ARGS(), "las", &num_traces, &curl_headers, &payload, - &payload_len) == FAILURE) { - RETURN_THROWS(); - } -#ifndef _WIN32 - bool result = ddtrace_send_traces_via_thread(num_traces, payload, payload_len); - dd_prepare_for_new_trace(); - RETURN_BOOL(result); -#else - RETURN_FALSE; -#endif -} - -PHP_FUNCTION(dd_trace_buffer_span) { - zval *trace_array = NULL; - - if (zend_parse_parameters(ZEND_NUM_ARGS(), "a", &trace_array) == FAILURE) { - RETURN_THROWS(); - } - -#ifndef _WIN32 - if (!get_DD_TRACE_ENABLED() || get_global_DD_TRACE_SIDECAR_TRACE_SENDER()) { - RETURN_BOOL(0); - } - - char *data; - size_t size; - if (ddtrace_serialize_simple_array_into_c_string(trace_array, &data, &size)) { - RETVAL_BOOL(ddtrace_coms_buffer_data(DDTRACE_G(traces_group_id), data, size)); - - free(data); - return; - } else { - RETURN_FALSE; - } -#else - RETURN_BOOL(0); -#endif -} - -PHP_FUNCTION(dd_trace_coms_trigger_writer_flush) { - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } - -#ifndef _WIN32 - if (!get_DD_TRACE_ENABLED() || get_global_DD_TRACE_SIDECAR_TRACE_SENDER()) { - RETURN_LONG(0); - } - - RETURN_LONG(ddtrace_coms_trigger_writer_flush()); -#else - RETURN_BOOL(0); -#endif -} - #define FUNCTION_NAME_MATCHES(function) zend_string_equals_literal(function_val, function) static bool ddtrace_otel_config_is_reportable(zend_string *name) { @@ -2774,7 +2589,7 @@ PHP_FUNCTION(DDTrace_set_distributed_tracing_context) { zend_array *root_meta = &DDTRACE_G(root_span_tags_preset); zend_array *propagated_tags = &DDTRACE_G(propagated_root_span_tags); if (root_span) { - root_meta = ddtrace_property_array(&root_span->property_meta); + root_meta = ddtrace_property_array(&root_span->property_attributes); propagated_tags = ddtrace_property_array(&root_span->property_propagated_tags); } diff --git a/tracer/handlers_http.h b/tracer/handlers_http.h index 82ebffbf7f..f5a78b6ee7 100644 --- a/tracer/handlers_http.h +++ b/tracer/handlers_http.h @@ -323,7 +323,7 @@ static inline void ddtrace_inject_distributed_headers_config(zend_array *array, } ddtrace_root_span_data *root_span = DDTRACE_G(active_stack) ? DDTRACE_G(active_stack)->root_span : NULL; - zend_array *meta = root_span ? ddtrace_property_array(&root_span->property_meta) : &DDTRACE_G(root_span_tags_preset); + zend_array *meta = root_span ? ddtrace_property_array(&root_span->property_attributes) : &DDTRACE_G(root_span_tags_preset); if (!get_DD_APM_TRACING_ENABLED() && !ddtrace_asm_event_emitted() && !ddtrace_trace_source_is_meta_asm_sourced(meta)) { return; } diff --git a/tracer/handlers_httpstreams.c b/tracer/handlers_httpstreams.c index 23617d2eb1..6e8a7f7e07 100644 --- a/tracer/handlers_httpstreams.c +++ b/tracer/handlers_httpstreams.c @@ -69,14 +69,13 @@ static php_stream *dd_stream_opener( if (span) { ddtrace_set_global_span_properties(span); - zend_array *meta = ddtrace_property_array(&span->property_meta); + zend_array *meta = ddtrace_property_array(&span->property_attributes); zval zv; - ZVAL_STRING(&zv, "php.stream"); - zend_hash_str_update(meta, ZEND_STRL("component"), &zv); - - ZVAL_STRING(&zv, "client"); - zend_hash_str_update(meta, ZEND_STRL("span.kind"), &zv); + // Set on the properties; the serializer mirrors them into meta at serialization time. + zval_ptr_dtor(&span->property_component); + ZVAL_STRING(&span->property_component, "php.stream"); + ZVAL_LONG(&span->property_span_kind, 3 /* DDTrace\SpanKind::CLIENT */); ZVAL_STRING(&zv, filename); zend_hash_str_update(meta, ZEND_STRL("http.url"), &zv); @@ -91,7 +90,7 @@ static php_stream *dd_stream_opener( if (method_zv && Z_TYPE_P(method_zv) == IS_STRING) { // `zend_hash_str_update()` moves the zval payload into the hashtable without adding a ref. // `method_zv` is owned by the stream context options array, so we must add a ref (via ZVAL_COPY) - // to avoid leaving span meta with a dangling zend_string once the options array is destroyed. + // to avoid leaving span attributes with a dangling zend_string once the options array is destroyed. zval method_copy; ZVAL_COPY(&method_copy, method_zv); zend_hash_str_update(meta, ZEND_STRL("http.method"), &method_copy); diff --git a/tracer/hook/uhook_attributes.c b/tracer/hook/uhook_attributes.c index 405adb5c50..8494e369b3 100644 --- a/tracer/hook/uhook_attributes.c +++ b/tracer/hook/uhook_attributes.c @@ -4,6 +4,7 @@ #include "../ddtrace.h" #include "../configuration.h" #include "../span.h" +#include #include "uhook_attributes_arginfo.h" #include "uhook.h" @@ -102,6 +103,46 @@ static zval dd_uhook_save_value(zval *value) { return ret; } +// A tag value as it serialized from meta: string leaves (null -> "null"), "" for an empty or +// recursive (reference cycle) array/object, so the v0.4 wire is unchanged now that it lives in the +// attributes. +static void dd_uhook_tag_as_meta(zval *dst, zval *src) { + ZVAL_DEREF(src); + if (Z_TYPE_P(src) != IS_ARRAY && Z_TYPE_P(src) != IS_OBJECT) { + datadog_convert_to_string(dst, src); + return; + } + HashTable *ht = Z_TYPE_P(src) == IS_ARRAY ? Z_ARR_P(src) : Z_OBJPROP_P(src); + if (!zend_hash_num_elements(ht) || Z_IS_RECURSIVE_P(src)) { + ZVAL_EMPTY_STRING(dst); + return; + } + // Immutable arrays cannot form a cycle and must never be written to. + bool guard = Z_TYPE_P(src) != IS_ARRAY || !(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE); + if (guard) { + Z_PROTECT_RECURSION_P(src); + } + array_init_size(dst, zend_hash_num_elements(ht)); + zend_string *key; + zend_ulong idx; + zval *val; + ZEND_HASH_FOREACH_KEY_VAL_IND(ht, idx, key, val) { + if (key && ZSTR_LEN(key) && ZSTR_VAL(key)[0] == '\0') { + continue; // protected and private members + } + zval leaf; + dd_uhook_tag_as_meta(&leaf, val); + if (key) { + zend_hash_update(Z_ARR_P(dst), key, &leaf); + } else { + zend_hash_index_update(Z_ARR_P(dst), idx, &leaf); + } + } ZEND_HASH_FOREACH_END(); + if (guard) { + Z_UNPROTECT_RECURSION_P(src); + } +} + static void dd_fill_span_data(dd_uhook_def *def, ddtrace_span_data *span) { if (def->name) { zval *name = &span->property_name; @@ -119,7 +160,7 @@ static void dd_fill_span_data(dd_uhook_def *def, ddtrace_span_data *span) { zval_ptr_dtor(service); ZVAL_STR_COPY(service, def->service); if (service_changed) { - zend_array *meta = ddtrace_property_array(&span->property_meta); + zend_array *meta = ddtrace_property_array(&span->property_attributes); zval val; ZVAL_NEW_STR(&val, zend_string_init("m", 1, 0)); zend_hash_str_update(meta, ZEND_STRL("_dd.svc_src"), &val); @@ -131,13 +172,14 @@ static void dd_fill_span_data(dd_uhook_def *def, ddtrace_span_data *span) { ZVAL_STR_COPY(type, def->type); } if (def->tags) { - zend_array *meta = ddtrace_property_array(&span->property_meta); + zend_array *meta = ddtrace_property_array(&span->property_attributes); zend_string *key; zval *value; ZEND_HASH_FOREACH_STR_KEY_VAL(def->tags, key, value) { if (key) { - Z_TRY_ADDREF_P(value); - zend_hash_update(meta, key, value); + zval tag; + dd_uhook_tag_as_meta(&tag, value); + zend_hash_update(meta, key, &tag); } } ZEND_HASH_FOREACH_END(); } @@ -211,7 +253,7 @@ static bool dd_uhook_begin(zend_ulong invocation, zend_execute_data *execute_dat bool new_span; dyn->span = ddtrace_alloc_execute_data_span_ex(invocation, execute_data, &new_span); dd_fill_span_data(def, dyn->span); - dd_uhook_fill_args_in_meta(def, ddtrace_property_array(&dyn->span->property_meta), execute_data); + dd_uhook_fill_args_in_meta(def, ddtrace_property_array(&dyn->span->property_attributes), execute_data); if (new_span) { ddtrace_observe_opened_span(dyn->span); } @@ -240,7 +282,7 @@ static void dd_uhook_generator_resumption(zend_ulong invocation, zend_execute_da dyn->span = ddtrace_alloc_execute_data_span_ex(invocation, execute_data, &new_span); dd_fill_span_data(def, dyn->span); if (def->retval) { - zend_array *meta = ddtrace_property_array(&dyn->span->property_meta); + zend_array *meta = ddtrace_property_array(&dyn->span->property_attributes); zval val = dd_uhook_save_value(value); zend_hash_str_update(meta, ZEND_STRL("send_value"), &val); } @@ -271,7 +313,7 @@ static void dd_uhook_generator_yield(zend_ulong invocation, zend_execute_data *e dd_trace_stop_span_time(dyn->span); if (def->retval) { - zend_array *meta = ddtrace_property_array(&dyn->span->property_meta); + zend_array *meta = ddtrace_property_array(&dyn->span->property_attributes); zval keyzv = dd_uhook_save_value(key); zend_hash_str_update(meta, ZEND_STRL("yield_key"), &keyzv); zval val = dd_uhook_save_value(value); @@ -303,7 +345,7 @@ static void dd_uhook_end(zend_ulong invocation, zend_execute_data *execute_data, dd_trace_stop_span_time(dyn->span); if (def->retval) { - zend_array *meta = ddtrace_property_array(&dyn->span->property_meta); + zend_array *meta = ddtrace_property_array(&dyn->span->property_attributes); zval val = dd_uhook_save_value(retval); zend_hash_str_update(meta, ZEND_STRL("return_value"), &val); } @@ -416,7 +458,10 @@ void dd_uhook_on_function_resolve(zend_function *func) { } else if (zend_string_equals_literal(name, "tags") && Z_TYPE(value) == IS_ARRAY) { if (!def->tags) { def->tags = Z_ARR(value); - GC_ADDREF(def->tags); + // Immutable arrays (the empty array, opcache) must never be written to. + if (!(GC_FLAGS(def->tags) & IS_ARRAY_IMMUTABLE)) { + GC_ADDREF(def->tags); + } } } diff --git a/tracer/integrations/exec_integration.c b/tracer/integrations/exec_integration.c index 8de53fa675..92e26a3bab 100644 --- a/tracer/integrations/exec_integration.c +++ b/tracer/integrations/exec_integration.c @@ -94,14 +94,15 @@ static int dd_php_stdiop_close_wrapper(php_stream *stream, int close_handle) { ddtrace_span_data *span_data = OBJ_SPANDATA(Z_OBJ_P(span_data_zv)); - zend_array *meta = ddtrace_property_array(&span_data->property_meta); + zend_array *meta = ddtrace_property_array(&span_data->property_attributes); if (ret == -1) { zval zv; ZVAL_INTERNED_STR(&zv, pclose_minus_one_zstr); zend_hash_update(meta, error_message_zstr, &zv); } else { + // A string, as the tag was when it lived in meta. zval zexit; - ZVAL_LONG(&zexit, ret); + ZVAL_STR(&zexit, zend_long_to_str(ret)); zend_hash_update(meta, cmd_exit_code_zstr, &zexit); } @@ -137,7 +138,7 @@ static void dd_waitpid(ddtrace_span_data *span_data, dd_proc_span *proc) { // already closed return; } - zend_array *meta = ddtrace_property_array(&span_data->property_meta); + zend_array *meta = ddtrace_property_array(&span_data->property_attributes); int wstatus; bool exited = false; @@ -183,7 +184,7 @@ static void dd_waitpid(ddtrace_span_data *span_data, dd_proc_span *proc) { if (exited) { zval zexit; - ZVAL_LONG(&zexit, wstatus); + ZVAL_STR(&zexit, zend_long_to_str(wstatus)); // set tag 'cmd.exit_code' zend_hash_update(meta, cmd_exit_code_zstr, &zexit); diff --git a/tracer/live_debugger.c b/tracer/live_debugger.c index ea74864954..cc0ad0d6ef 100644 --- a/tracer/live_debugger.c +++ b/tracer/live_debugger.c @@ -447,7 +447,7 @@ static bool dd_span_probe_begin(zend_ulong invocation, zend_execute_data *execut zval probe_id; ZVAL_STR_COPY(&probe_id, def->probe_id); - zend_hash_str_update(ddtrace_property_array(&dyn->span->property_meta), ZEND_STRL("debugger.probeid"), &probe_id); + zend_hash_str_update(ddtrace_property_array(&dyn->span->property_attributes), ZEND_STRL("debugger.probeid"), &probe_id); if (new_span) { ddtrace_observe_opened_span(dyn->span); @@ -500,7 +500,7 @@ static void dd_span_decoration_end(zend_ulong invocation, zend_execute_data *exe if (def->probe.probe.span_decoration.target == DDOG_SPAN_PROBE_TARGET_ROOT) { span = &span->stack->root_span->span; } - zend_array *meta = ddtrace_property_array(&span->property_meta); + zend_array *meta = ddtrace_property_array(&span->property_attributes); bool condition_result = true; const ddog_ProbeCondition *const *condition = def->probe.probe.span_decoration.conditions; diff --git a/tracer/priority_sampling/priority_sampling.c b/tracer/priority_sampling/priority_sampling.c index b10c071d06..52bffb6ab5 100644 --- a/tracer/priority_sampling/priority_sampling.c +++ b/tracer/priority_sampling/priority_sampling.c @@ -45,9 +45,13 @@ void ddtrace_try_read_agent_rate(void) { } } +static void dd_del_root_tag(ddtrace_root_span_data *root_span, const char *key, size_t len) { + zend_hash_str_del(ddtrace_property_array(&root_span->property_attributes), key, len); +} + static void dd_update_decision_maker_tag(ddtrace_root_span_data *root_span, enum dd_sampling_mechanism mechanism) { - zend_array *meta = ddtrace_property_array(&root_span->property_meta); + zend_array *attributes = ddtrace_property_array(&root_span->property_attributes); zend_long sampling_priority = zval_get_long(&root_span->property_sampling_priority); if (Z_TYPE(root_span->property_propagated_sampling_priority) != IS_UNDEF && @@ -58,15 +62,15 @@ static void dd_update_decision_maker_tag(ddtrace_root_span_data *root_span, if (sampling_priority > 0 && sampling_priority != DDTRACE_PRIORITY_SAMPLING_UNKNOWN) { zval dm; ZVAL_STR(&dm, zend_strpprintf(0, "-%d", mechanism)); - zend_hash_str_update(meta, "_dd.p.dm", sizeof("_dd.p.dm") - 1, &dm); + zend_hash_str_update(attributes, ZEND_STRL("_dd.p.dm"), &dm); zend_hash_str_add_empty_element(ddtrace_property_array(&root_span->property_propagated_tags), ZEND_STRL("_dd.p.dm")); } else { - zend_hash_str_del(meta, "_dd.p.dm", sizeof("_dd.p.dm") - 1); + dd_del_root_tag(root_span, ZEND_STRL("_dd.p.dm")); } } static void dd_update_knuth_sampling_rate_tag(ddtrace_root_span_data *root_span, double sample_rate) { - zend_array *meta = ddtrace_property_array(&root_span->property_meta); + zend_array *attributes = ddtrace_property_array(&root_span->property_attributes); char buf[32]; #if PHP_VERSION_ID < 80100 @@ -85,14 +89,14 @@ static void dd_update_knuth_sampling_rate_tag(ddtrace_root_span_data *root_span, } // Skip update if already set to the same value - zval *existing = zend_hash_str_find(meta, ZEND_STRL("_dd.p.ksr")); + zval *existing = zend_hash_str_find(attributes, ZEND_STRL("_dd.p.ksr")); if (existing && Z_TYPE_P(existing) == IS_STRING && zend_string_equals_cstr(Z_STR_P(existing), buf, len) == 0) { return; } zval ksr; ZVAL_STRINGL(&ksr, buf, len); - zend_hash_str_update(meta, ZEND_STRL("_dd.p.ksr"), &ksr); + zend_hash_str_update(attributes, ZEND_STRL("_dd.p.ksr"), &ksr); zend_hash_str_add_empty_element(ddtrace_property_array(&root_span->property_propagated_tags), ZEND_STRL("_dd.p.ksr")); } @@ -131,13 +135,12 @@ static bool dd_check_sampling_rule(zend_array *rule, ddtrace_span_data *span) { } if ((rule_pattern = zend_hash_str_find(rule, ZEND_STRL("tags"))) && Z_TYPE_P(rule_pattern) == IS_ARRAY) { zend_array *tag_rules = Z_ARR_P(rule_pattern); - zend_array *meta = ddtrace_property_array(&span->property_meta); - zend_array *metrics = ddtrace_property_array(&span->property_metrics); + zend_array *attributes = ddtrace_property_array(&span->property_attributes); zend_string *tag_name; ZEND_HASH_FOREACH_STR_KEY_VAL(tag_rules, tag_name, rule_pattern) { if (tag_name) { zval *value; - if (!(value = zend_hash_find(meta, tag_name)) && !(value = zend_hash_find(metrics, tag_name))) { + if (!(value = zend_hash_find(attributes, tag_name))) { return false; } if (!dd_rule_matches(rule_pattern, value, get_DD_TRACE_SAMPLING_RULES_FORMAT())) { @@ -159,8 +162,7 @@ static ddtrace_rule_result dd_match_rules(ddtrace_span_data *span, bool eval_roo return (ddtrace_rule_result){ .sampling_rate = 0, .rule = INT32_MAX, .mechanism = DD_MECHANISM_RULE }; } - zend_array *meta = ddtrace_property_array(&span->property_meta); - if (zend_hash_str_exists(meta, ZEND_STRL("manual.keep"))) { + if (ddtrace_span_find_tag(span, ZEND_STRL("manual.keep"))) { // manual.keep and manual.drop count as manual return (ddtrace_rule_result){ .sampling_rate = 1, .rule = -2, .mechanism = DD_MECHANISM_MANUAL }; } @@ -168,7 +170,7 @@ static ddtrace_rule_result dd_match_rules(ddtrace_span_data *span, bool eval_roo if (++index >= skip_at) { return (ddtrace_rule_result){ .sampling_rate = 0, .rule = INT32_MAX, .mechanism = DD_MECHANISM_RULE }; } - if (zend_hash_str_exists(meta, ZEND_STRL("manual.drop"))) { + if (ddtrace_span_find_tag(span, ZEND_STRL("manual.drop"))) { return (ddtrace_rule_result){ .sampling_rate = 0, .rule = -1, .mechanism = DD_MECHANISM_MANUAL }; } @@ -282,7 +284,7 @@ static void dd_decide_on_sampling(ddtrace_root_span_data *span) { } else { explicit_rule = false; - zval *env = zend_hash_str_find(ddtrace_property_array(&span->property_meta), ZEND_STRL("env")); + zval *env = ddtrace_span_find_tag(&span->span, ZEND_STRL("env")); if (!env) { env = &span->property_env; } @@ -330,7 +332,7 @@ static void dd_decide_on_sampling(ddtrace_root_span_data *span) { ddtrace_otel_update_trace_flags(span); #endif } - zend_hash_str_del(ddtrace_property_array(&span->property_meta), ZEND_STRL("_dd.p.ksr")); + dd_del_root_tag(span, ZEND_STRL("_dd.p.ksr")); return; } else { sample_rate = result.sampling_rate; @@ -355,38 +357,37 @@ static void dd_decide_on_sampling(ddtrace_root_span_data *span) { zval sample_rate_zv; ZVAL_DOUBLE(&sample_rate_zv, sample_rate); - zend_array *metrics = ddtrace_property_array(&span->property_metrics); + zend_array *attributes = ddtrace_property_array(&span->property_attributes); if (explicit_rule) { mechanism = result.mechanism; priority = sampling && !limited ? PRIORITY_SAMPLING_USER_KEEP : PRIORITY_SAMPLING_USER_REJECT; if (mechanism == DD_MECHANISM_MANUAL) { - zend_hash_str_del(metrics, ZEND_STRL("_dd.rule_psr")); - zend_hash_str_del(ddtrace_property_array(&span->property_meta), ZEND_STRL("_dd.p.ksr")); + dd_del_root_tag(span, ZEND_STRL("_dd.rule_psr")); + dd_del_root_tag(span, ZEND_STRL("_dd.p.ksr")); } else { - zend_hash_str_update(metrics, ZEND_STRL("_dd.rule_psr"), &sample_rate_zv); + zend_hash_str_update(attributes, ZEND_STRL("_dd.rule_psr"), &sample_rate_zv); dd_update_knuth_sampling_rate_tag(span, sample_rate); } - zend_hash_str_del(metrics, ZEND_STRL("_dd.agent_psr")); + dd_del_root_tag(span, ZEND_STRL("_dd.agent_psr")); } else { // manual if it's not just inherited, otherwise this value is irrelevant (as sampling priority will be default) mechanism = DDTRACE_G(agent_rate_by_service) ? DD_MECHANISM_AGENT_RATE : DD_MECHANISM_DEFAULT; priority = sampling && !limited ? PRIORITY_SAMPLING_AUTO_KEEP : PRIORITY_SAMPLING_AUTO_REJECT; - zend_hash_str_update(metrics, ZEND_STRL("_dd.agent_psr"), &sample_rate_zv); + zend_hash_str_update(attributes, ZEND_STRL("_dd.agent_psr"), &sample_rate_zv); if (mechanism == DD_MECHANISM_AGENT_RATE) { dd_update_knuth_sampling_rate_tag(span, sample_rate); } else { - zend_hash_str_del(ddtrace_property_array(&span->property_meta), ZEND_STRL("_dd.p.ksr")); + dd_del_root_tag(span, ZEND_STRL("_dd.p.ksr")); } } if (limited) { zval limit_zv; ZVAL_DOUBLE(&limit_zv, ddtrace_limiter_rate()); - zend_hash_str_update(ddtrace_property_array(&span->property_metrics), ZEND_STRL("_dd.limit_psr"), - &limit_zv); + zend_hash_str_update(attributes, ZEND_STRL("_dd.limit_psr"), &limit_zv); } if (mechanism == DD_MECHANISM_MANUAL || mechanism == DD_MECHANISM_ASM || limited || sample_rate <= 0) { diff --git a/tracer/serializer.c b/tracer/serializer.c index 5e6ae61ffb..fd0a3ee2fa 100644 --- a/tracer/serializer.c +++ b/tracer/serializer.c @@ -19,7 +19,6 @@ #include #include #include -#include #include #ifndef _WIN32 @@ -41,6 +40,7 @@ #include "ip_extraction.h" #include #include "priority_sampling/priority_sampling.h" +#include "random.h" #include "span.h" #include "uri_normalization.h" #include "user_request.h" @@ -327,7 +327,14 @@ static void dd_add_header_to_meta(zend_array *meta, const char *type, zend_strin } } -static void dd_add_header_to_rust_span(ddog_SpanBytes *span, const char *type, zend_string *lowerheader, +void dd_span_attr_str(ddog_SpanNode *span, const char *key, const char *val) { + ddog_attributes_add_lit(ddog_span_get_attributes(span), key, (ddog_CharSlice){ .ptr = val, .len = strlen(val) }); +} +void dd_span_attr_zstr(ddog_SpanNode *span, const char *key, zend_string *val) { + ddog_attributes_add_lit(ddog_span_get_attributes(span), key, dd_zend_string_to_CharSlice(val)); +} + +static void dd_add_header_to_rust_span(ddog_SpanNode *span, const char *type, zend_string *lowerheader, zend_string *headerval) { zval *header_config = zend_hash_find(get_DD_TRACE_HEADER_TAGS(), lowerheader); if (header_config != NULL && Z_TYPE_P(header_config) == IS_STRING) { @@ -344,7 +351,7 @@ static void dd_add_header_to_rust_span(ddog_SpanBytes *span, const char *type, z headertag = zend_string_copy(header_config_str); } - ddog_add_span_meta_zstr(span, headertag, headerval); + ddog_attributes_add_zstr(ddog_span_get_attributes(span), headertag, headerval); zend_string_release(headertag); } } @@ -441,7 +448,7 @@ static void dd_add_post_fields_to_meta_recursive(zend_array *meta, const char *t } void ddtrace_set_global_span_properties(ddtrace_span_data *span) { - zend_array *meta = ddtrace_property_array(&span->property_meta); + zend_array *meta = ddtrace_property_array(&span->property_attributes); zend_array *global_tags = get_DD_TAGS(); zend_string *global_key; zval *global_val; @@ -575,7 +582,7 @@ static zend_string *dd_get_referrer_host(zend_array *_server) { return ZSTR_EMPTY_ALLOC(); } -static bool dd_set_mapped_peer_service(ddog_SpanBytes *span, zend_string *peer_service) { +static bool dd_set_mapped_peer_service(ddog_SpanNode *span, zend_string *peer_service) { zend_array *peer_service_mapping = get_DD_TRACE_PEER_SERVICE_MAPPING(); if (zend_hash_num_elements(peer_service_mapping) == 0 || !peer_service) { return false; @@ -584,8 +591,8 @@ static bool dd_set_mapped_peer_service(ddog_SpanBytes *span, zend_string *peer_s zval* mapped_service_zv = zend_hash_find(peer_service_mapping, peer_service); if (mapped_service_zv) { zend_string *mapped_service = zval_get_string(mapped_service_zv); - ddog_add_str_span_meta_zstr(span, "peer.service.remapped_from", peer_service); - ddog_add_str_span_meta_zstr(span, "peer.service", mapped_service); + dd_span_attr_zstr(span, "peer.service.remapped_from", peer_service); + dd_span_attr_zstr(span, "peer.service", mapped_service); zend_string_release(mapped_service); return true; } @@ -611,14 +618,14 @@ struct superglob_equiv { }; static void dd_set_entrypoint_root_span_props(struct superglob_equiv *data, ddtrace_root_span_data *span) { - zend_array *meta = ddtrace_property_array(&span->property_meta); + zend_array *attributes = ddtrace_property_array(&span->property_attributes); if (data->server){ zend_string *http_url = dd_build_req_url(data->server); if (ZSTR_LEN(http_url) > 0) { zval http_url_zv; ZVAL_STR(&http_url_zv, http_url); - zend_hash_str_add_new(meta, ZEND_STRL("http.url"), &http_url_zv); + zend_hash_str_add_new(attributes, ZEND_STRL("http.url"), &http_url_zv); } } @@ -638,16 +645,25 @@ static void dd_set_entrypoint_root_span_props(struct superglob_equiv *data, ddtr if (method) { zval http_method; ZVAL_STR(&http_method, zend_string_init(method, strlen(method), 0)); - zend_hash_str_add_new(meta, ZEND_STRL("http.method"), &http_method); + zend_hash_str_add_new(attributes, ZEND_STRL("http.method"), &http_method); // Mark HTTP server entry spans with span.kind=server for client-side stats aggregation. - // Only add if not already set (e.g. by an OTel or framework integration). + // Written as a tag add-if-absent (not via the property) so a userland/OTel value wins. zval span_kind_server; ZVAL_STRING(&span_kind_server, "server"); - if (!zend_hash_str_add(meta, ZEND_STRL("span.kind"), &span_kind_server)) { + if (!zend_hash_str_add(attributes, ZEND_STRL("span.kind"), &span_kind_server)) { zval_ptr_dtor(&span_kind_server); } + // Default component to the SAPI (the server integration layer), add-if-absent so frameworks override it. + if (strcmp(sapi_module.name, "cli") != 0) { + zval component; + ZVAL_STRING(&component, sapi_module.name); + if (!zend_hash_str_add(attributes, ZEND_STRL("component"), &component)) { + zval_ptr_dtor(&component); + } + } + if (get_DD_TRACE_URL_AS_RESOURCE_NAMES_ENABLED()) { const char *uri = dd_get_req_uri(data->server); zval *prop_resource = &span->property_resource; @@ -677,21 +693,21 @@ static void dd_set_entrypoint_root_span_props(struct superglob_equiv *data, ddtr if (get_DD_TRACE_CLIENT_IP_ENABLED() && data->server) { zval server_zv; ZVAL_ARR(&server_zv, data->server); - ddtrace_extract_ip_from_headers(&server_zv, meta); + ddtrace_extract_ip_from_headers(&server_zv, attributes); } zend_string *user_agent = dd_get_user_agent(data->server); if (user_agent && ZSTR_LEN(user_agent) > 0) { zval http_useragent; ZVAL_STR_COPY(&http_useragent, user_agent); - zend_hash_str_add_new(meta, ZEND_STRL("http.useragent"), &http_useragent); + zend_hash_str_add_new(attributes, ZEND_STRL("http.useragent"), &http_useragent); } zend_string *referrer_host = dd_get_referrer_host(data->server); if (referrer_host && ZSTR_LEN(referrer_host) > 0) { zval http_referrer_host; ZVAL_STR(&http_referrer_host, referrer_host); - zend_hash_str_add_new(meta, ZEND_STRL("http.referrer_hostname"), &http_referrer_host); + zend_hash_str_update(attributes, ZEND_STRL("http.referrer_hostname"), &http_referrer_host); } if (data->server) { @@ -709,7 +725,7 @@ static void dd_set_entrypoint_root_span_props(struct superglob_equiv *data, ddtr } } - dd_add_header_to_meta(meta, "request", lowerheader, Z_STR_P(headerval)); + dd_add_header_to_meta(attributes, "request", lowerheader, Z_STR_P(headerval)); zend_string_release(lowerheader); } } @@ -720,7 +736,7 @@ static void dd_set_entrypoint_root_span_props(struct superglob_equiv *data, ddtr zval post_zv; ZVAL_ARR(&post_zv, data->post); zend_string *empty = ZSTR_EMPTY_ALLOC(); - dd_add_post_fields_to_meta_recursive(meta, "request", empty, &post_zv, get_DD_TRACE_HTTP_POST_DATA_PARAM_ALLOWED(), false); + dd_add_post_fields_to_meta_recursive(attributes, "request", empty, &post_zv, get_DD_TRACE_HTTP_POST_DATA_PARAM_ALLOWED(), false); zend_string_release(empty); } } @@ -737,11 +753,9 @@ void ddtrace_inherit_span_properties(ddtrace_span_data *span, ddtrace_span_data zval_ptr_dtor(prop_baggage); ZVAL_COPY_DEREF(prop_baggage, prop_parent_baggage); - zend_array *parent_meta = ddtrace_property_array(&parent->property_meta); - - zval *parent_svc_src = zend_hash_str_find(parent_meta, ZEND_STRL("_dd.svc_src")); + zval *parent_svc_src = ddtrace_span_find_tag(parent, ZEND_STRL("_dd.svc_src")); if (parent_svc_src) { - zend_array *child_meta = ddtrace_property_array(&span->property_meta); + zend_array *child_meta = ddtrace_property_array(&span->property_attributes); Z_TRY_ADDREF_P(parent_svc_src); zend_hash_str_update(child_meta, ZEND_STRL("_dd.svc_src"), parent_svc_src); } @@ -749,7 +763,7 @@ void ddtrace_inherit_span_properties(ddtrace_span_data *span, ddtrace_span_data zval *prop_version = &span->property_version; zval_ptr_dtor(prop_version); zval *version; - if ((version = zend_hash_str_find(parent_meta, ZEND_STRL("version")))) { + if ((version = ddtrace_span_find_tag(parent, ZEND_STRL("version")))) { zval old = *version; datadog_convert_to_string(version, version); zval_ptr_dtor(&old); @@ -761,7 +775,7 @@ void ddtrace_inherit_span_properties(ddtrace_span_data *span, ddtrace_span_data zval *prop_env = &span->property_env; zval_ptr_dtor(prop_env); zval *env; - if ((env = zend_hash_str_find(parent_meta, ZEND_STRL("env")))) { + if ((env = ddtrace_span_find_tag(parent, ZEND_STRL("env")))) { zval old = *env; datadog_convert_to_string(env, env); zval_ptr_dtor(&old); @@ -788,10 +802,8 @@ void ddtrace_set_root_span_properties(ddtrace_root_span_data *span) { span->sampling_rule.rule = INT32_MAX; - zend_array *meta = ddtrace_property_array(&span->property_meta); - zend_array *metrics = ddtrace_property_array(&span->property_metrics); - - zend_hash_copy(meta, &DDTRACE_G(root_span_tags_preset), (copy_ctor_func_t)zval_add_ref); + zend_array *attributes = ddtrace_property_array(&span->property_attributes); + zend_hash_copy(attributes, &DDTRACE_G(root_span_tags_preset), (copy_ctor_func_t)zval_add_ref); /* Compilers rightfully complain about array bounds due to the struct * hack if we write straight to the char storage. Saving the char* to a @@ -803,7 +815,7 @@ void ddtrace_set_root_span_properties(ddtrace_root_span_data *span) { zval zv; ZVAL_STR(&zv, encoded_id); - zend_hash_str_add_new(meta, ZEND_STRL("runtime-id"), &zv); + zend_hash_str_update(attributes, ZEND_STRL("runtime-id"), &zv); if (ddtrace_span_is_entrypoint_root(&span->span)) { struct superglob_equiv data = {0}; @@ -827,7 +839,7 @@ void ddtrace_set_root_span_properties(ddtrace_root_span_data *span) { if (ZSTR_LEN(get_DD_HOSTNAME())) { zval hostname_zv; ZVAL_STR_COPY(&hostname_zv, get_DD_HOSTNAME()); - zend_hash_str_add_new(meta, ZEND_STRL("_dd.hostname"), &hostname_zv); + zend_hash_str_update(attributes, ZEND_STRL("_dd.hostname"), &hostname_zv); } else { #ifndef HOST_NAME_MAX @@ -841,7 +853,7 @@ void ddtrace_set_root_span_properties(ddtrace_root_span_data *span) { hostname = zend_string_truncate(hostname, strlen(ZSTR_VAL(hostname)), 0); zval hostname_zv; ZVAL_STR(&hostname_zv, hostname); - zend_hash_str_add_new(meta, ZEND_STRL("_dd.hostname"), &hostname_zv); + zend_hash_str_update(attributes, ZEND_STRL("_dd.hostname"), &hostname_zv); } } } @@ -913,13 +925,6 @@ void ddtrace_set_root_span_properties(ddtrace_root_span_data *span) { DATADOG_G(asm_event_emitted) = false; // we attach this to the first root span after the asm event was detected (if there was none while emitted) } - ddtrace_integration *web_integration = &ddtrace_integrations[DDTRACE_INTEGRATION_WEB]; - if (get_DD_TRACE_ANALYTICS_ENABLED() || web_integration->is_analytics_enabled()) { - zval sample_rate; - ZVAL_DOUBLE(&sample_rate, web_integration->get_sample_rate()); - zend_hash_str_add_new(metrics, ZEND_STRL("_dd1.sr.eausr"), &sample_rate); - } - if (get_DD_TRACE_GIT_METADATA_ENABLED()) { ddtrace_inject_git_metadata(&span->property_git_metadata); } @@ -927,82 +932,395 @@ void ddtrace_set_root_span_properties(ddtrace_root_span_data *span) { zval pid; ZVAL_DOUBLE(&pid, (double)getpid()); - zend_hash_str_add_new(metrics, ZEND_STRL("process_id"), &pid); + zend_hash_str_update(attributes, ZEND_STRL("process_id"), &pid); } -static void dd_serialize_json(zend_array *arr, smart_str *buf, int options) { - zval zv; - ZVAL_ARR(&zv, arr); - zai_json_encode(buf, &zv, options); - smart_str_0(buf); +// Backing array of an array/object value; sets *release when the caller must +// zend_release_properties() afterwards (object properties on PHP >= 7.4). +static zend_array *dd_native_props(zval *value, bool *release) { + *release = false; + if (Z_TYPE_P(value) == IS_OBJECT) { +#if PHP_VERSION_ID >= 70400 + *release = true; + return zend_get_properties_for(value, ZEND_PROP_PURPOSE_JSON); +#else + return Z_OBJPROP_P(value); +#endif + } + return Z_ARR_P(value); } -static void dd_serialize_array_recursively(ddog_SpanBytes *target, zend_string *str, zval *value, bool convert_to_double) { - ZVAL_DEREF(value); - - if (Z_TYPE_P(value) == IS_ARRAY || Z_TYPE_P(value) == IS_OBJECT) { - zend_array *arr; - if (Z_TYPE_P(value) == IS_OBJECT) { +static inline void dd_native_release_props(zend_array *arr, bool release) { #if PHP_VERSION_ID >= 70400 - arr = zend_get_properties_for(value, ZEND_PROP_PURPOSE_JSON); + if (release) { + zend_release_properties(arr); + } #else - arr = Z_OBJPROP_P(value); + (void)arr; (void)release; #endif - } else { - arr = Z_ARR_P(value); +} + +// Immutable arrays (opcache SHM, the empty array) must never be written to and cannot form a cycle. +static inline bool dd_native_is_immutable(zval *value) { + return Z_TYPE_P(value) == IS_ARRAY && (GC_FLAGS(Z_ARR_P(value)) & IS_ARRAY_IMMUTABLE); +} + +// Marks array/object `value` while it is serialized, so Z_IS_RECURSIVE_P detects a reference cycle back +// to it. Objects are marked on the object: get_properties_for may build a fresh table per call (DateTime). +// Mirrors php_var_dump: the value is also held (addref) while being iterated. +static inline void dd_native_protect_recursion(zval *value) { + if (!dd_native_is_immutable(value)) { + Z_ADDREF_P(value); + Z_PROTECT_RECURSION_P(value); + } +} + +static inline void dd_native_unprotect_recursion(zval *value) { + if (!dd_native_is_immutable(value)) { + Z_UNPROTECT_RECURSION_P(value); + GC_DTOR_NO_REF(Z_COUNTED_P(value)); + } +} + +// A packed PHP array nests as a list; any other array, and objects, nest as a map. +static inline bool dd_native_is_list(zval *value) { + return Z_TYPE_P(value) == IS_ARRAY && zend_array_is_list(Z_ARR_P(value)); +} + +// Map member key for `arr` entry (`str_key`, `num_key`): numeric keys as decimal into `numbuf`. +static inline ddog_CharSlice dd_native_member_key(zend_string *str_key, zend_ulong num_key, char numbuf[24]) { + return str_key + ? dd_zend_string_to_CharSlice(str_key) + : (ddog_CharSlice){ .ptr = numbuf, .len = snprintf(numbuf, 24, ZEND_ULONG_FMT, num_key) }; +} + +// Protected and private object members are mangled with a leading NUL byte. +static inline bool dd_native_is_hidden_member(zend_string *str_key) { + return str_key && ZSTR_LEN(str_key) > 0 && ZSTR_VAL(str_key)[0] == '\0'; +} + +// --- Native attributes -------------------------------------------------------------------------- +// +// One emitter fills every attribute map (span, link, event, nested map): scalars keep their PHP type, +// arrays/objects nest as a List/KeyValue (objects as a map of their public properties), and a +// reference cycle becomes the "" leaf. The top-level flags keep each node's v0.4-parity differences. +#define DD_ATTR_TOP (1 << 0) // top-level entry: empty keys are skipped +#define DD_ATTR_NULL_AS_STRING (1 << 1) // null is the "null" string (links, events), not skipped +#define DD_ATTR_EMPTY_ARRAY_AS_STRING (1 << 2) // an empty array is the "" tag (spans: no v0.4 form) +#define DD_ATTR_SCALARS_AS_STRINGS (1 << 3) // scalars are strings (links) + +#define DD_ATTR_SPAN (DD_ATTR_TOP | DD_ATTR_EMPTY_ARRAY_AS_STRING) +#define DD_ATTR_EVENT (DD_ATTR_TOP | DD_ATTR_NULL_AS_STRING) +#define DD_ATTR_LINK (DD_ATTR_TOP | DD_ATTR_NULL_AS_STRING | DD_ATTR_SCALARS_AS_STRINGS) + +static void dd_attr_emit(ddog_Attributes *dest, ddog_CharSlice key, zend_string *zkey, zval *value, int flags); +static void dd_attr_emit_list(ddog_AttrList *dest, zval *value); + +// Builds the list for packed array `value`. +static ddog_AttrList *dd_attr_build_list(zval *value) { + zend_array *arr = Z_ARR_P(value); + ddog_AttrList *list = ddog_attr_list_new(zend_hash_num_elements(arr)); + dd_native_protect_recursion(value); + zval *val; + ZEND_HASH_FOREACH_VAL_IND(arr, val) { + dd_attr_emit_list(list, val); + } ZEND_HASH_FOREACH_END(); + dd_native_unprotect_recursion(value); + return list; +} + +// Builds the map for array/object `value` (numeric keys as decimal, matching PHP's json object keys). +static ddog_AttrMap *dd_attr_build_map(zval *value) { + bool release; + zend_array *arr = dd_native_props(value, &release); + ddog_AttrMap *map = ddog_attr_map_new(zend_hash_num_elements(arr)); + ddog_Attributes *attrs = ddog_attr_map_get_attributes(map); + dd_native_protect_recursion(value); + zval *val; + zend_string *str_key; + zend_ulong num_key; + ZEND_HASH_FOREACH_KEY_VAL_IND(arr, num_key, str_key, val) { + if (!dd_native_is_hidden_member(str_key)) { + char numbuf[24]; + dd_attr_emit(attrs, dd_native_member_key(str_key, num_key, numbuf), NULL, val, 0); + } + } ZEND_HASH_FOREACH_END(); + dd_native_unprotect_recursion(value); + dd_native_release_props(arr, release); + return map; +} + +// String form of a scalar leaf (null -> "null"). +static zend_string *dd_native_typed_str(zval *value) { + return datadog_convert_to_str(value); +} + +// Emits one list element, preserving the PHP scalar type (nested nulls are skipped). +static void dd_attr_emit_list(ddog_AttrList *dest, zval *value) { + ZVAL_DEREF(value); + switch (Z_TYPE_P(value)) { + case IS_ARRAY: + case IS_OBJECT: + if (Z_IS_RECURSIVE_P(value)) { + ddog_attr_list_push_str(dest, DDOG_CHARSLICE_C("")); + } else if (dd_native_is_list(value)) { + ddog_attr_list_push_list(dest, dd_attr_build_list(value)); + } else { + ddog_attr_list_push_map(dest, dd_attr_build_map(value)); + } + break; + case IS_NULL: + break; // V1 has no null value + case IS_TRUE: ddog_attr_list_push_bool(dest, true); break; + case IS_FALSE: ddog_attr_list_push_bool(dest, false); break; + case IS_LONG: ddog_attr_list_push_int(dest, Z_LVAL_P(value)); break; + case IS_DOUBLE: ddog_attr_list_push_double(dest, Z_DVAL_P(value)); break; + default: { + zend_string *str = dd_native_typed_str(value); + ddog_attr_list_push_str(dest, dd_zend_string_to_CharSlice(str)); + zend_string_release(str); + break; + } + } +} + +// ParseBool returns the boolean value represented by the string. +// It accepts 1, t, T, TRUE, true, True, 0, f, F, FALSE, false, False. +// Any other value returns -1. +static zend_always_inline double strconv_parse_bool(zend_string *str) { + // See Go's strconv.ParseBool + // https://cs.opensource.google/go/go/+/refs/tags/go1.21.5:src/strconv/atob.go;drc=1f137052e4a20dbd302f947b1cf34cdf4b427d65;l=10 + size_t len = ZSTR_LEN(str); + if (len == 0) { + return -1; + } + + char *s = ZSTR_VAL(str); + switch (len) { + case 1: + switch (s[0]) { + case '1': + case 't': + case 'T': + return 1; + case '0': + case 'f': + case 'F': + return 0; + } + break; + case 4: + if (strcmp(s, "TRUE") == 0 || strcmp(s, "True") == 0 || strcmp(s, "true") == 0) { + return 1; + } + break; + case 5: + if (strcmp(s, "FALSE") == 0 || strcmp(s, "False") == 0 || strcmp(s, "false") == 0) { + return 0; + } + break; + } + + return -1; +} + +// Emits `value` under `key` into `dest`; `zkey`, when given, is `key` as a zend_string (zero-copy). +static void dd_attr_emit(ddog_Attributes *dest, ddog_CharSlice key, zend_string *zkey, zval *value, int flags) { + if ((flags & DD_ATTR_TOP) && !key.len) { + return; + } + bool as_string = flags & DD_ATTR_SCALARS_AS_STRINGS; + ZVAL_DEREF(value); + switch (Z_TYPE_P(value)) { + case IS_ARRAY: + case IS_OBJECT: + if (Z_IS_RECURSIVE_P(value) + || ((flags & DD_ATTR_EMPTY_ARRAY_AS_STRING) && Z_TYPE_P(value) == IS_ARRAY && !zend_hash_num_elements(Z_ARR_P(value)))) { + ddog_attributes_add_str(dest, key, DDOG_CHARSLICE_C("")); + } else if (dd_native_is_list(value)) { + ddog_attributes_add_list(dest, key, dd_attr_build_list(value)); + } else { + ddog_attributes_add_map(dest, key, dd_attr_build_map(value)); + } + return; + case IS_NULL: + if (!(flags & DD_ATTR_NULL_AS_STRING)) { + return; + } + break; + case IS_TRUE: + case IS_FALSE: + if (!as_string) { + ddog_attributes_add_bool(dest, key, Z_TYPE_P(value) == IS_TRUE); + return; + } + break; + case IS_LONG: + if (!as_string) { + ddog_attributes_add_int(dest, key, Z_LVAL_P(value)); + return; + } + break; + case IS_DOUBLE: + if (!as_string) { + if (zkey) { + ddog_attributes_add_double_zstr(dest, zkey, Z_DVAL_P(value)); + } else { + ddog_attributes_add_double(dest, key, Z_DVAL_P(value)); + } + return; + } + break; + } + zend_string *str = dd_native_typed_str(value); + if (zkey) { + ddog_attributes_add_zstr(dest, zkey, str); + } else { + ddog_attributes_add_str(dest, key, dd_zend_string_to_CharSlice(str)); + } + zend_string_release(str); +} + +// Emit each SpanLink into the V1 builder span, reading from the PHP link objects (scalar attributes +// are strings; dropped_attributes_count has no PHP-side source). +static void dd_span_links_to_rust(zend_array *links, ddog_SpanNode *span) { + zval *val; + ZEND_HASH_FOREACH_VAL(links, val) { + ZVAL_DEREF(val); + if (Z_TYPE_P(val) != IS_OBJECT || !instanceof_function(Z_OBJCE_P(val), ddtrace_ce_span_link)) { + continue; + } + ddtrace_span_link *link = (ddtrace_span_link *)Z_OBJ_P(val); + ddog_SpanLinkBytes *rust_link = ddog_new_link(span); + + zval *tid = &link->property_trace_id; + if (Z_TYPE_P(tid) == IS_STRING) { + datadog_trace_id id = ddtrace_parse_hex_trace_id(Z_STRVAL_P(tid), Z_STRLEN_P(tid)); + ddog_link_set_trace_id(rust_link, id.high, id.low); + } + ddog_link_set_span_id(rust_link, ddtrace_parse_hex_span_id(&link->property_span_id)); + + zval *ts = &link->property_trace_state; + if (Z_TYPE_P(ts) == IS_STRING && Z_STRLEN_P(ts) > 0) { + ddog_link_set_tracestate(rust_link, dd_zend_string_to_CharSlice(Z_STR_P(ts))); + } + + zval *attrs = &link->property_attributes; + ZVAL_DEREF(attrs); + if (Z_TYPE_P(attrs) == IS_ARRAY) { + ddog_Attributes *link_attrs = ddog_link_get_attributes(rust_link); + zend_ulong idx; + zend_string *key; + zval *aval; + ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(attrs), idx, key, aval) { + char numbuf[24]; + dd_attr_emit(link_attrs, dd_native_member_key(key, idx, numbuf), NULL, aval, DD_ATTR_LINK); + } ZEND_HASH_FOREACH_END(); } - if (zend_hash_num_elements(arr) && !GC_IS_RECURSIVE(arr)) { - GC_PROTECT_RECURSION(arr); + } ZEND_HASH_FOREACH_END(); +} + +// Emit each SpanEvent into the V1 builder span, dispatching attributes by type. ExceptionSpanEvent +// flattens exception.message/type/stacktrace as string attributes. +static void dd_span_events_to_rust(zend_array *events, ddog_SpanNode *span) { + zval *val; + ZEND_HASH_FOREACH_VAL(events, val) { + ZVAL_DEREF(val); + if (Z_TYPE_P(val) != IS_OBJECT || !instanceof_function(Z_OBJCE_P(val), ddtrace_ce_span_event)) { + continue; + } + ddtrace_span_event *event = (ddtrace_span_event *)Z_OBJ_P(val); + ddog_SpanEventBytes *rust_event = ddog_new_event(span); + ddog_Attributes *event_attrs = ddog_event_get_attributes(rust_event); + zval *name = &event->property_name; + if (Z_TYPE_P(name) == IS_STRING) { + ddog_event_set_name(rust_event, dd_zend_string_to_CharSlice(Z_STR_P(name))); + } + zval *time = &event->property_timestamp; + ZVAL_DEREF(time); + if (Z_TYPE_P(time) == IS_LONG) { + ddog_event_set_time(rust_event, (uint64_t)Z_LVAL_P(time)); + } + + if (instanceof_function(event->std.ce, ddtrace_ce_exception_span_event)) { + ddtrace_exception_span_event *exc_event = (ddtrace_exception_span_event *)event; + zval *exception = &exc_event->property_exception; + if (Z_TYPE_P(exception) == IS_OBJECT && instanceof_function(Z_OBJCE_P(exception), zend_ce_throwable)) { + zend_string *message = zai_exception_message(Z_OBJ_P(exception)); + if (ZSTR_LEN(message)) { + ddog_attributes_add_str(event_attrs, + DDOG_CHARSLICE_C("exception.message"), dd_zend_string_to_CharSlice(message)); + } + ddog_attributes_add_str(event_attrs, + DDOG_CHARSLICE_C("exception.type"), dd_zend_string_to_CharSlice(Z_OBJCE_P(exception)->name)); + zend_string *stacktrace = zai_get_trace_without_args_from_exception(Z_OBJ_P(exception)); + ddog_attributes_add_str(event_attrs, + DDOG_CHARSLICE_C("exception.stacktrace"), dd_zend_string_to_CharSlice(stacktrace)); + zend_string_release(stacktrace); + } + } + + zval *attrs = &event->property_attributes; + ZVAL_DEREF(attrs); + if (Z_TYPE_P(attrs) == IS_ARRAY) { + zend_ulong idx; + zend_string *key; + zval *aval; + ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(attrs), idx, key, aval) { + char numbuf[24]; + dd_attr_emit(event_attrs, dd_native_member_key(key, idx, numbuf), NULL, aval, DD_ATTR_EVENT); + } ZEND_HASH_FOREACH_END(); + } + } ZEND_HASH_FOREACH_END(); +} + +// Value stored through the $meta/$metrics views: meta leaves become strings, metric leaves doubles, +// and empty or recursive arrays/objects the ""/0.0 placeholder, so the v0.4 wire keeps the old form. +void ddtrace_normalize_tag_value(zval *dst, zval *value, bool metric) { + ZVAL_DEREF(value); + if (Z_TYPE_P(value) == IS_ARRAY || Z_TYPE_P(value) == IS_OBJECT) { + bool release; + zend_array *arr = dd_native_props(value, &release); + if (zend_hash_num_elements(arr) && !Z_IS_RECURSIVE_P(value)) { + bool is_list = dd_native_is_list(value); + array_init_size(dst, zend_hash_num_elements(arr)); + dd_native_protect_recursion(value); zval *val; zend_string *str_key; zend_ulong num_key; ZEND_HASH_FOREACH_KEY_VAL_IND(arr, num_key, str_key, val) { - zend_string *key; - if (str_key) { - if (ZSTR_VAL(str_key)[0] == '\0' && ZSTR_LEN(str_key) > 0) { - // Skip protected and private members - continue; - } - key = zend_strpprintf(0, "%.*s.%.*s", (int)ZSTR_LEN(str), ZSTR_VAL(str), (int)ZSTR_LEN(str_key), ZSTR_VAL(str_key)); + if (dd_native_is_hidden_member(str_key)) { + continue; + } + zval child; + ddtrace_normalize_tag_value(&child, val, metric); + if (is_list) { + zend_hash_next_index_insert_new(Z_ARR_P(dst), &child); + } else if (str_key) { + zend_hash_update(Z_ARR_P(dst), str_key, &child); } else { - key = zend_strpprintf(0, "%.*s." ZEND_LONG_FMT, (int)ZSTR_LEN(str), ZSTR_VAL(str), num_key); + zend_hash_index_update(Z_ARR_P(dst), num_key, &child); } - dd_serialize_array_recursively(target, key, val, convert_to_double); - zend_string_release(key); } ZEND_HASH_FOREACH_END(); - - GC_UNPROTECT_RECURSION(arr); - } else if (convert_to_double) { - ddog_add_span_metrics_zstr(target, str, 0.0); - } else { - ddog_add_zstr_span_meta_str(target, str, ""); + dd_native_unprotect_recursion(value); + dd_native_release_props(arr, release); + return; } - -#if PHP_VERSION_ID >= 70400 - if (Z_TYPE_P(value) == IS_OBJECT) { - zend_release_properties(arr); + dd_native_release_props(arr, release); + if (metric) { + ZVAL_DOUBLE(dst, 0.0); + } else { + ZVAL_EMPTY_STRING(dst); } -#endif - } else if (convert_to_double) { - ddog_add_span_metrics_zstr(target, str, zval_get_double(value)); + } else if (metric) { + ZVAL_DOUBLE(dst, zval_get_double(value)); } else { - zval val_as_string; - datadog_convert_to_string(&val_as_string, value); - ddog_add_span_meta_zstr(target, str, Z_STR_P(&val_as_string)); - zval_ptr_dtor(&val_as_string); + datadog_convert_to_string(dst, value); } } -static void dd_serialize_array_meta_recursively(ddog_SpanBytes *target, zend_string *str, zval *value) { - dd_serialize_array_recursively(target, str, value, false); -} - -static void dd_serialize_array_metrics_recursively(ddog_SpanBytes *target, zend_string *str, zval *value) { - dd_serialize_array_recursively(target, str, value, true); -} - -static void dd_serialize_array_meta_struct_recursively(ddog_SpanBytes *target, zend_string *str, zval *value) { +static void dd_serialize_array_meta_struct_recursively(ddog_SpanNode *target, zend_string *str, zval *value) { char *data; size_t size; @@ -1016,7 +1334,9 @@ static void dd_serialize_array_meta_struct_recursively(ddog_SpanBytes *target, z return; } - ddog_add_zstr_span_meta_struct_CharSlice(target, str, (ddog_CharSlice){.ptr = data, .len = size}); + if (ZSTR_LEN(str)) { + ddog_attributes_add_bytes(ddog_span_get_attributes(target), dd_zend_string_to_CharSlice(str), (ddog_CharSlice){.ptr = data, .len = size}); + } free(data); } @@ -1182,34 +1502,35 @@ static bool dd_is_http_error(int status) { return false; } -static void dd_set_http_error(zend_array *meta, int status, bool ignore_error) { +static void dd_set_http_error(ddtrace_span_data *span, int status, bool ignore_error) { if (status) { + zend_array *attributes = ddtrace_property_array(&span->property_attributes); zend_string *status_str = zend_long_to_str((long)status); zval status_zv; ZVAL_STR(&status_zv, status_str); - zend_hash_str_update(meta, ZEND_STRL("http.status_code"), &status_zv); + zend_hash_str_update(attributes, ZEND_STRL("http.status_code"), &status_zv); // Only check status codes if not ignoring errors - if (!ignore_error && dd_is_http_error(status)) { - zval zv = {0}, *value; - if ((value = zend_hash_str_add(meta, ZEND_STRL("error.type"), &zv))) { - ZVAL_STR(value, zend_string_init(ZEND_STRL("HttpError"), 0)); - } + if (!ignore_error && dd_is_http_error(status) && !ddtrace_span_find_tag(span, ZEND_STRL("error.type"))) { + zval zv; + ZVAL_STR(&zv, zend_string_init(ZEND_STRL("HttpError"), 0)); + zend_hash_str_add_new(attributes, ZEND_STRL("error.type"), &zv); } } } -static void dd_set_entrypoint_root_span_props_end(zend_array *meta, int status, struct iter *headers, bool ignore_error) { - dd_set_http_error(meta, status, ignore_error); +static void dd_set_entrypoint_root_span_props_end(ddtrace_span_data *span, int status, struct iter *headers, bool ignore_error) { + dd_set_http_error(span, status, ignore_error); + zend_array *attributes = ddtrace_property_array(&span->property_attributes); for (zend_string *lowerheader, *headerval; headers->next(headers, &lowerheader, &headerval);) { - dd_add_header_to_meta(meta, "response", lowerheader, headerval); + dd_add_header_to_meta(attributes, "response", lowerheader, headerval); zend_string_release(lowerheader); zend_string_release(headerval); } } -static void dd_set_entrypoint_root_rust_span_props_end(ddog_SpanBytes *span, struct iter *headers) { +static void dd_set_entrypoint_root_rust_span_props_end(ddog_SpanNode *span, struct iter *headers) { for (zend_string *lowerheader, *headerval; headers->next(headers, &lowerheader, &headerval);) { dd_add_header_to_rust_span(span, "response", lowerheader, headerval); zend_string_release(lowerheader); @@ -1217,19 +1538,28 @@ static void dd_set_entrypoint_root_rust_span_props_end(ddog_SpanBytes *span, str } } +// $ignoreError, or the deprecated "error.ignored" tag of a span not yet serialized (serialized spans +// have it folded into the property, see ddtrace_precompute_span). +static bool dd_span_ignores_error(ddtrace_span_data *span) { + if (zend_is_true(&span->property_ignore_error)) { + return true; + } + zval *attr = ddtrace_span_find_tag(span, ZEND_STRL("error.ignored")); + return attr && zend_is_true(attr); +} + static bool should_track_error(zend_object *exception, ddtrace_span_data *span) { if (Z_TYPE(span->property_exception) != IS_OBJECT || Z_OBJ(span->property_exception) != exception) { return true; } zval *zv; - zend_array *meta = ddtrace_property_array(&span->property_meta); // Check if error should be ignored or tracking is disabled - if ((zv = zend_hash_str_find(meta, ZEND_STRL("error.ignored"))) && zend_is_true(zv)) { + if (dd_span_ignores_error(span)) { return false; } - if ((zv = zend_hash_str_find(meta, ZEND_STRL("track_error"))) && !zend_is_true(zv)) { + if ((zv = ddtrace_span_find_tag(span, ZEND_STRL("track_error"))) && !zend_is_true(zv)) { return false; } return true; @@ -1274,88 +1604,49 @@ void ddtrace_shutdown_span_sampling_limiter(void) { zend_hash_destroy(&dd_span_sampling_limiters); } -// ParseBool returns the boolean value represented by the string. -// It accepts 1, t, T, TRUE, true, True, 0, f, F, FALSE, false, False. -// Any other value returns -1. -static zend_always_inline double strconv_parse_bool(zend_string *str) { - // See Go's strconv.ParseBool - // https://cs.opensource.google/go/go/+/refs/tags/go1.21.5:src/strconv/atob.go;drc=1f137052e4a20dbd302f947b1cf34cdf4b427d65;l=10 - size_t len = ZSTR_LEN(str); - if (len == 0) { - return -1; - } - - char *s = ZSTR_VAL(str); - switch (len) { - case 1: - switch (s[0]) { - case '1': - case 't': - case 'T': - return 1; - case '0': - case 'f': - case 'F': - return 0; - } - break; - case 4: - if (strcmp(s, "TRUE") == 0 || strcmp(s, "True") == 0 || strcmp(s, "true") == 0) { - return 1; - } - break; - case 5: - if (strcmp(s, "FALSE") == 0 || strcmp(s, "False") == 0 || strcmp(s, "false") == 0) { - return 0; - } - break; - } - - return -1; -} - -void transfer_meta_data(ddog_SpanBytes *source, ddog_SpanBytes *destination, const char *key, bool delete_source) { - ddog_CharSlice value = ddog_get_span_meta_str(source, key); - if (value.len > 0) { - ddog_add_str_span_meta_CharSlice(destination, key, value); - if (delete_source) { - ddog_del_span_meta_str(source, key); +// DD_ENV/DD_VERSION win, else the root's env/version (DD_TAGS fallback); the hostname is _dd.hostname's. +static void dd_set_payload_fields(ddog_TracerPayloadV1Builder *builder, ddtrace_span_precomputed *pre, zend_array *attributes, zval *git_metadata) { + zend_string *env = ZSTR_LEN(get_DD_ENV()) ? get_DD_ENV() : pre->env; + zend_string *version = ZSTR_LEN(get_DD_VERSION()) ? get_DD_VERSION() : pre->version; + ddog_CharSlice hostname = DDOG_CHARSLICE_C(""); + zval *hostname_zv = zend_hash_str_find(attributes, ZEND_STRL("_dd.hostname")); + if (get_DD_TRACE_REPORT_HOSTNAME() && hostname_zv && Z_TYPE_P(hostname_zv) == IS_STRING) { + hostname = dd_zend_string_to_CharSlice(Z_STR_P(hostname_zv)); + } + ddog_set_payload_metadata(builder, + env ? dd_zend_string_to_CharSlice(env) : DDOG_CHARSLICE_C(""), + version ? dd_zend_string_to_CharSlice(version) : DDOG_CHARSLICE_C(""), + hostname); + + // Only set when git metadata was injected (DD_TRACE_GIT_METADATA_ENABLED). + if (Z_TYPE_P(git_metadata) == IS_OBJECT) { + datadog_git_metadata *metadata = (datadog_git_metadata *)Z_OBJ_P(git_metadata); + ddog_Attributes *payload_attrs = ddog_payload_get_attributes(builder); + if (Z_TYPE(metadata->property_commit) == IS_STRING && Z_STRLEN(metadata->property_commit)) { + ddog_attributes_add_lit(payload_attrs, "_dd.git.commit.sha", dd_zend_string_to_CharSlice(Z_STR(metadata->property_commit))); } - } -} - -void transfer_metrics_data(ddog_SpanBytes *source, ddog_SpanBytes *destination, const char* key, bool delete_source) { - double metric; - if (ddog_get_span_metrics_str(source, key, &metric)) { - ddog_add_span_metrics_str(destination, key, metric); - if (delete_source) { - ddog_del_span_metrics_str(source, key); + if (Z_TYPE(metadata->property_repository) == IS_STRING && Z_STRLEN(metadata->property_repository)) { + ddog_attributes_add_lit(payload_attrs, "_dd.git.repository_url", dd_zend_string_to_CharSlice(Z_STR(metadata->property_repository))); } } } -ddog_SpanBytes *ddtrace_serialize_span_to_rust_span(ddtrace_span_data *span, ddog_TraceBytes *trace, bool p0_trace) { - zend_array *meta = ddtrace_property_array(&span->property_meta); - zend_array *metrics = ddtrace_property_array(&span->property_metrics); +ddog_SpanNode *ddtrace_serialize_span_to_rust_span(ddtrace_span_data *span, ddtrace_serialize_ctx *ctx, bool p0_trace) { + zend_array *attributes = ddtrace_property_array(&span->property_attributes); - // Remap OTel's status code (metric, http.status_code) to DD's status code (meta, http.status_code) - // OTel HTTP semantic conventions < 1.21.0 - zval *http_status_code = zend_hash_str_find(metrics, ZEND_STRL("http.status_code")); - if (http_status_code) { + // http.status_code is a string tag on the wire; a numeric one (e.g. OTel's metric) is converted. + zval *attr_status_code = zend_hash_str_find(attributes, ZEND_STRL("http.status_code")); + if (attr_status_code && Z_TYPE_P(attr_status_code) != IS_STRING) { zval status_code_as_string; - datadog_convert_to_string(&status_code_as_string, http_status_code); - zend_hash_str_update(meta, ZEND_STRL("http.status_code"), &status_code_as_string); - zend_hash_str_del(metrics, ZEND_STRL("http.status_code")); + datadog_convert_to_string(&status_code_as_string, attr_status_code); + zend_hash_str_update(attributes, ZEND_STRL("http.status_code"), &status_code_as_string); } - - // Remap OTel's status code (metric, http.response.status_code) to DD's status code (meta, http.status_code) - // OTel HTTP semantic conventions >= 1.21.0 - zval *http_response_status_code = zend_hash_str_find(metrics, ZEND_STRL("http.response.status_code")); - if (http_response_status_code) { + zval *attr_response_status_code = zend_hash_str_find(attributes, ZEND_STRL("http.response.status_code")); + if (attr_response_status_code && Z_TYPE_P(attr_response_status_code) != IS_STRING) { zval status_code_as_string; - datadog_convert_to_string(&status_code_as_string, http_response_status_code); - zend_hash_str_update(meta, ZEND_STRL("http.status_code"), &status_code_as_string); - zend_hash_str_del(metrics, ZEND_STRL("http.response.status_code")); + datadog_convert_to_string(&status_code_as_string, attr_response_status_code); + zend_hash_str_update(attributes, ZEND_STRL("http.status_code"), &status_code_as_string); + zend_hash_str_del(attributes, ZEND_STRL("http.response.status_code")); } ddtrace_span_precomputed pre; @@ -1381,7 +1672,7 @@ ddog_SpanBytes *ddtrace_serialize_span_to_rust_span(ddtrace_span_data *span, ddo if (datadog_active_sapi == DATADOG_PHP_SAPI_FRANKENPHP && !status) { status = pre.has_exception ? 500 : 200; } - dd_set_http_error(meta, status, pre.ignore_error); + dd_set_http_error(span, status, pre.ignore_error); } ddtrace_span_data *inferred_span = NULL; @@ -1549,15 +1840,22 @@ ddog_SpanBytes *ddtrace_serialize_span_to_rust_span(ddtrace_span_data *span, ddo return NULL; } - uintptr_t rust_span_index = ddog_get_trace_size(trace); - bool is_first_span = rust_span_index == 0; - ddog_SpanBytes *rust_span = ddog_trace_new_span(trace); + // The span is built directly into the native V1 builder chunk; the chunk carries the 128-bit + // trace id (set at creation). + if (ctx->chunk == DD_CHUNK_NONE) { + // dropped_trace is reserved for the agent; the chunk priority carries the sampling decision. + ctx->chunk = ddog_new_chunk(ctx->builder, span->root->trace_id.high, span->root->trace_id.low); + } + bool is_first_span = ddog_chunk_span_count(ctx->chunk) == 0; + ddog_SpanNode *rspan = ddog_new_span(ctx->chunk); + ddog_Attributes *rattrs = ddog_span_get_attributes(rspan); - ddog_set_span_trace_id(rust_span, span->root->trace_id.low); - ddog_set_span_id(rust_span, span->span_id); + ddog_span_set_id(rspan, span->span_id); + uint64_t parent_id_set = 0; + bool has_parent_id = false; if (inferred_span) { - ddog_set_span_parent_id(rust_span, inferred_span->span_id); + parent_id_set = inferred_span->span_id; has_parent_id = true; } else if (span->parent) { // handle dropped spans ddtrace_span_data *parent = SPANDATA(span->parent); // Ensure the parent id is the root span if everything else was dropped @@ -1565,20 +1863,26 @@ ddog_SpanBytes *ddtrace_serialize_span_to_rust_span(ddtrace_span_data *span, ddo parent = SPANDATA(parent->parent); } if (parent) { - ddog_set_span_parent_id(rust_span, parent->span_id); + parent_id_set = parent->span_id; has_parent_id = true; } } else if (is_root_span) { - ddog_set_span_parent_id(rust_span, ROOTSPANDATA(&span->std)->parent_id); + parent_id_set = ROOTSPANDATA(&span->std)->parent_id; has_parent_id = true; } else if (is_inferred_span) { - ddog_set_span_parent_id(rust_span, span->root->parent_id); + parent_id_set = span->root->parent_id; has_parent_id = true; + } + if (has_parent_id) { + ddog_span_set_parent_id(rspan, parent_id_set); } - ddog_set_span_start(rust_span, span->start); - ddog_set_span_duration(rust_span, span->duration); - - if (is_first_span) { - ddog_add_str_span_meta_str(rust_span, "_dd.sdk.otlp_export", "false"); + ddog_span_set_start(rspan, span->start); + ddog_span_set_duration(rspan, span->duration); + // Process tags and the OTLP export marker are TracerPayload attributes (V1 guide), taken from the payload's first trace. + if (is_first_span && !ctx->process_tags_set) { + ctx->process_tags_set = true; + ddog_Attributes *payload_attrs = ddog_payload_get_attributes(ctx->builder); + // v0.4 downgrade puts this on each chunk's first span, as the pre-V1 serializer did. + ddog_attributes_add_lit(payload_attrs, "_dd.sdk.otlp_export", DDOG_CHARSLICE_C("false")); zend_string *process_tags = datadog_process_tags_get_serialized(); if (ZSTR_LEN(process_tags)) { const char *svc_tag_appendix = NULL; @@ -1588,8 +1892,7 @@ ddog_SpanBytes *ddtrace_serialize_span_to_rust_span(ddtrace_span_data *span, ddo if (dd_service && ZSTR_LEN(dd_service)) { svc_tag_appendix = ",svc.user:true"; } else { - zend_array *root_meta = ddtrace_property_array(&span->root->property_meta); - if (!zend_hash_str_exists(root_meta, ZEND_STRL("_dd.svc_src"))) { + if (!ddtrace_span_find_tag(&span->root->span, ZEND_STRL("_dd.svc_src"))) { zend_string *root_svc = datadog_convert_to_str(&span->root->property_service); if (ZSTR_LEN(root_svc)) { normalized_default = ddog_normalize_process_tag_value(dd_zend_string_to_CharSlice(root_svc)); @@ -1608,10 +1911,10 @@ ddog_SpanBytes *ddtrace_serialize_span_to_rust_span(ddtrace_span_data *span, ddo smart_str_appends(&combined, normalized_default); } smart_str_0(&combined); - ddog_add_str_span_meta_zstr(rust_span, "_dd.tags.process", combined.s); + ddog_attributes_add_lit(payload_attrs, "_dd.tags.process", dd_zend_string_to_CharSlice(combined.s)); smart_str_free(&combined); } else { - ddog_add_str_span_meta_zstr(rust_span, "_dd.tags.process", process_tags); + ddog_attributes_add_lit(payload_attrs, "_dd.tags.process", dd_zend_string_to_CharSlice(process_tags)); } if (normalized_default) { @@ -1622,121 +1925,176 @@ ddog_SpanBytes *ddtrace_serialize_span_to_rust_span(ddtrace_span_data *span, ddo // SpanData::$name defaults to fully qualified called name (set at span close) if (pre.name) { - ddog_set_span_name_zstr(rust_span, pre.name); + ddog_set_span_name_zstr(rspan, pre.name); } if (pre.name_from_meta) { - zend_hash_str_del(meta, ZEND_STRL("operation.name")); + zend_hash_str_del(attributes, ZEND_STRL("operation.name")); } // SpanData::$resource defaults to SpanData::$name if (pre.resource) { - ddog_set_span_resource_zstr(rust_span, pre.resource); + ddog_set_span_resource_zstr(rspan, pre.resource); } if (pre.resource_from_meta) { - zend_hash_str_del(meta, ZEND_STRL("resource.name")); + zend_hash_str_del(attributes, ZEND_STRL("resource.name")); } // TODO: SpanData::$service defaults to parent SpanData::$service or DD_SERVICE if root span if (pre.service) { - ddog_set_span_service_zstr(rust_span, pre.service); + ddog_set_span_service_zstr(rspan, pre.service); } if (pre.service_from_meta) { - zend_hash_str_del(meta, ZEND_STRL("service.name")); + zend_hash_str_del(attributes, ZEND_STRL("service.name")); } // SpanData::$type is optional and defaults to 'custom' at the Agent level if (pre.type) { - ddog_set_span_type_zstr(rust_span, pre.type); + ddog_set_span_type_zstr(rspan, pre.type); } if (pre.type_from_meta) { - zend_hash_str_del(meta, ZEND_STRL("span.type")); + zend_hash_str_del(attributes, ZEND_STRL("span.type")); } - zval *analytics_event = zend_hash_str_find(meta, ZEND_STRL("analytics.event")); + // analytics.event maps to _dd1.sr.eausr (a valid value wins over a set _dd1.sr.eausr). + zval *analytics_event = zend_hash_str_find(attributes, ZEND_STRL("analytics.event")); if (analytics_event) { - if (Z_TYPE_P(analytics_event) == IS_STRING) { - double parsed_analytics_event = strconv_parse_bool(Z_STR_P(analytics_event)); - if (parsed_analytics_event >= 0) { - ddog_add_span_metrics_str(rust_span, "_dd1.sr.eausr", parsed_analytics_event); - } - } else { - ddog_add_span_metrics_str(rust_span, "_dd1.sr.eausr", zval_get_double(analytics_event)); + ZVAL_DEREF(analytics_event); + double parsed_analytics_event = Z_TYPE_P(analytics_event) == IS_STRING + ? strconv_parse_bool(Z_STR_P(analytics_event)) + : zval_get_double(analytics_event); + if (Z_TYPE_P(analytics_event) != IS_STRING || parsed_analytics_event >= 0) { + zend_hash_str_del(attributes, ZEND_STRL("_dd1.sr.eausr")); + ddog_attributes_add_double_lit(rattrs, "_dd1.sr.eausr", parsed_analytics_event); } - zend_hash_str_del(meta, ZEND_STRL("analytics.event")); + zend_hash_str_del(attributes, ZEND_STRL("analytics.event")); } if (span_sampling_applied) { - ddog_add_span_metrics_str(rust_span, "_dd.span_sampling.mechanism", 8.0); - ddog_add_span_metrics_str(rust_span, "_dd.span_sampling.rule_rate", span_sampling_rate); + ddog_attributes_add_double_lit(rattrs, "_dd.span_sampling.mechanism", 8.0); + ddog_attributes_add_double_lit(rattrs, "_dd.span_sampling.rule_rate", span_sampling_rate); if (span_sampling_has_max) { - ddog_add_span_metrics_str(rust_span, "_dd.span_sampling.max_per_second", span_sampling_max_per_second); + ddog_attributes_add_double_lit(rattrs, "_dd.span_sampling.max_per_second", span_sampling_max_per_second); } } - if (meta) { - zend_string *meta_str_key; - zval *orig_val; - ZEND_HASH_FOREACH_STR_KEY_VAL_IND(meta, meta_str_key, orig_val) { - if (meta_str_key) { - if (!ddog_has_span_meta_zstr(rust_span, meta_str_key)) { - dd_serialize_array_meta_recursively(rust_span, meta_str_key, orig_val); - } - } + // Promote span/chunk fields up front (their tags are deleted below). env/version are property-first + // with a tag fallback: DD_TAGS "env"/"version" are plain tags when DD_ENV/DD_VERSION are unset. + // pre.env/pre.version already carry that fallback. + if (pre.env) { + ddog_set_span_env(rspan, dd_zend_string_to_CharSlice(pre.env)); + } + if (pre.version) { + ddog_set_span_version(rspan, dd_zend_string_to_CharSlice(pre.version)); + } + + zval *component_prop = &span->property_component; + ZVAL_DEREF(component_prop); + if (Z_TYPE_P(component_prop) == IS_STRING && Z_STRLEN_P(component_prop) > 0) { + ddog_set_span_component(rspan, dd_zend_string_to_CharSlice(Z_STR_P(component_prop))); + } else { + zval *component_meta = zend_hash_str_find(attributes, ZEND_STRL("component")); + if (component_meta && Z_TYPE_P(component_meta) == IS_STRING) { + ddog_set_span_component(rspan, dd_zend_string_to_CharSlice(Z_STR_P(component_meta))); } - ZEND_HASH_FOREACH_END(); } - // Avoid adding it twice to meta - if (!pre.env_deprecated && pre.env) { - ddog_add_str_span_meta_zstr(rust_span, "env", pre.env); + zval *span_kind_prop = &span->property_span_kind; + ZVAL_DEREF(span_kind_prop); + // Non-canonical span.kind strings (e.g. "process") leave the kind unspecified; + // keep them as a plain attribute instead of deleting below. + bool span_kind_is_canonical = true; + if (Z_TYPE_P(span_kind_prop) == IS_LONG && Z_LVAL_P(span_kind_prop) >= 1 && Z_LVAL_P(span_kind_prop) <= 5) { + ddog_set_span_kind(rspan, (uint32_t)Z_LVAL_P(span_kind_prop)); + } else { + zval *span_kind_meta = zend_hash_str_find(attributes, ZEND_STRL("span.kind")); + if (span_kind_meta && Z_TYPE_P(span_kind_meta) == IS_STRING) { + span_kind_is_canonical = ddog_set_span_kind_str(rspan, dd_zend_string_to_CharSlice(Z_STR_P(span_kind_meta))); + } } - if (!pre.version_deprecated && pre.version) { - ddog_add_str_span_meta_zstr(rust_span, "version", pre.version); + + // _dd.origin is property-sourced; the chunk carries it (never a span attribute). + zval *origin = &span->root->property_origin; + if (Z_TYPE_P(origin) > IS_NULL && (Z_TYPE_P(origin) != IS_STRING || Z_STRLEN_P(origin))) { + ddog_set_chunk_origin(ctx->chunk, dd_zend_string_to_CharSlice(Z_STR_P(origin))); + } + + { + // _dd.p.dm is "-N" (legacy "-N"): the mechanism is the digits after the last '-'. + // Unparseable values leave the chunk field unset rather than claiming mechanism 0. + zval *dm_meta = zend_hash_str_find(attributes, ZEND_STRL("_dd.p.dm")); + if (dm_meta && Z_TYPE_P(dm_meta) == IS_STRING) { + const char *dash = zend_memrchr(Z_STRVAL_P(dm_meta), '-', Z_STRLEN_P(dm_meta)); + const char *p = dash ? dash + 1 : Z_STRVAL_P(dm_meta); + const char *end = Z_STRVAL_P(dm_meta) + Z_STRLEN_P(dm_meta); + uint64_t mech = 0; + bool valid = p < end; + for (; valid && p < end; p++) { + valid = *p >= '0' && *p <= '9' && (mech = mech * 10 + (uint64_t)(*p - '0')) <= UINT32_MAX; + } + if (valid) { + ddog_set_chunk_sampling_mechanism(ctx->chunk, (uint32_t)mech); + } + } + // Delete promoted keys so the copy loop only carries plain attributes. + zend_hash_str_del(attributes, ZEND_STRL("env")); + zend_hash_str_del(attributes, ZEND_STRL("version")); + zend_hash_str_del(attributes, ZEND_STRL("component")); + if (span_kind_is_canonical) { + zend_hash_str_del(attributes, ZEND_STRL("span.kind")); + } + zend_hash_str_del(attributes, ZEND_STRL("_dd.origin")); + zend_hash_str_del(attributes, ZEND_STRL("_dd.p.dm")); + // _sampling_priority_v1 becomes the chunk sampling priority below. + zend_hash_str_del(attributes, ZEND_STRL("_sampling_priority_v1")); } + // $attributes is the single tag store ($meta/$metrics are views onto it). + zend_string *attr_str_key; + zval *attr_val; + ZEND_HASH_FOREACH_STR_KEY_VAL_IND(attributes, attr_str_key, attr_val) { + if (attr_str_key) { + dd_attr_emit(rattrs, dd_zend_string_to_CharSlice(attr_str_key), attr_str_key, attr_val, DD_ATTR_SPAN); + } + } ZEND_HASH_FOREACH_END(); + zval *exception_zv = &span->property_exception; if (pre.has_exception && !pre.ignore_error) { enum dd_exception exception_type = DD_EXCEPTION_THROWN; if (is_root_span) { exception_type = Z_PROP_FLAG_P(exception_zv) == 2 ? DD_EXCEPTION_CAUGHT : DD_EXCEPTION_UNCAUGHT; } - ddtrace_exception_to_meta(Z_OBJ_P(exception_zv), pre.service ? pre.service : ZSTR_EMPTY_ALLOC(), span->start, rust_span, exception_type); + ddtrace_exception_to_meta(Z_OBJ_P(exception_zv), pre.service ? pre.service : ZSTR_EMPTY_ALLOC(), span->start, rspan, exception_type); } + // Links/events are emitted natively from the PHP span (the _dd.span_links/events meta keys are + // never produced on the V1 path). zend_array *span_links = ddtrace_property_array(&span->property_links); if (zend_hash_num_elements(span_links) > 0) { - zend_object *current_exception = EG(exception); - EG(exception) = NULL; - smart_str buf = {0}; - dd_serialize_json(span_links, &buf, 0); - ddog_add_str_span_meta_zstr(rust_span, "_dd.span_links", buf.s); - smart_str_free(&buf); - EG(exception) = current_exception; + dd_span_links_to_rust(span_links, rspan); } zend_array *span_events = ddtrace_property_array(&span->property_events); if (zend_hash_num_elements(span_events) > 0) { - zend_object *current_exception = EG(exception); - EG(exception) = NULL; - smart_str buf = {0}; - dd_serialize_json(span_events, &buf, 0); - ddog_add_str_span_meta_zstr(rust_span, "events", buf.s); - smart_str_free(&buf); - EG(exception) = current_exception; + dd_span_events_to_rust(span_events, rspan); } zval *git_metadata = &span->root->property_git_metadata; + // Payload env/app_version/hostname/git come from the payload's first root span, as the v0.4 agent read them. + if (is_root_span && !ctx->payload_fields_set) { + ctx->payload_fields_set = true; + dd_set_payload_fields(ctx->builder, &pre, attributes, git_metadata); + } if (git_metadata && Z_TYPE_P(git_metadata) == IS_OBJECT) { datadog_git_metadata *metadata = (datadog_git_metadata *)Z_OBJ_P(git_metadata); if (is_root_span) { if (Z_TYPE(metadata->property_commit) == IS_STRING) { zend_string *commit_sha = datadog_convert_to_str(&metadata->property_commit); - ddog_add_str_span_meta_zstr(rust_span, "_dd.git.commit.sha", commit_sha); + dd_span_attr_zstr(rspan, "_dd.git.commit.sha", commit_sha); zend_string_release(commit_sha); } if (Z_TYPE(metadata->property_repository) == IS_STRING) { zend_string *repository_url = datadog_convert_to_str(&metadata->property_repository); - ddog_add_str_span_meta_zstr(rust_span, "_dd.git.repository_url", repository_url); + dd_span_attr_zstr(rspan, "_dd.git.repository_url", repository_url); zend_string_release(repository_url); } } @@ -1744,20 +2102,20 @@ ddog_SpanBytes *ddtrace_serialize_span_to_rust_span(ddtrace_span_data *span, ddo if (get_DD_TRACE_PEER_SERVICE_DEFAULTS_ENABLED()) { zend_array *peer_service_sources = ddtrace_property_array(&span->property_peer_service_sources); - zval *peer_service_tag = meta ? zend_hash_str_find(meta, ZEND_STRL("peer.service")) : NULL; + zval *peer_service_tag = zend_hash_str_find(attributes, ZEND_STRL("peer.service")); if (peer_service_tag && Z_TYPE_P(peer_service_tag) == IS_STRING) { - ddog_add_str_span_meta_str(rust_span, "_dd.peer.service.source", "peer.service"); - dd_set_mapped_peer_service(rust_span, Z_STR_P(peer_service_tag)); + dd_span_attr_str(rspan, "_dd.peer.service.source", "peer.service"); + dd_set_mapped_peer_service(rspan, Z_STR_P(peer_service_tag)); } else if (zend_hash_num_elements(peer_service_sources) > 0) { zval *tag; ZEND_HASH_FOREACH_VAL(peer_service_sources, tag) { if (Z_TYPE_P(tag) == IS_STRING) { - zval *found_peer_service = meta ? zend_hash_find(meta, Z_STR_P(tag)) : NULL; + zval *found_peer_service = zend_hash_find(attributes, Z_STR_P(tag)); if (found_peer_service && Z_TYPE_P(found_peer_service) == IS_STRING) { - ddog_add_str_span_meta_zstr(rust_span, "_dd.peer.service.source", Z_STR_P(tag)); + dd_span_attr_zstr(rspan, "_dd.peer.service.source", Z_STR_P(tag)); zend_string *peer = zval_get_string(found_peer_service); - if (!dd_set_mapped_peer_service(rust_span, peer)) { - ddog_add_str_span_meta_zstr(rust_span, "peer.service", peer); + if (!dd_set_mapped_peer_service(rspan, peer)) { + dd_span_attr_zstr(rspan, "peer.service", peer); } zend_string_release(peer); break; @@ -1769,18 +2127,13 @@ ddog_SpanBytes *ddtrace_serialize_span_to_rust_span(ddtrace_span_data *span, ddo if (ddtrace_span_is_entrypoint_root(span) || is_inferred_span) { struct iter *headers = dd_iterate_sapi_headers(); - dd_set_entrypoint_root_rust_span_props_end(rust_span, headers); + dd_set_entrypoint_root_rust_span_props_end(rspan, headers); efree(headers); } - zval *origin = &span->root->property_origin; - if (Z_TYPE_P(origin) > IS_NULL && (Z_TYPE_P(origin) != IS_STRING || Z_STRLEN_P(origin))) { - ddog_add_str_span_meta_zstr(rust_span, "_dd.origin", Z_STR_P(origin)); - } - bool error = dd_compute_span_is_error(&pre); if (error) { - ddog_set_span_error(rust_span, 1); + ddog_span_set_error(rspan, true); if (Z_TYPE(span->property_exception) == IS_OBJECT) { zend_object *exception = Z_OBJ(span->property_exception); ddtrace_span_data *current = span; @@ -1788,7 +2141,7 @@ ddog_SpanBytes *ddtrace_serialize_span_to_rust_span(ddtrace_span_data *span, ddo do { should_track = should_track_error(exception, current); if (!should_track) { - ddog_add_str_span_meta_str(rust_span, "track_error", "false"); + dd_span_attr_str(rspan, "track_error", "false"); break; } current = current->parent ? SPANDATA(current->parent) : NULL; @@ -1796,12 +2149,6 @@ ddog_SpanBytes *ddtrace_serialize_span_to_rust_span(ddtrace_span_data *span, ddo } } - if (is_inferred_span || (span->root->trace_id.high && is_root_span && !inferred_span)) { - zend_string *trace_id_str = zend_strpprintf(0, "%" PRIx64, span->root->trace_id.high); - ddog_add_str_span_meta_zstr(rust_span, "_dd.p.tid", trace_id_str); - zend_string_release(trace_id_str); - } - // Add _dd.base_service if service name differs from mapped root service name. zval prop_service_as_string; datadog_convert_to_string(&prop_service_as_string, &span->property_service); @@ -1813,7 +2160,7 @@ ddog_SpanBytes *ddtrace_serialize_span_to_rust_span(ddtrace_span_data *span, ddo ZVAL_COPY(&prop_root_service_as_string, new_root_name); } if (!is_inferred_span && !zend_string_equals_ci(Z_STR(prop_service_as_string), Z_STR(prop_root_service_as_string))) { - ddog_add_str_span_meta_zstr(rust_span, "_dd.base_service", Z_STR_P(&prop_root_service_as_string)); + dd_span_attr_zstr(rspan, "_dd.base_service", Z_STR_P(&prop_root_service_as_string)); } zend_string_release(Z_STR(prop_root_service_as_string)); zend_string_release(Z_STR(prop_service_as_string)); @@ -1822,29 +2169,24 @@ ddog_SpanBytes *ddtrace_serialize_span_to_rust_span(ddtrace_span_data *span, ddo ddtrace_feed_span_to_concentrator(span, &pre); } - zend_string *str_key; - zval *val; - ZEND_HASH_FOREACH_STR_KEY_VAL_IND(metrics, str_key, val) { - if (str_key && !ddog_has_span_metrics_zstr(rust_span, str_key)) { - dd_serialize_array_metrics_recursively(rust_span, str_key, val); - } - } ZEND_HASH_FOREACH_END(); + // _sampling_priority_v1 is a chunk-level field, not a span metric. if ((is_root_span && !inferred_span) || is_inferred_span) { if (Z_TYPE_P(&span->root->property_sampling_priority) != IS_UNDEF) { long sampling_priority = zval_get_long(&span->root->property_sampling_priority); - if (!get_global_DD_APM_TRACING_ENABLED() && !ddtrace_trace_source_is_meta_asm_sourced(meta)) { + if (!get_global_DD_APM_TRACING_ENABLED() && !ddtrace_trace_source_is_meta_asm_sourced(attributes)) { sampling_priority = MIN(PRIORITY_SAMPLING_AUTO_KEEP, sampling_priority); } - ddog_add_span_metrics_str(rust_span, "_sampling_priority_v1", sampling_priority); + ddog_set_chunk_sampling_priority(ctx->chunk, (int32_t)sampling_priority); } } if (!get_global_DD_APM_TRACING_ENABLED()) { - ddog_add_span_metrics_str(rust_span, "_dd.apm.enabled", 0); + ddog_attributes_add_double_lit(rattrs, "_dd.apm.enabled", 0); } - if (DATADOG_G(sidecar) && get_DD_TRACE_STATS_COMPUTATION_ENABLED() && !is_inferred_span) { + // Top-level as the agent defines it: a local root, or a span whose service differs from its parent's. + if (ctx->mark_top_level || (DATADOG_G(sidecar) && get_DD_TRACE_STATS_COMPUTATION_ENABLED() && !is_inferred_span)) { bool is_top_level_span = !span->parent; if (span->parent) { zval *parent_service = &SPANDATA(span->parent)->property_service; @@ -1858,44 +2200,43 @@ ddog_SpanBytes *ddtrace_serialize_span_to_rust_span(ddtrace_span_data *span, ddo } } if (is_top_level_span) { - ddog_add_span_metrics_str(rust_span, "_dd.top_level", 1); + ddog_attributes_add_double_lit(rattrs, "_dd.top_level", 1); } } if (ddtrace_span_is_entrypoint_root(span)) { if (get_DD_TRACE_MEASURE_COMPILE_TIME()) { - ddog_add_span_metrics_str(rust_span, "php.compilation.total_time_ms", ddtrace_compile_time_get() / 1000.); + ddog_attributes_add_double_lit(rattrs, "php.compilation.total_time_ms", ddtrace_compile_time_get() / 1000.); } if (get_DD_TRACE_MEASURE_PEAK_MEMORY_USAGE()) { - ddog_add_span_metrics_str(rust_span, "php.memory.peak_usage_bytes", zend_memory_peak_usage(false)); - ddog_add_span_metrics_str(rust_span, "php.memory.peak_real_usage_bytes", zend_memory_peak_usage(true)); + ddog_attributes_add_double_lit(rattrs, "php.memory.peak_usage_bytes", zend_memory_peak_usage(false)); + ddog_attributes_add_double_lit(rattrs, "php.memory.peak_real_usage_bytes", zend_memory_peak_usage(true)); } } - if (inferred_span) { - ddog_SpanBytes *serialized_inferred_span = ddtrace_serialize_span_to_rust_span(inferred_span, trace, p0_trace); - rust_span = ddog_get_span(trace, rust_span_index); - - transfer_metrics_data(rust_span, serialized_inferred_span, "_dd.agent_psr", true); - transfer_metrics_data(rust_span, serialized_inferred_span, "_dd.rule_psr", true); - transfer_metrics_data(rust_span, serialized_inferred_span, "_dd.limit_psr", true); + ddog_SpanNode *inferred = inferred_span ? ddtrace_serialize_span_to_rust_span(inferred_span, ctx, p0_trace) : NULL; + // A dropped inferred span returns NULL; skip the transfers then. Node pointers stay valid across + // sibling pushes, so rspan is still usable after the inferred span was added to the chunk. + if (inferred) { + ddog_transfer_span_attr(rspan, inferred, "_dd.agent_psr", true); + ddog_transfer_span_attr(rspan, inferred, "_dd.rule_psr", true); + ddog_transfer_span_attr(rspan, inferred, "_dd.limit_psr", true); - transfer_meta_data(rust_span, serialized_inferred_span, "error.message", false); - transfer_meta_data(rust_span, serialized_inferred_span, "error.type", false); - transfer_meta_data(rust_span, serialized_inferred_span, "error.stack", false); - transfer_meta_data(rust_span, serialized_inferred_span, "track_error", false); - transfer_meta_data(rust_span, serialized_inferred_span, "_dd.p.dm", true); - transfer_meta_data(rust_span, serialized_inferred_span, "_dd.p.ksr", false); - transfer_meta_data(rust_span, serialized_inferred_span, "_dd.p.tid", true); - transfer_meta_data(rust_span, serialized_inferred_span, "_dd.svc_src", false); - transfer_meta_data(rust_span, serialized_inferred_span, DD_TAG_HTTP_REQH_ENDPOINT_SCAN, false); - transfer_meta_data(rust_span, serialized_inferred_span, DD_TAG_HTTP_REQH_SECURITY_TEST, false); + ddog_transfer_span_attr(rspan, inferred, "error.message", false); + ddog_transfer_span_attr(rspan, inferred, "error.type", false); + ddog_transfer_span_attr(rspan, inferred, "error.stack", false); + ddog_transfer_span_attr(rspan, inferred, "track_error", false); + ddog_transfer_span_attr(rspan, inferred, "_dd.p.dm", true); + ddog_transfer_span_attr(rspan, inferred, "_dd.p.ksr", false); + ddog_transfer_span_attr(rspan, inferred, "_dd.svc_src", false); + ddog_transfer_span_attr(rspan, inferred, DD_TAG_HTTP_REQH_ENDPOINT_SCAN, false); + ddog_transfer_span_attr(rspan, inferred, DD_TAG_HTTP_REQH_SECURITY_TEST, false); - ddog_set_span_error(serialized_inferred_span, ddog_get_span_error(rust_span)); + ddog_span_set_error(inferred, ddog_span_get_error(rspan)); } LOGEV(SPAN, { - ddog_CharSlice span_log = ddog_span_debug_log(rust_span); + ddog_CharSlice span_log = ddog_v1_span_debug_log(ctx->chunk, rspan); log("Encoding span: %s", span_log.ptr); ddog_free_charslice(span_log); }); @@ -1905,123 +2246,226 @@ ddog_SpanBytes *ddtrace_serialize_span_to_rust_span(ddtrace_span_data *span, ddo zval *ms_val; ZEND_HASH_FOREACH_STR_KEY_VAL_IND(meta_struct, ms_str_key, ms_val) { if (ms_str_key) { - dd_serialize_array_meta_struct_recursively(rust_span, ms_str_key, ms_val); + dd_serialize_array_meta_struct_recursively(rspan, ms_str_key, ms_val); } } ZEND_HASH_FOREACH_END(); - ddog_del_span_meta_str(rust_span, "error.ignored"); - ddtrace_free_span_precomputed(&pre); - return rust_span; + return rspan; } -zval dd_serialize_rust_traces_to_zval(ddog_TracesBytes *traces) { +// Reads a native V1 attribute value into a zval, recursing into List/KeyValue so nested attributes +// surface as nested PHP arrays (a list becomes a packed array, a KeyValue an assoc map). +static void dd_attr_value_to_zval(const ddog_AttrValue *value, zval *out) { + switch (ddog_v1_value_type(value)) { + case ddog_DDOG_V1_ATTR_INT: + ZVAL_LONG(out, ddog_v1_value_int(value)); + break; + case ddog_DDOG_V1_ATTR_DOUBLE: + ZVAL_DOUBLE(out, ddog_v1_value_double(value)); + break; + case ddog_DDOG_V1_ATTR_BOOL: + ZVAL_BOOL(out, ddog_v1_value_bool(value)); + break; + case ddog_DDOG_V1_ATTR_BYTES: + ZVAL_STR(out, dd_CharSlice_to_zend_string(ddog_v1_value_bytes(value))); + break; + case ddog_DDOG_V1_ATTR_LIST: { + array_init(out); + size_t n = ddog_v1_value_list_len(value); + for (size_t i = 0; i < n; i++) { + zval v; + dd_attr_value_to_zval(ddog_v1_value_list_get(value, i), &v); + add_next_index_zval(out, &v); + } + break; + } + case ddog_DDOG_V1_ATTR_KEYVALUE: { + array_init(out); + const ddog_Attributes *members = ddog_v1_value_map(value); + size_t n = ddog_v1_attributes_len(members); + for (size_t i = 0; i < n; i++) { + ddog_CharSlice mkey = ddog_v1_attributes_key(members, i); + zval v; + dd_attr_value_to_zval(ddog_v1_attributes_value(members, i), &v); + // Symtable insert: a numeric member name ("0") becomes an integer key again. + add_assoc_zval_ex(out, dd_CharSlice_ptr(mkey), mkey.len, &v); + } + break; + } + default: // STRING + ZVAL_STR(out, dd_CharSlice_to_zend_string(ddog_v1_value_str(value))); + break; + } +} + +// Reads an attribute map into the `out` array. With `bytes_out`, Bytes values go +// there instead (v0.4 meta_struct entries). A repeated key keeps its last write, as on the wire. +static void dd_attributes_to_zval(const ddog_Attributes *attrs, zval *out, zval *bytes_out) { + size_t n = ddog_v1_attributes_len(attrs); + for (size_t i = 0; i < n; i++) { + ddog_CharSlice key = ddog_v1_attributes_key(attrs, i); + const ddog_AttrValue *value = ddog_v1_attributes_value(attrs, i); + zval v; + dd_attr_value_to_zval(value, &v); + zval *target = bytes_out && ddog_v1_value_type(value) == ddog_DDOG_V1_ATTR_BYTES ? bytes_out : out; + zend_hash_str_update(Z_ARR_P(target), dd_CharSlice_ptr(key), key.len, &v); + } +} + +// Adds `arr` under `key` if it's non-empty, else frees it. +static void dd_add_assoc_nonempty(zval *parent, const char *key, zval *arr) { + if (zend_hash_num_elements(Z_ARR_P(arr))) { + add_assoc_zval(parent, key, arr); + } else { + zval_ptr_dtor(arr); + } +} + +// Introspection reader for the native V1 builder: promoted and chunk-level fields are surfaced +// directly, the unified typed attribute map under "attributes", and links/events natively. +zval dd_serialize_rust_to_zval(ddog_TracerPayloadV1Builder *b) { + // The payload's process tags and OTLP export marker show on each chunk's first span, as on the v0.4 wire. + const ddog_AttrValue *process_tags_value = ddog_v1_attributes_get(ddog_payload_get_attributes(b), DDOG_CHARSLICE_C("_dd.tags.process")); + ddog_CharSlice process_tags = process_tags_value ? ddog_v1_value_str(process_tags_value) : (ddog_CharSlice){0}; + const ddog_AttrValue *otlp_export_value = ddog_v1_attributes_get(ddog_payload_get_attributes(b), DDOG_CHARSLICE_C("_dd.sdk.otlp_export")); + ddog_CharSlice otlp_export = otlp_export_value ? ddog_v1_value_str(otlp_export_value) : (ddog_CharSlice){0}; zval traces_zv; array_init(&traces_zv); - for (size_t i = 0; i < ddog_get_traces_size(traces); i++) { - ddog_TraceBytes *trace = ddog_get_trace(traces, i); + size_t chunk_count; + ddog_ChunkNode *const *chunks = ddog_v1_get_chunks(b, &chunk_count); + for (size_t c = 0; c < chunk_count; c++) { + const ddog_ChunkNode *chunk = chunks[c]; zval trace_zv; array_init(&trace_zv); - for (size_t j = 0; j < ddog_get_trace_size(trace); j++) { - ddog_SpanBytes *span = ddog_get_span(trace, j); + uint64_t tid_high = ddog_v1_get_chunk_trace_id_high(chunk); + uint64_t tid_low = ddog_v1_get_chunk_trace_id_low(chunk); + // Chunk-level fields go on the chunk's local root only, the same span the v0.4 wire picks. + const ddog_SpanNode *root = ddog_v1_get_chunk_root_span(chunk); + int32_t chunk_priority; + bool has_priority = ddog_v1_get_chunk_sampling_priority(chunk, &chunk_priority); + uint32_t chunk_mechanism; + bool has_mechanism = ddog_v1_get_chunk_sampling_mechanism(chunk, &chunk_mechanism); + ddog_CharSlice chunk_origin = ddog_v1_get_chunk_origin(chunk); + + size_t span_count; + ddog_SpanNode *const *spans = ddog_v1_get_spans(chunk, &span_count); + for (size_t j = 0; j < span_count; j++) { + ddog_SpanNode *span = spans[j]; + bool is_root = span == root; zval span_zv; array_init(&span_zv); - add_assoc_str(&span_zv, KEY_TRACE_ID, ddtrace_span_id_as_string(ddog_get_span_trace_id(span))); - add_assoc_str(&span_zv, KEY_SPAN_ID, ddtrace_span_id_as_string(ddog_get_span_id(span))); - - size_t span_parent_id = ddog_get_span_parent_id(span); - if (span_parent_id) { - add_assoc_str(&span_zv, KEY_PARENT_ID, ddtrace_span_id_as_string(span_parent_id)); + add_assoc_str(&span_zv, KEY_TRACE_ID, ddtrace_span_id_as_string(tid_low)); + if (tid_high && is_root) { + add_assoc_str(&span_zv, "trace_id_high", ddtrace_span_id_as_hex_string(tid_high)); } - - add_assoc_long(&span_zv, "start", ddog_get_span_start(span)); - add_assoc_long(&span_zv, "duration", ddog_get_span_duration(span)); - - ddog_CharSlice name = ddog_get_span_name(span); - add_assoc_str(&span_zv, "name", dd_CharSlice_to_zend_string(name)); - - ddog_CharSlice resource = ddog_get_span_resource(span); - add_assoc_str(&span_zv, "resource", dd_CharSlice_to_zend_string(resource)); - - ddog_CharSlice service = ddog_get_span_service(span); - add_assoc_str(&span_zv, "service", dd_CharSlice_to_zend_string(service)); - - ddog_CharSlice type = ddog_get_span_type(span); - add_assoc_str(&span_zv, "type", dd_CharSlice_to_zend_string(type)); - - double error = ddog_get_span_error(span); - if (error != 0) { - add_assoc_long(&span_zv, "error", error); + add_assoc_str(&span_zv, KEY_SPAN_ID, ddtrace_span_id_as_string(ddog_v1_get_span_id(span))); + uint64_t parent_id = ddog_v1_get_span_parent_id(span); + if (parent_id) { + add_assoc_str(&span_zv, KEY_PARENT_ID, ddtrace_span_id_as_string(parent_id)); } - - size_t meta_count = 0; - ddog_CharSlice *meta_keys = ddog_span_meta_get_keys(span, &meta_count); - - if (meta_count > 0) { - zval meta_zv; - array_init(&meta_zv); - - for (size_t k = 0; k < meta_count; k++) { - ddog_CharSlice key = meta_keys[k]; - ddog_CharSlice value = ddog_get_span_meta(span, key); - - zval value_zv; - ZVAL_STR(&value_zv, dd_CharSlice_to_zend_string(value)); - zend_hash_str_update(Z_ARR(meta_zv), key.ptr, key.len, &value_zv); - } - - add_assoc_zval(&span_zv, "meta", &meta_zv); + add_assoc_long(&span_zv, "start", ddog_v1_get_span_start(span)); + add_assoc_long(&span_zv, "duration", ddog_v1_get_span_duration(span)); + add_assoc_str(&span_zv, "name", dd_CharSlice_to_zend_string(ddog_v1_get_span_name(span))); + add_assoc_str(&span_zv, "resource", dd_CharSlice_to_zend_string(ddog_v1_get_span_resource(span))); + add_assoc_str(&span_zv, "service", dd_CharSlice_to_zend_string(ddog_v1_get_span_service(span))); + add_assoc_str(&span_zv, "type", dd_CharSlice_to_zend_string(ddog_v1_get_span_type(span))); + if (ddog_v1_get_span_error(span)) { + add_assoc_long(&span_zv, "error", 1); } - size_t metrics_count = 0; - ddog_CharSlice *metrics_keys = ddog_span_metrics_get_keys(span, &metrics_count); - - if (metrics_count > 0) { - zval metrics_zv; - array_init(&metrics_zv); - - for (size_t k = 0; k < metrics_count; k++) { - ddog_CharSlice key = metrics_keys[k]; - double value; +#define DD_ZVAL_PROMOTED(field, getter) \ + do { \ + ddog_CharSlice _v = getter(span); \ + if (_v.len) add_assoc_str(&span_zv, field, dd_CharSlice_to_zend_string(_v)); \ + } while (0) + DD_ZVAL_PROMOTED("env", ddog_v1_get_span_env); + DD_ZVAL_PROMOTED("version", ddog_v1_get_span_version); + DD_ZVAL_PROMOTED("component", ddog_v1_get_span_component); +#undef DD_ZVAL_PROMOTED + uint32_t span_kind = ddog_v1_get_span_kind(span); + if (span_kind) { + add_assoc_long(&span_zv, "span_kind", span_kind); + } + if (has_priority && is_root) { + add_assoc_long(&span_zv, "sampling_priority", chunk_priority); + } + if (has_mechanism && is_root) { + add_assoc_long(&span_zv, "sampling_mechanism", chunk_mechanism); + } + if (chunk_origin.len && is_root) { + add_assoc_str(&span_zv, "origin", dd_CharSlice_to_zend_string(chunk_origin)); + } - if (ddog_get_span_metrics(span, key, &value)) { - zval value_zv; - ZVAL_DOUBLE(&value_zv, value); - zend_hash_str_update(Z_ARR(metrics_zv), key.ptr, key.len, &value_zv); + // Bytes-typed attributes are v0.4 meta_struct entries; surface them under + // "meta_struct" (as the v0.4 reader did), not mixed into the attribute map. + zval attrs_zv, meta_struct_zv; + array_init(&attrs_zv); + array_init(&meta_struct_zv); + if (j == 0 && process_tags.len) { + add_assoc_str(&attrs_zv, "_dd.tags.process", dd_CharSlice_to_zend_string(process_tags)); + } + if (j == 0 && otlp_export.len) { + add_assoc_str(&attrs_zv, "_dd.sdk.otlp_export", dd_CharSlice_to_zend_string(otlp_export)); + } + dd_attributes_to_zval(ddog_span_get_attributes(span), &attrs_zv, &meta_struct_zv); + dd_add_assoc_nonempty(&span_zv, "attributes", &attrs_zv); + dd_add_assoc_nonempty(&span_zv, "meta_struct", &meta_struct_zv); + + size_t link_count; + ddog_SpanLinkBytes *const *links = ddog_v1_get_links(span, &link_count); + if (link_count > 0) { + zval links_zv; + array_init(&links_zv); + for (size_t l = 0; l < link_count; l++) { + ddog_SpanLinkBytes *link = links[l]; + zval link_zv; + array_init(&link_zv); + add_assoc_str(&link_zv, KEY_TRACE_ID, ddtrace_span_id_as_string(ddog_v1_get_link_trace_id_low(link))); + uint64_t link_tid_high = ddog_v1_get_link_trace_id_high(link); + if (link_tid_high) { + add_assoc_str(&link_zv, "trace_id_high", ddtrace_span_id_as_hex_string(link_tid_high)); + } + add_assoc_str(&link_zv, KEY_SPAN_ID, ddtrace_span_id_as_string(ddog_v1_get_link_span_id(link))); + ddog_CharSlice tracestate = ddog_v1_get_link_tracestate(link); + if (tracestate.len) { + add_assoc_str(&link_zv, "trace_state", dd_CharSlice_to_zend_string(tracestate)); } + add_assoc_long(&link_zv, "flags", ddog_v1_get_link_flags(link)); + zval lattrs_zv; + array_init(&lattrs_zv); + dd_attributes_to_zval(ddog_link_get_attributes(link), &lattrs_zv, NULL); + dd_add_assoc_nonempty(&link_zv, "attributes", &lattrs_zv); + zend_hash_next_index_insert_new(Z_ARR(links_zv), &link_zv); } - - add_assoc_zval(&span_zv, "metrics", &metrics_zv); + add_assoc_zval(&span_zv, "span_links", &links_zv); } - size_t meta_struct_count = 0; - ddog_CharSlice *meta_struct_keys = ddog_span_meta_struct_get_keys(span, &meta_struct_count); - - if (meta_struct_count > 0) { - zval meta_struct_zv; - array_init(&meta_struct_zv); - - for (size_t k = 0; k < meta_struct_count; k++) { - ddog_CharSlice key = meta_struct_keys[k]; - ddog_CharSlice value = ddog_get_span_meta_struct(span, key); - - zval value_zv; - ZVAL_STR(&value_zv, dd_CharSlice_to_zend_string(value)); - zend_hash_str_update(Z_ARR(meta_struct_zv), key.ptr, key.len, &value_zv); + size_t event_count; + ddog_SpanEventBytes *const *events = ddog_v1_get_events(span, &event_count); + if (event_count > 0) { + zval events_zv; + array_init(&events_zv); + for (size_t e = 0; e < event_count; e++) { + ddog_SpanEventBytes *event = events[e]; + zval event_zv; + array_init(&event_zv); + add_assoc_str(&event_zv, "name", dd_CharSlice_to_zend_string(ddog_v1_get_event_name(event))); + add_assoc_long(&event_zv, "time_unix_nano", ddog_v1_get_event_time(event)); + zval eattrs_zv; + array_init(&eattrs_zv); + dd_attributes_to_zval(ddog_event_get_attributes(event), &eattrs_zv, NULL); + dd_add_assoc_nonempty(&event_zv, "attributes", &eattrs_zv); + zend_hash_next_index_insert_new(Z_ARR(events_zv), &event_zv); } - - add_assoc_zval(&span_zv, "meta_struct", &meta_struct_zv); + add_assoc_zval(&span_zv, "span_events", &events_zv); } zend_hash_next_index_insert_new(Z_ARR_P(&trace_zv), &span_zv); - - ddog_span_free_keys_ptr(meta_keys, meta_count); - ddog_span_free_keys_ptr(metrics_keys, metrics_count); - ddog_span_free_keys_ptr(meta_struct_keys, meta_struct_count); } zend_hash_next_index_insert_new(Z_ARR_P(&traces_zv), &trace_zv); @@ -2030,7 +2474,6 @@ zval dd_serialize_rust_traces_to_zval(ddog_TracesBytes *traces) { return traces_zv; } - static zend_string *dd_truncate_uncaught_exception(zend_string *msg) { const char uncaught[] = "Uncaught "; const char *data = ZSTR_VAL(msg); @@ -2061,7 +2504,7 @@ void ddtrace_save_active_error_to_metadata(void) { continue; } - dd_fatal_error_to_meta(ddtrace_property_array(&pspan->property_meta), error); + dd_fatal_error_to_meta(ddtrace_property_array(&pspan->property_attributes), error); } zend_string_release(error.type); zend_string_release(error.msg); @@ -2157,7 +2600,7 @@ void ddtrace_error_cb(DDTRACE_ERROR_CB_PARAMETERS) { continue; } - dd_fatal_error_to_meta(ddtrace_property_array(&pspan->property_meta), error); + dd_fatal_error_to_meta(ddtrace_property_array(&pspan->property_attributes), error); } zend_string_release(error.type); zend_string_release(error.msg); @@ -2196,9 +2639,8 @@ static zend_array *dd_ser_response_committed(ddtrace_user_req_listeners *self, z UNUSED(self, entity); ddtrace_root_span_data *root_span_data = ROOTSPANDATA(span); - zend_array *meta = ddtrace_property_array(&root_span_data->property_meta); struct iter *iter = dd_iterate_arr_arr_headers(headers); - dd_set_entrypoint_root_span_props_end(meta, status, iter, false); + dd_set_entrypoint_root_span_props_end(&root_span_data->span, status, iter, false); efree(iter); return NULL; } diff --git a/tracer/serializer.h b/tracer/serializer.h index 0bb42c31d5..1bfcdf3c7e 100644 --- a/tracer/serializer.h +++ b/tracer/serializer.h @@ -6,8 +6,16 @@ int ddtrace_serialize_simple_array(zval *trace, zval *retval); int ddtrace_serialize_simple_array_into_c_string(zval *trace, char **data_p, size_t *size_p); -ddog_SpanBytes *ddtrace_serialize_span_to_rust_span(ddtrace_span_data *span, ddog_TraceBytes *trace, bool p0_trace); -zval dd_serialize_rust_traces_to_zval(ddog_TracesBytes *traces); +// Returns the span's V1 builder node, or NULL when the span was dropped. +ddog_SpanNode *ddtrace_serialize_span_to_rust_span(ddtrace_span_data *span, ddtrace_serialize_ctx *ctx, bool p0_trace); +zval dd_serialize_rust_to_zval(struct ddog_TracerPayloadV1Builder *builder); + +// String span attribute setters shared with exception_serialize.c. +void dd_span_attr_str(ddog_SpanNode *span, const char *key, const char *val); +void dd_span_attr_zstr(ddog_SpanNode *span, const char *key, zend_string *val); + +// Normalizes a value written through SpanData::$meta (strings) or $metrics (doubles) into `dst`. +void ddtrace_normalize_tag_value(zval *dst, zval *value, bool metric); void ddtrace_save_active_error_to_metadata(void); void ddtrace_set_global_span_properties(ddtrace_span_data *span); diff --git a/tracer/span.c b/tracer/span.c index 0040514971..1d52dc3897 100644 --- a/tracer/span.c +++ b/tracer/span.c @@ -226,28 +226,29 @@ ddtrace_inferred_span_data *ddtrace_open_inferred_span(ddtrace_inferred_proxy_re ZVAL_COPY(&span->property_service, &root->property_service); // Fall back to root service name } - zend_array *meta = ddtrace_property_array(&span->property_meta); - - zend_hash_copy(meta, &DDTRACE_G(root_span_tags_preset), (copy_ctor_func_t)zval_add_ref); + zend_array *attributes = ddtrace_property_array(&span->property_attributes); + zend_hash_copy(attributes, &DDTRACE_G(root_span_tags_preset), (copy_ctor_func_t)zval_add_ref); if (result->http_method) { ZVAL_STR_COPY(&zv, result->http_method); - zend_hash_str_add_new(meta, ZEND_STRL("http.method"), &zv); + zend_hash_str_update(attributes, ZEND_STRL("http.method"), &zv); } if (result->domain && result->path) { ZVAL_STR(&zv, strpprintf(0, "%s%s", ZSTR_VAL(result->domain), ZSTR_VAL(result->path))); - zend_hash_str_add_new(meta, ZEND_STRL("http.url"), &zv); + zend_hash_str_update(attributes, ZEND_STRL("http.url"), &zv); } if (result->stage) { ZVAL_STR_COPY(&zv, result->stage); - zend_hash_str_add_new(meta, ZEND_STRL("stage"), &zv); + zend_hash_str_update(attributes, ZEND_STRL("stage"), &zv); } - ZVAL_LONG(&zv, 1); - zend_hash_str_add_new(ddtrace_property_array(&span->property_metrics), ZEND_STRL("_dd.inferred_span"), &zv); - add_assoc_string(&span->property_meta, "component", (char *)proxy_info->component); + ZVAL_DOUBLE(&zv, 1); + zend_hash_str_update(attributes, ZEND_STRL("_dd.inferred_span"), &zv); + // Set on the property; the serializer mirrors it into meta["component"] at serialization time. + zval_ptr_dtor(&span->property_component); + ZVAL_STRING(&span->property_component, (char *)proxy_info->component); ZVAL_STR(&span->property_type, zend_string_init(ZEND_STRL("web"), 0)); free_inferred_proxy_result(result); @@ -548,7 +549,7 @@ ddtrace_span_data *ddtrace_alloc_execute_data_span_ex(zend_ulong index, zend_exe zend_string_release(basename); } - zend_array *meta = ddtrace_property_array(&span->property_meta); + zend_array *meta = ddtrace_property_array(&span->property_attributes); zval location; ZVAL_STR(&location, zend_strpprintf(0, "%s:%d", ZSTR_VAL(EX(func)->op_array.filename), EX(func)->op_array.opcodes->lineno)); zend_hash_str_add_new(meta, ZEND_STRL("closure.declaration"), &location); @@ -828,7 +829,7 @@ static void dd_mark_closed_spans_flushable(ddtrace_span_stack *stack) { // This might get updated later with SpanStacks, but at that point it will be orphan spans. That's intentional. if (!get_global_DD_APM_TRACING_ENABLED()) { // Increment limiter, then force sampling priority if not an asm event - if (!ddtrace_standalone_limiter_allow() && !root_span->asm_event_emitted && !ddtrace_trace_source_is_meta_asm_sourced(ddtrace_property_array(&stack->root_span->property_meta))) { + if (!ddtrace_standalone_limiter_allow() && !root_span->asm_event_emitted && !ddtrace_trace_source_is_meta_asm_sourced(ddtrace_property_array(&stack->root_span->property_attributes))) { zval priority; ZVAL_LONG(&priority, PRIORITY_SAMPLING_AUTO_REJECT); datadog_assign_variable(&root_span->property_sampling_priority, &priority); @@ -1150,7 +1151,7 @@ void ddtrace_drop_span(ddtrace_span_data *span) { dd_drop_span(span, false); } -void ddtrace_serialize_closed_spans(ddog_TracesBytes *traces, bool fast_shutdown) { +void ddtrace_serialize_closed_spans(ddtrace_serialize_ctx *ctx, bool fast_shutdown) { if (DDTRACE_G(top_closed_stack)) { ddtrace_span_stack *rootstack = DDTRACE_G(top_closed_stack); DDTRACE_G(top_closed_stack) = NULL; @@ -1164,7 +1165,9 @@ void ddtrace_serialize_closed_spans(ddog_TracesBytes *traces, bool fast_shutdown stack = next_stack; next_stack = stack->next; } - ddog_TraceBytes *trace = ddog_traces_new_trace(traces); + if (ctx) { + ctx->chunk = DD_CHUNK_NONE; // one V1 chunk per V0.4 trace + } bool sampling_decided = false; bool p0_trace = false; @@ -1182,7 +1185,7 @@ void ddtrace_serialize_closed_spans(ddog_TracesBytes *traces, bool fast_shutdown do { ddtrace_span_data *tmp = span; span = tmp->next; - ddtrace_serialize_span_to_rust_span(tmp, trace, p0_trace); + ddtrace_serialize_span_to_rust_span(tmp, ctx, p0_trace); #if PHP_VERSION_ID < 70400 // remove the artificially increased RC while closing again GC_SET_REFCOUNT(&tmp->std, GC_REFCOUNT(&tmp->std) - DD_RC_CLOSED_MARKER); @@ -1209,10 +1212,10 @@ void ddtrace_serialize_closed_spans(ddog_TracesBytes *traces, bool fast_shutdown DDTRACE_G(dropped_spans_count) = 0; } -void ddtrace_serialize_closed_spans_with_cycle(ddog_TracesBytes *traces, bool fast_shutdown) { +void ddtrace_serialize_closed_spans_with_cycle(ddtrace_serialize_ctx *ctx, bool fast_shutdown) { // We need to loop here, as closing the last span root stack could add other spans here while (DDTRACE_G(top_closed_stack)) { - ddtrace_serialize_closed_spans(traces, fast_shutdown); + ddtrace_serialize_closed_spans(ctx, fast_shutdown); if (DDTRACE_G(open_spans_count)) { // Also flush possible cycles here, if there are remaining open spans gc_collect_cycles(); @@ -1259,7 +1262,7 @@ void ddtrace_populate_span_data(ddtrace_span_data *span, zend_string **service, *service = zend_string_init(ZEND_STRL("unnamed-php-service"), 0); } - zval *prop_env = zend_hash_str_find(ddtrace_property_array(&span->property_meta), ZEND_STRL("env")); + zval *prop_env = ddtrace_span_find_tag(span, ZEND_STRL("env")); if (!prop_env) { prop_env = &span->property_env; } @@ -1269,7 +1272,7 @@ void ddtrace_populate_span_data(ddtrace_span_data *span, zend_string **service, *env = NULL; } - zval *prop_version = zend_hash_str_find(ddtrace_property_array(&span->property_meta), ZEND_STRL("version")); + zval *prop_version = ddtrace_span_find_tag(span, ZEND_STRL("version")); if (!prop_version) { prop_version = &span->property_version; } diff --git a/tracer/span.h b/tracer/span.h index 7733b85535..f9d5f5be9f 100644 --- a/tracer/span.h +++ b/tracer/span.h @@ -16,6 +16,18 @@ #include "otel_context.h" #endif +// V1 payload build context threaded through serialization. `chunk` is DD_CHUNK_NONE until the +// first span of the current stack creates its chunk (ddtrace_serialize_closed_spans resets it per +// stack). Under the Box-per-node model `chunk` is the chunk node pointer, stable across sibling pushes. +#define DD_CHUNK_NONE (NULL) +typedef struct { + struct ddog_TracerPayloadV1Builder *builder; + struct ddog_ChunkNode *chunk; + bool process_tags_set; // the payload's _dd.tags.process / _dd.sdk.otlp_export attributes were decided + bool payload_fields_set; // the payload env/app_version/hostname/git were taken from a root span + bool mark_top_level; // mark `_dd.top_level` on every top-level span (the sidecar sender's V1 needs it) +} ddtrace_serialize_ctx; + #define DDTRACE_DROPPED_SPAN (-1ull) #define DDTRACE_SILENTLY_DROPPED_SPAN (-2ull) @@ -52,8 +64,6 @@ typedef union ddtrace_span_properties { zval property_name; zval property_resource; zval property_service; - zval property_env; - zval property_version; zval property_meta_struct; zval property_type; zval property_meta; @@ -76,6 +86,12 @@ typedef union ddtrace_span_properties { }; zval property_on_close; zval property_baggage; + zval property_env; + zval property_version; + zval property_component; + zval property_span_kind; + zval property_attributes; + zval property_ignore_error; }; } ddtrace_span_properties; @@ -96,6 +112,7 @@ struct ddtrace_span_data { uint32_t active_child_spans; struct ddtrace_span_data *next; struct ddtrace_root_span_data *root; + zend_object *tags_views[2]; // cached $meta / $metrics views (span_tags_view.c) union { ddtrace_span_properties; @@ -150,6 +167,7 @@ struct ddtrace_root_span_data { zval property_origin; zval property_propagated_tags; zval property_sampling_priority; + zval property_sampling_mechanism; zval property_propagated_sampling_priority; zval property_tracestate; zval property_tracestate_tags; @@ -157,6 +175,7 @@ struct ddtrace_root_span_data { zval property_trace_id; zval property_git_metadata; zval property_inferred_span; + zval property_hostname; }; static inline ddtrace_root_span_data *ROOTSPANDATA(zend_object *obj) { @@ -177,6 +196,7 @@ struct ddtrace_span_stack { ddtrace_span_properties *active; }; zval property_span_creation_observers; + zval property_attributes; }; }; struct ddtrace_root_span_data *root_span; @@ -275,8 +295,8 @@ void ddtrace_close_top_span_without_stack_swap(ddtrace_span_data *span); void ddtrace_close_all_open_spans(bool force_close_root_span); void ddtrace_drop_span(ddtrace_span_data *span); void ddtrace_mark_all_span_stacks_flushable(void); -void ddtrace_serialize_closed_spans(ddog_TracesBytes *traces, bool fast_shutdown); -void ddtrace_serialize_closed_spans_with_cycle(ddog_TracesBytes *traces, bool fast_shutdown); +void ddtrace_serialize_closed_spans(ddtrace_serialize_ctx *ctx, bool fast_shutdown); +void ddtrace_serialize_closed_spans_with_cycle(ddtrace_serialize_ctx *ctx, bool fast_shutdown); zend_string *ddtrace_span_id_as_string(uint64_t id); zend_string *datadog_trace_id_as_string(datadog_trace_id id); zend_string *ddtrace_span_id_as_hex_string(uint64_t id); @@ -294,6 +314,11 @@ static inline bool ddtrace_span_is_entrypoint_root(ddtrace_span_data *span) { return span->std.ce == ddtrace_ce_root_span_data && (!span->stack->parent_stack || !span->stack->parent_stack->parent_stack); } +// Tag lookup in SpanData::$attributes, the single tag store ($meta/$metrics are views onto it). +static inline zval *ddtrace_span_find_tag(ddtrace_span_data *span, const char *key, size_t len) { + return zend_hash_str_find(ddtrace_property_array(&span->property_attributes), key, len); +} + static inline ddtrace_span_data *ddtrace_get_inferred_span(ddtrace_root_span_data *root) { zval *inferred_span_zv = &root->property_inferred_span; if (Z_TYPE_P(inferred_span_zv) == IS_OBJECT && Z_OBJCE_P(inferred_span_zv) == ddtrace_ce_inferred_span_data) { diff --git a/tracer/span_stats.c b/tracer/span_stats.c index 2e0750a40e..c90bedbf0a 100644 --- a/tracer/span_stats.c +++ b/tracer/span_stats.c @@ -39,12 +39,15 @@ static const size_t GRPC_META_KEY_LENS[] = { // agent, which is larger and must be scanned in full. #define DDTRACE_MAX_PEER_TAGS 32 +static zval *dd_pre_find_tag(const ddtrace_span_precomputed *pre, const char *key, size_t len) { + return zend_hash_str_find(pre->attributes, key, len); +} + void ddtrace_precompute_span(ddtrace_span_data *span, ddtrace_span_precomputed *pre) { - pre->meta = ddtrace_property_array(&span->property_meta); - pre->metrics = ddtrace_property_array(&span->property_metrics); + pre->attributes = ddtrace_property_array(&span->property_attributes); - // Service: meta["service.name"] override then span property, then apply DD_SERVICE_MAPPING. - zval *service_name_meta = pre->meta ? zend_hash_str_find(pre->meta, ZEND_STRL("service.name")) : NULL; + // Service: "service.name" tag override then span property, then apply DD_SERVICE_MAPPING. + zval *service_name_meta = dd_pre_find_tag(pre, ZEND_STRL("service.name")); pre->service_from_meta = (service_name_meta != NULL); pre->service = NULL; if (service_name_meta) { @@ -64,8 +67,8 @@ void ddtrace_precompute_span(ddtrace_span_data *span, ddtrace_span_precomputed * } } - // Name: meta["operation.name"] (lowercased!) or span property. - zval *operation_name = pre->meta ? zend_hash_str_find(pre->meta, ZEND_STRL("operation.name")) : NULL; + // Name: "operation.name" tag (lowercased!) or span property. + zval *operation_name = dd_pre_find_tag(pre, ZEND_STRL("operation.name")); pre->name = NULL; if (operation_name && Z_TYPE_P(operation_name) == IS_STRING) { pre->name = zend_string_tolower(Z_STR_P(operation_name)); @@ -79,8 +82,8 @@ void ddtrace_precompute_span(ddtrace_span_data *span, ddtrace_span_precomputed * pre->name_from_meta = false; } - // Resource: meta["resource.name"] or span property, falling back to name. - zval *resource_name = pre->meta ? zend_hash_str_find(pre->meta, ZEND_STRL("resource.name")) : NULL; + // Resource: "resource.name" tag or span property, falling back to name. + zval *resource_name = dd_pre_find_tag(pre, ZEND_STRL("resource.name")); pre->resource_from_meta = (resource_name != NULL); pre->resource = NULL; if (resource_name) { @@ -97,8 +100,8 @@ void ddtrace_precompute_span(ddtrace_span_data *span, ddtrace_span_precomputed * pre->resource = zend_string_copy(pre->name); } - // Type: meta["span.type"] or span property. - zval *span_type = pre->meta ? zend_hash_str_find(pre->meta, ZEND_STRL("span.type")) : NULL; + // Type: "span.type" tag or span property. + zval *span_type = dd_pre_find_tag(pre, ZEND_STRL("span.type")); pre->type_from_meta = (span_type != NULL); pre->type = NULL; zval *prop_type = span_type ? span_type : &span->property_type; @@ -107,55 +110,42 @@ void ddtrace_precompute_span(ddtrace_span_data *span, ddtrace_span_precomputed * pre->type = datadog_convert_to_str(prop_type); } - // Env: prefer deprecated meta["env"] (with a warning), else span property. + // Env: property first, then the "env" tag fallback (matching serializer.c promotion). Without the + // fallback, DD_TAGS "env" (DD_ENV unset) would bucket stats by empty env vs the trace's. pre->env = NULL; - zval *meta_env = pre->meta ? zend_hash_str_find(pre->meta, ZEND_STRL("env")) : NULL; - if (meta_env) { - pre->env_deprecated = true; - LOG(DEPRECATED, "Using \"env\" in meta is deprecated. Instead specify the env property directly on the span."); - zend_string *str = datadog_convert_to_str(meta_env); + zval *prop_env = &span->property_env; + ZVAL_DEREF(prop_env); + if (Z_TYPE_P(prop_env) > IS_NULL) { + zend_string *str = datadog_convert_to_str(prop_env); if (ZSTR_LEN(str) > 0) { pre->env = str; } else { zend_string_release(str); } - } else { - pre->env_deprecated = false; - zval *prop_env = &span->property_env; - ZVAL_DEREF(prop_env); - if (Z_TYPE_P(prop_env) > IS_NULL) { - zend_string *str = datadog_convert_to_str(prop_env); - if (ZSTR_LEN(str) > 0) { - pre->env = str; - } else { - zend_string_release(str); - } + } + if (!pre->env) { + zval *env_meta = dd_pre_find_tag(pre, ZEND_STRL("env")); + if (env_meta && Z_TYPE_P(env_meta) == IS_STRING) { + pre->env = zend_string_copy(Z_STR_P(env_meta)); } } - // Version: prefer deprecated meta["version"] (with a warning), else the span's own property. + // Version: span property first, then the "version" tag fallback (same rationale). pre->version = NULL; - zval *meta_version = pre->meta ? zend_hash_str_find(pre->meta, ZEND_STRL("version")) : NULL; - if (meta_version) { - pre->version_deprecated = true; - LOG(DEPRECATED, "Using \"version\" in meta is deprecated. Instead specify the version property directly on the span."); - zend_string *str = datadog_convert_to_str(meta_version); + zval *prop_version = &span->property_version; + ZVAL_DEREF(prop_version); + if (Z_TYPE_P(prop_version) > IS_NULL) { + zend_string *str = datadog_convert_to_str(prop_version); if (ZSTR_LEN(str) > 0) { pre->version = str; } else { zend_string_release(str); } - } else { - pre->version_deprecated = false; - zval *prop_version = &span->property_version; - ZVAL_DEREF(prop_version); - if (Z_TYPE_P(prop_version) > IS_NULL) { - zend_string *str = datadog_convert_to_str(prop_version); - if (ZSTR_LEN(str) > 0) { - pre->version = str; - } else { - zend_string_release(str); - } + } + if (!pre->version) { + zval *version_meta = dd_pre_find_tag(pre, ZEND_STRL("version")); + if (version_meta && Z_TYPE_P(version_meta) == IS_STRING) { + pre->version = zend_string_copy(Z_STR_P(version_meta)); } } @@ -164,25 +154,36 @@ void ddtrace_precompute_span(ddtrace_span_data *span, ddtrace_span_precomputed * pre->has_exception = Z_TYPE_P(exception_zv) == IS_OBJECT && instanceof_function(Z_OBJCE_P(exception_zv), zend_ce_throwable); - zval *error_ignored_zv = pre->meta ? zend_hash_str_find(pre->meta, ZEND_STRL("error.ignored")) : NULL; - pre->ignore_error = error_ignored_zv && zend_is_true(error_ignored_zv); + // $ignoreError, or the deprecated "error.ignored" tag, which can only turn it on. The tag is folded into + // the property and dropped, so it is never emitted and should_track_error's ancestor walk still sees it. + zval *error_ignored = zend_hash_str_find(pre->attributes, ZEND_STRL("error.ignored")); + if (error_ignored) { + if (zend_is_true(error_ignored)) { + zval *ignore_error = &span->property_ignore_error; + ZVAL_DEREF(ignore_error); + zval_ptr_dtor(ignore_error); + ZVAL_TRUE(ignore_error); + } + zend_hash_str_del(pre->attributes, ZEND_STRL("error.ignored")); + } + pre->ignore_error = zend_is_true(&span->property_ignore_error); // Stats eligibility fields — fetched once here to avoid duplicate lookups in the two // call sites (ddtrace_span_concentrator_feed_cb and ddtrace_feed_span_to_concentrator). pre->has_top_level = ddtrace_span_is_entrypoint_root(span) || (span->std.ce == ddtrace_ce_root_span_data && ROOTSPANDATA(&span->std)->parent_id == 0) || (span->parent && !zend_is_identical(&span->property_service, &span->parent->property_service)); - zval *is_measured = pre->metrics ? zend_hash_str_find(pre->metrics, ZEND_STRL("_dd.measured")) : NULL; + zval *is_measured = dd_pre_find_tag(pre, ZEND_STRL("_dd.measured")); pre->is_measured = is_measured && zval_get_double(is_measured) != 0.0; pre->is_partial_snapshot = false; - zval *span_kind_zv = pre->meta ? zend_hash_str_find(pre->meta, ZEND_STRL("span.kind")) : NULL; - pre->span_kind = (span_kind_zv && Z_TYPE_P(span_kind_zv) == IS_STRING) ? Z_STR_P(span_kind_zv) : NULL; + zval *span_kind_zv = dd_pre_find_tag(pre, ZEND_STRL("span.kind")); + // Owned copy: the serializer deletes the "span.kind" tag up front, so pre must not borrow it. + pre->span_kind = (span_kind_zv && Z_TYPE_P(span_kind_zv) == IS_STRING) ? zend_string_copy(Z_STR_P(span_kind_zv)) : NULL; } bool dd_compute_span_is_error(const ddtrace_span_precomputed *pre) { if (pre->ignore_error) { return false; } - if (pre->meta && (zend_hash_str_find(pre->meta, ZEND_STRL("error.message")) != NULL || - zend_hash_str_find(pre->meta, ZEND_STRL("error.type")) != NULL)) { + if (dd_pre_find_tag(pre, ZEND_STRL("error.message")) || dd_pre_find_tag(pre, ZEND_STRL("error.type"))) { return true; } return pre->has_exception; @@ -207,6 +208,9 @@ void ddtrace_free_span_precomputed(ddtrace_span_precomputed *pre) { if (pre->version) { zend_string_release(pre->version); } + if (pre->span_kind) { + zend_string_release(pre->span_kind); + } } typedef struct { @@ -222,9 +226,6 @@ typedef struct { static ddog_PhpSpanStats ddtrace_build_span_stats_core( ddtrace_span_data *span, const ddtrace_span_precomputed *pre, ddog_CharSlice span_kind_slice ) { - zend_array *meta = pre->meta; - zend_array *metrics = pre->metrics; - ddog_CharSlice service_slice = dd_zend_string_to_CharSlice(pre->service); ddog_CharSlice name_slice = dd_zend_string_to_CharSlice(pre->name); ddog_CharSlice resource_slice = dd_zend_string_to_CharSlice(pre->resource); @@ -236,22 +237,22 @@ static ddog_PhpSpanStats ddtrace_build_span_stats_core( // HTTP and gRPC fields only appear on service entry spans, which are always stats-eligible. // They are fetched here (after the eligibility check) rather than in ddtrace_precompute_span. - zval *http_status_str_zv = meta ? zend_hash_str_find(meta, ZEND_STRL("http.status_code")) : NULL; + zval *http_status_str_zv = dd_pre_find_tag(pre, ZEND_STRL("http.status_code")); ddog_CharSlice http_status_str_slice = http_status_str_zv && Z_TYPE_P(http_status_str_zv) == IS_STRING ? dd_zend_string_to_CharSlice(Z_STR_P(http_status_str_zv)) : DDOG_CHARSLICE_C(""); - zval *http_method_zv = meta ? zend_hash_str_find(meta, ZEND_STRL("http.method")) : NULL; + zval *http_method_zv = dd_pre_find_tag(pre, ZEND_STRL("http.method")); ddog_CharSlice http_method_slice = http_method_zv && Z_TYPE_P(http_method_zv) == IS_STRING ? dd_zend_string_to_CharSlice(Z_STR_P(http_method_zv)) : DDOG_CHARSLICE_C(""); - zval *http_endpoint_zv = meta ? zend_hash_str_find(meta, ZEND_STRL("http.endpoint")) : NULL; + zval *http_endpoint_zv = dd_pre_find_tag(pre, ZEND_STRL("http.endpoint")); ddog_CharSlice http_endpoint_slice = http_endpoint_zv && Z_TYPE_P(http_endpoint_zv) == IS_STRING ? dd_zend_string_to_CharSlice(Z_STR_P(http_endpoint_zv)) : DDOG_CHARSLICE_C(""); - zval *http_route_zv = meta ? zend_hash_str_find(meta, ZEND_STRL("http.route")) : NULL; + zval *http_route_zv = dd_pre_find_tag(pre, ZEND_STRL("http.route")); ddog_CharSlice http_route_slice = http_route_zv && Z_TYPE_P(http_route_zv) == IS_STRING ? dd_zend_string_to_CharSlice(Z_STR_P(http_route_zv)) : DDOG_CHARSLICE_C(""); @@ -262,7 +263,7 @@ static ddog_PhpSpanStats ddtrace_build_span_stats_core( ? dd_zend_string_to_CharSlice(Z_STR_P(origin_zv)) : DDOG_CHARSLICE_C(""); - zval *service_source_zv = meta ? zend_hash_str_find(meta, ZEND_STRL("_dd.svc_src")) : NULL; + zval *service_source_zv = dd_pre_find_tag(pre, ZEND_STRL("_dd.svc_src")); ddog_CharSlice service_source_slice = service_source_zv && Z_TYPE_P(service_source_zv) == IS_STRING ? dd_zend_string_to_CharSlice(Z_STR_P(service_source_zv)) : DDOG_CHARSLICE_C(""); @@ -272,17 +273,12 @@ static ddog_PhpSpanStats ddtrace_build_span_stats_core( for (int i = 0; i < ddog_PHP_GRPC_KEY_COUNT; i++) { grpc_meta[i] = DDOG_CHARSLICE_C(""); grpc_metrics[i] = NAN; - if (meta) { - zval *gm = zend_hash_str_find(meta, GRPC_META_KEYS[i], GRPC_META_KEY_LENS[i]); - if (gm && Z_TYPE_P(gm) == IS_STRING) { - grpc_meta[i] = dd_zend_string_to_CharSlice(Z_STR_P(gm)); - } - } - if (metrics) { - zval *gv = zend_hash_str_find(metrics, GRPC_META_KEYS[i], GRPC_META_KEY_LENS[i]); - if (gv) { - grpc_metrics[i] = zval_get_double(gv); - } + // A string tag lands in the meta slot, a number in the metrics slot. + zval *ga = zend_hash_str_find(pre->attributes, GRPC_META_KEYS[i], GRPC_META_KEY_LENS[i]); + if (ga && Z_TYPE_P(ga) == IS_STRING) { + grpc_meta[i] = dd_zend_string_to_CharSlice(Z_STR_P(ga)); + } else if (ga) { + grpc_metrics[i] = zval_get_double(ga); } } @@ -344,7 +340,7 @@ static ddog_OwnedShmSpanInput *ddtrace_span_concentrator_feed_cb(const ddog_Span if (peer_tag_keys_count > 0 && peer_tag_keys) { for (size_t i = 0; i < peer_tag_keys_count && actual_peer_tags < DDTRACE_MAX_PEER_TAGS; i++) { const ddog_CharSlice *k = &peer_tag_keys[i]; - zval *val = zend_hash_str_find(pre->meta, k->ptr, k->len); + zval *val = dd_pre_find_tag(pre, k->ptr, k->len); if (val && Z_TYPE_P(val) == IS_STRING) { peer_tags[actual_peer_tags].key = *k; peer_tags[actual_peer_tags].value = dd_zend_string_to_CharSlice(Z_STR_P(val)); @@ -355,7 +351,7 @@ static ddog_OwnedShmSpanInput *ddtrace_span_concentrator_feed_cb(const ddog_Span } else if (!pre->span_kind || !zend_string_equals_literal(pre->span_kind, "server")) { // internal or no span.kind: use _dd.base_service only if it marks a service override static const ddog_CharSlice BASE_SERVICE_KEY = DDOG_CHARSLICE_C_BARE("_dd.base_service"); - zval *base_svc_zv = zend_hash_str_find(pre->meta, ZEND_STRL("_dd.base_service")); + zval *base_svc_zv = dd_pre_find_tag(pre, ZEND_STRL("_dd.base_service")); if (base_svc_zv && Z_TYPE_P(base_svc_zv) == IS_STRING) { peer_tags[0].key = BASE_SERVICE_KEY; peer_tags[0].value = dd_zend_string_to_CharSlice(Z_STR_P(base_svc_zv)); @@ -379,6 +375,11 @@ void ddtrace_feed_span_to_concentrator(ddtrace_span_data *span, const ddtrace_sp version_zstr = Z_STR_P(root_version_zv); } else { version_zstr = get_DD_VERSION(); + // When DD_VERSION is unset, DD_TAGS "version" lives only in meta (deleted during promotion), + // so fall back to pre->version to keep stats bucketed by the trace's version. + if (ZSTR_LEN(version_zstr) == 0 && pre->version) { + version_zstr = pre->version; + } } ddog_CharSlice version_slice = dd_zend_string_to_CharSlice(version_zstr); // Use the process-level DD_SERVICE as the concentrator key so all spans from this PHP diff --git a/tracer/span_stats.h b/tracer/span_stats.h index b33e068672..f1fa07e17a 100644 --- a/tracer/span_stats.h +++ b/tracer/span_stats.h @@ -13,12 +13,10 @@ * Owned strings (service, name, resource, type) are zend_string* that must be released with * ddtrace_free_span_precomputed() when no longer needed. NULL means the field is absent. * - * meta and metrics are borrowed pointers (no ownership transfer). - * zval* fields below are also borrowed from meta/metrics and share the same lifetime. + * attributes is a borrowed pointer (no ownership transfer); all tag lookups read it. */ typedef struct { - zend_array *meta; - zend_array *metrics; + zend_array *attributes; /* Owned strings — release with ddtrace_free_span_precomputed() */ zend_string *service; /* mapped service name */ @@ -27,20 +25,16 @@ typedef struct { zend_string *type; /* resolved span type */ zend_string *env; /* from span->property_env; NULL when empty */ zend_string *version; /* from span->root->property_version; NULL when empty */ - zend_string *span_kind; /* meta["span.kind"], NULL if absent or not a string */ + zend_string *span_kind; /* owned copy of meta["span.kind"], NULL if absent or not a string */ /* True when the value came from a meta override (serializer must delete that meta key) */ - bool service_from_meta; + bool service_from_meta; /* from_meta: an attributes or meta override */ bool name_from_meta; bool resource_from_meta; bool type_from_meta; - /* True when the span's meta hash contains a deprecated "env"/"version" key */ - bool env_deprecated; - bool version_deprecated; - bool has_exception; /* when span->property_exception holds a Throwable */ - bool ignore_error; + bool ignore_error; /* SpanData::$ignoreError, or the deprecated meta["error.ignored"] */ /* Stats-specific fields — precomputed to avoid repeated lookups across two call sites. */ bool has_top_level; /* ddtrace_span_is_entrypoint_root() */ @@ -59,7 +53,7 @@ void ddtrace_free_span_precomputed(ddtrace_span_precomputed *pre); /** * Compute whether a span should be marked as an error. - * Checks meta["error.message"], meta["error.type"], pre->has_exception, and meta["error.ignored"]. + * Checks the error.message/error.type tags, pre->has_exception, and pre->ignore_error. * Accurate for both sampled and non-sampled spans (HTTP errors are in PHP meta via * dd_ser_response_committed before the span is closed). */ diff --git a/tracer/span_tags_view.c b/tracer/span_tags_view.c new file mode 100644 index 0000000000..9596d74eba --- /dev/null +++ b/tracer/span_tags_view.c @@ -0,0 +1,520 @@ +#include "span_tags_view.h" + +#include +#include +#include +#if PHP_VERSION_ID < 70200 +#include +#define zend_ce_countable spl_ce_Countable +#endif + +#include "ddtrace.h" +#include "serializer.h" + +zend_class_entry *ddtrace_ce_span_tags_view; +static zend_object_handlers dd_span_tags_view_handlers; + +typedef struct { + ddtrace_span_data *span; // weak; NULL once the span is freed + bool metrics; + zend_object std; +} dd_span_tags_view; + +#if PHP_VERSION_ID < 80000 +#define DD_OBJ_ARG zval *object +#define DD_OBJ Z_OBJ_P(object) +#define DD_MEMBER_ARG zval *member +#define DD_MEMBER (Z_TYPE_P(member) == IS_STRING ? Z_STR_P(member) : ZSTR_EMPTY_ALLOC()) +#else +#define DD_OBJ_ARG zend_object *object +#define DD_OBJ object +#define DD_MEMBER_ARG zend_string *member +#define DD_MEMBER member +#endif + +static inline dd_span_tags_view *dd_tags_view_from_obj(zend_object *obj) { + return (dd_span_tags_view *)((char *)obj - XtOffsetOf(dd_span_tags_view, std)); +} + +// 0 for $meta, 1 for $metrics, -1 for any other property. +static inline int dd_tags_bucket_of(zend_string *name) { + if (zend_string_equals_literal(name, "meta")) { + return 0; + } + if (zend_string_equals_literal(name, "metrics")) { + return 1; + } + return -1; +} + +// Numbers are metrics; any other non-null value is meta. +static inline bool dd_tags_in_bucket(zval *val, bool metrics) { + ZVAL_DEREF(val); + if (Z_TYPE_P(val) == IS_LONG || Z_TYPE_P(val) == IS_DOUBLE) { + return metrics; + } + return !metrics && Z_TYPE_P(val) > IS_NULL; +} + +static inline zend_array *dd_tags_attrs_read(ddtrace_span_data *span) { + if (!span) { + return NULL; + } + zval *attrs = &span->property_attributes; + ZVAL_DEREF(attrs); + return Z_TYPE_P(attrs) == IS_ARRAY ? Z_ARR_P(attrs) : NULL; +} + +static void dd_tags_snapshot(zend_array *attrs, bool metrics, zval *rv) { + array_init(rv); + if (!attrs) { + return; + } + zend_ulong h; + zend_string *key; + zval *val; + ZEND_HASH_FOREACH_KEY_VAL_IND(attrs, h, key, val) { + if (dd_tags_in_bucket(val, metrics)) { + ZVAL_DEREF(val); + Z_TRY_ADDREF_P(val); + if (key) { + zend_hash_add_new(Z_ARR_P(rv), key, val); + } else { + zend_hash_index_add_new(Z_ARR_P(rv), h, val); + } + } + } ZEND_HASH_FOREACH_END(); +} + +static zend_long dd_tags_count(zend_array *attrs, bool metrics) { + zend_long count = 0; + if (attrs) { + zval *val; + ZEND_HASH_FOREACH_VAL_IND(attrs, val) { + count += dd_tags_in_bucket(val, metrics); + } ZEND_HASH_FOREACH_END(); + } + return count; +} + +// Replaces the bucket's entries of $attributes with `values` (normalized), or just clears it. +// Keys kept by `values` are updated in place so that they keep their position. +static void dd_tags_replace_bucket(ddtrace_span_data *span, bool metrics, zend_array *values) { + zend_array *attrs = ddtrace_property_array(&span->property_attributes); + zend_ulong h; + zend_string *key; + zval *val; + ZEND_HASH_FOREACH_KEY_VAL_IND(attrs, h, key, val) { + if (dd_tags_in_bucket(val, metrics) + && !(values && (key ? zend_hash_exists(values, key) : zend_hash_index_exists(values, h)))) { + if (key) { + zend_hash_del(attrs, key); + } else { + zend_hash_index_del(attrs, h); + } + } + } ZEND_HASH_FOREACH_END(); + + if (values) { + ZEND_HASH_FOREACH_KEY_VAL_IND(values, h, key, val) { + zval normalized; + ddtrace_normalize_tag_value(&normalized, val, metrics); + if (key) { + zend_hash_update(attrs, key, &normalized); + } else { + zend_hash_index_update(attrs, h, &normalized); + } + } ZEND_HASH_FOREACH_END(); + } +} + +static zval *dd_tags_find(dd_span_tags_view *view, zval *offset, zend_string **key_out) { + ZVAL_DEREF(offset); + zend_string *key = zval_get_string(offset); + zend_array *attrs = dd_tags_attrs_read(view->span); + zval *val = attrs && !EG(exception) ? zend_symtable_find(attrs, key) : NULL; + if (val && !dd_tags_in_bucket(val, view->metrics)) { + val = NULL; + } + if (key_out) { + *key_out = key; + } else { + zend_string_release(key); + } + return val; +} + +static zval *dd_tags_view_read(dd_span_tags_view *view, zval *offset, int type, zval *rv) { + if (!offset) { + zend_throw_error(NULL, "Cannot read an appended element of SpanData::$%s", view->metrics ? "metrics" : "meta"); + return &EG(uninitialized_zval); + } + zend_string *key; + zval *val = dd_tags_find(view, offset, &key); + if (val) { + ZVAL_COPY_DEREF(rv, val); + } else { + if (type == BP_VAR_R && !EG(exception)) { +#if PHP_VERSION_ID >= 80000 + zend_error(E_WARNING, "Undefined array key \"%s\"", ZSTR_VAL(key)); +#else + zend_error(E_NOTICE, "Undefined index: %s", ZSTR_VAL(key)); +#endif + } + ZVAL_NULL(rv); + } + zend_string_release(key); + return rv; +} + +static void dd_tags_view_write(dd_span_tags_view *view, zval *offset, zval *value) { + if (!offset) { + zend_throw_error(NULL, "Cannot append to SpanData::$%s", view->metrics ? "metrics" : "meta"); + return; + } + if (!view->span) { + return; + } + ZVAL_DEREF(offset); + zend_string *key = zval_get_string(offset); + if (!EG(exception)) { + zval normalized; + ddtrace_normalize_tag_value(&normalized, value, view->metrics); + zend_symtable_update(ddtrace_property_array(&view->span->property_attributes), key, &normalized); + } + zend_string_release(key); +} + +static bool dd_tags_view_has(dd_span_tags_view *view, zval *offset, int check_empty) { + zval *val = dd_tags_find(view, offset, NULL); + return val && (check_empty ? zend_is_true(val) : 1); +} + +static void dd_tags_view_unset(dd_span_tags_view *view, zval *offset) { + zend_string *key; + if (dd_tags_find(view, offset, &key)) { + zend_symtable_del(ddtrace_property_array(&view->span->property_attributes), key); + } + zend_string_release(key); +} + +static zend_object *dd_tags_view_create(zend_class_entry *ce) { + dd_span_tags_view *view = ecalloc(1, sizeof(*view) + zend_object_properties_size(ce)); + zend_object_std_init(&view->std, ce); + object_properties_init(&view->std, ce); + view->std.handlers = &dd_span_tags_view_handlers; + return &view->std; +} + +// The span keeps the cached view alive; the view only points back weakly. +static zend_object *dd_span_tags_view_get(ddtrace_span_data *span, int bucket) { + zend_object *obj = span->tags_views[bucket]; + if (!obj) { + obj = dd_tags_view_create(ddtrace_ce_span_tags_view); + dd_span_tags_view *view = dd_tags_view_from_obj(obj); + view->span = span; + view->metrics = bucket == 1; + span->tags_views[bucket] = obj; + } + GC_ADDREF(obj); + return obj; +} + +void ddtrace_span_tags_views_release(ddtrace_span_data *span) { + for (int i = 0; i < 2; ++i) { + zend_object *obj = span->tags_views[i]; + if (obj) { + dd_tags_view_from_obj(obj)->span = NULL; + span->tags_views[i] = NULL; + OBJ_RELEASE(obj); + } + } +} + +/* View object handlers */ + +static zval *dd_tags_view_read_dimension(DD_OBJ_ARG, zval *offset, int type, zval *rv) { + return dd_tags_view_read(dd_tags_view_from_obj(DD_OBJ), offset, type, rv); +} + +static void dd_tags_view_write_dimension(DD_OBJ_ARG, zval *offset, zval *value) { + dd_tags_view_write(dd_tags_view_from_obj(DD_OBJ), offset, value); +} + +static int dd_tags_view_has_dimension(DD_OBJ_ARG, zval *offset, int check_empty) { + return dd_tags_view_has(dd_tags_view_from_obj(DD_OBJ), offset, check_empty); +} + +static void dd_tags_view_unset_dimension(DD_OBJ_ARG, zval *offset) { + dd_tags_view_unset(dd_tags_view_from_obj(DD_OBJ), offset); +} + +#if PHP_VERSION_ID >= 80100 +static zend_result dd_tags_view_count_elements(DD_OBJ_ARG, zend_long *count) { +#else +static int dd_tags_view_count_elements(DD_OBJ_ARG, zend_long *count) { +#endif + dd_span_tags_view *view = dd_tags_view_from_obj(DD_OBJ); + *count = dd_tags_count(dd_tags_attrs_read(view->span), view->metrics); + return SUCCESS; +} + +static zend_array *dd_tags_view_snapshot_ht(zend_object *obj) { + dd_span_tags_view *view = dd_tags_view_from_obj(obj); + zval snapshot; + dd_tags_snapshot(dd_tags_attrs_read(view->span), view->metrics, &snapshot); + return Z_ARR(snapshot); +} + +#if PHP_VERSION_ID >= 70400 +static zend_array *dd_tags_view_get_properties_for(DD_OBJ_ARG, zend_prop_purpose purpose) { + (void)purpose; + return dd_tags_view_snapshot_ht(DD_OBJ); +} +#else +static HashTable *dd_tags_view_get_debug_info(zval *object, int *is_temp) { + *is_temp = 1; + return dd_tags_view_snapshot_ht(Z_OBJ_P(object)); +} +#endif + +/* View methods (ArrayAccess, Countable, IteratorAggregate) */ + +#define DD_THIS_VIEW dd_tags_view_from_obj(Z_OBJ_P(ZEND_THIS)) + +PHP_METHOD(DDTrace_SpanTagsView, offsetGet) { + zval *offset; + if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &offset) == FAILURE) { + return; + } + dd_tags_view_read(DD_THIS_VIEW, offset, BP_VAR_R, return_value); +} + +PHP_METHOD(DDTrace_SpanTagsView, offsetSet) { + zval *offset, *value; + if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz", &offset, &value) == FAILURE) { + return; + } + dd_tags_view_write(DD_THIS_VIEW, Z_TYPE_P(offset) == IS_NULL ? NULL : offset, value); +} + +PHP_METHOD(DDTrace_SpanTagsView, offsetExists) { + zval *offset; + if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &offset) == FAILURE) { + return; + } + RETURN_BOOL(dd_tags_view_has(DD_THIS_VIEW, offset, 0)); +} + +PHP_METHOD(DDTrace_SpanTagsView, offsetUnset) { + zval *offset; + if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &offset) == FAILURE) { + return; + } + dd_tags_view_unset(DD_THIS_VIEW, offset); +} + +PHP_METHOD(DDTrace_SpanTagsView, count) { + if (zend_parse_parameters_none() == FAILURE) { + return; + } + dd_span_tags_view *view = DD_THIS_VIEW; + RETURN_LONG(dd_tags_count(dd_tags_attrs_read(view->span), view->metrics)); +} + +PHP_METHOD(DDTrace_SpanTagsView, getIterator) { + if (zend_parse_parameters_none() == FAILURE) { + return; + } + zval snapshot; + ZVAL_ARR(&snapshot, dd_tags_view_snapshot_ht(Z_OBJ_P(ZEND_THIS))); + object_init_ex(return_value, spl_ce_ArrayIterator); +#if PHP_VERSION_ID >= 80000 + zend_call_method_with_1_params(Z_OBJ_P(return_value), spl_ce_ArrayIterator, &spl_ce_ArrayIterator->constructor, "__construct", NULL, &snapshot); +#else + zend_call_method_with_1_params(return_value, spl_ce_ArrayIterator, &spl_ce_ArrayIterator->constructor, "__construct", NULL, &snapshot); +#endif + zval_ptr_dtor(&snapshot); +} + +#if PHP_VERSION_ID >= 80100 +ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_dd_tags_view_offsetGet, 0, 1, IS_MIXED, 0) + ZEND_ARG_TYPE_INFO(0, offset, IS_MIXED, 0) +ZEND_END_ARG_INFO() +ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_dd_tags_view_offsetSet, 0, 2, IS_VOID, 0) + ZEND_ARG_TYPE_INFO(0, offset, IS_MIXED, 0) + ZEND_ARG_TYPE_INFO(0, value, IS_MIXED, 0) +ZEND_END_ARG_INFO() +ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_dd_tags_view_offsetExists, 0, 1, _IS_BOOL, 0) + ZEND_ARG_TYPE_INFO(0, offset, IS_MIXED, 0) +ZEND_END_ARG_INFO() +ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_dd_tags_view_offsetUnset, 0, 1, IS_VOID, 0) + ZEND_ARG_TYPE_INFO(0, offset, IS_MIXED, 0) +ZEND_END_ARG_INFO() +ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_dd_tags_view_count, 0, 0, IS_LONG, 0) +ZEND_END_ARG_INFO() +ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_OBJ_INFO_EX(arginfo_dd_tags_view_getIterator, 0, 0, Iterator, 0) +ZEND_END_ARG_INFO() +#else +ZEND_BEGIN_ARG_INFO_EX(arginfo_dd_tags_view_offsetGet, 0, 0, 1) + ZEND_ARG_INFO(0, offset) +ZEND_END_ARG_INFO() +ZEND_BEGIN_ARG_INFO_EX(arginfo_dd_tags_view_offsetSet, 0, 0, 2) + ZEND_ARG_INFO(0, offset) + ZEND_ARG_INFO(0, value) +ZEND_END_ARG_INFO() +#define arginfo_dd_tags_view_offsetExists arginfo_dd_tags_view_offsetGet +#define arginfo_dd_tags_view_offsetUnset arginfo_dd_tags_view_offsetGet +ZEND_BEGIN_ARG_INFO_EX(arginfo_dd_tags_view_count, 0, 0, 0) +ZEND_END_ARG_INFO() +#define arginfo_dd_tags_view_getIterator arginfo_dd_tags_view_count +#endif + +static const zend_function_entry dd_span_tags_view_methods[] = { + PHP_ME(DDTrace_SpanTagsView, offsetGet, arginfo_dd_tags_view_offsetGet, ZEND_ACC_PUBLIC) + PHP_ME(DDTrace_SpanTagsView, offsetSet, arginfo_dd_tags_view_offsetSet, ZEND_ACC_PUBLIC) + PHP_ME(DDTrace_SpanTagsView, offsetExists, arginfo_dd_tags_view_offsetExists, ZEND_ACC_PUBLIC) + PHP_ME(DDTrace_SpanTagsView, offsetUnset, arginfo_dd_tags_view_offsetUnset, ZEND_ACC_PUBLIC) + PHP_ME(DDTrace_SpanTagsView, count, arginfo_dd_tags_view_count, ZEND_ACC_PUBLIC) + PHP_ME(DDTrace_SpanTagsView, getIterator, arginfo_dd_tags_view_getIterator, ZEND_ACC_PUBLIC) + PHP_FE_END +}; + +void ddtrace_register_span_tags_view(void) { + zend_class_entry ce; + INIT_NS_CLASS_ENTRY(ce, "DDTrace", "SpanTagsView", dd_span_tags_view_methods); + ddtrace_ce_span_tags_view = zend_register_internal_class(&ce); + ddtrace_ce_span_tags_view->ce_flags |= ZEND_ACC_FINAL; + ddtrace_ce_span_tags_view->create_object = dd_tags_view_create; + zend_class_implements(ddtrace_ce_span_tags_view, 3, zend_ce_arrayaccess, zend_ce_countable, zend_ce_aggregate); + + memcpy(&dd_span_tags_view_handlers, &std_object_handlers, sizeof(zend_object_handlers)); + dd_span_tags_view_handlers.offset = XtOffsetOf(dd_span_tags_view, std); + dd_span_tags_view_handlers.clone_obj = NULL; + dd_span_tags_view_handlers.read_dimension = dd_tags_view_read_dimension; + dd_span_tags_view_handlers.write_dimension = dd_tags_view_write_dimension; + dd_span_tags_view_handlers.has_dimension = dd_tags_view_has_dimension; + dd_span_tags_view_handlers.unset_dimension = dd_tags_view_unset_dimension; + dd_span_tags_view_handlers.count_elements = dd_tags_view_count_elements; +#if PHP_VERSION_ID >= 70400 + dd_span_tags_view_handlers.get_properties_for = dd_tags_view_get_properties_for; +#else + dd_span_tags_view_handlers.get_debug_info = dd_tags_view_get_debug_info; +#endif +} + +/* SpanData property handlers for $meta / $metrics */ + +// Read contexts get an array snapshot (so array functions keep working); write contexts the view. +static zval *dd_span_read_property(DD_OBJ_ARG, DD_MEMBER_ARG, int type, void **cache_slot, zval *rv) { + int bucket = dd_tags_bucket_of(DD_MEMBER); + if (bucket < 0) { + return std_object_handlers.read_property(object, member, type, cache_slot, rv); + } + ddtrace_span_data *span = OBJ_SPANDATA(DD_OBJ); + if (type == BP_VAR_R || type == BP_VAR_IS) { + dd_tags_snapshot(dd_tags_attrs_read(span), bucket, rv); + } else { + ZVAL_OBJ(rv, dd_span_tags_view_get(span, bucket)); + } + return rv; +} + +// NULL keeps the engine off the property slot (and its runtime cache) for $meta/$metrics. +static zval *dd_span_get_property_ptr_ptr(DD_OBJ_ARG, DD_MEMBER_ARG, int type, void **cache_slot) { + if (dd_tags_bucket_of(DD_MEMBER) >= 0) { + return NULL; + } + return std_object_handlers.get_property_ptr_ptr(object, member, type, cache_slot); +} + +static int dd_span_has_property(DD_OBJ_ARG, DD_MEMBER_ARG, int has_set_exists, void **cache_slot) { + int bucket = dd_tags_bucket_of(DD_MEMBER); + if (bucket < 0) { + return std_object_handlers.has_property(object, member, has_set_exists, cache_slot); + } + if (has_set_exists == 1) { // empty() + return dd_tags_count(dd_tags_attrs_read(OBJ_SPANDATA(DD_OBJ)), bucket) > 0; + } + return 1; +} + +static void dd_span_unset_property(DD_OBJ_ARG, DD_MEMBER_ARG, void **cache_slot) { + int bucket = dd_tags_bucket_of(DD_MEMBER); + if (bucket < 0) { + std_object_handlers.unset_property(object, member, cache_slot); + return; + } + dd_tags_replace_bucket(OBJ_SPANDATA(DD_OBJ), bucket, NULL); +} + +bool ddtrace_span_tags_view_write_property(zend_object *obj, zend_string *name, zval *value) { + int bucket = dd_tags_bucket_of(name); + if (bucket < 0) { + return false; + } + ddtrace_span_data *span = OBJ_SPANDATA(obj); + ZVAL_DEREF(value); + if (Z_TYPE_P(value) == IS_ARRAY) { + dd_tags_replace_bucket(span, bucket, Z_ARR_P(value)); + } else if (Z_TYPE_P(value) == IS_NULL) { + dd_tags_replace_bucket(span, bucket, NULL); + } else if (Z_TYPE_P(value) == IS_OBJECT && Z_OBJCE_P(value) == ddtrace_ce_span_tags_view) { + zval snapshot; + ZVAL_ARR(&snapshot, dd_tags_view_snapshot_ht(Z_OBJ_P(value))); + dd_tags_replace_bucket(span, bucket, Z_ARR(snapshot)); + zval_ptr_dtor(&snapshot); + } else { + zend_type_error("Cannot assign %s to property %s::$%s of type array", zend_zval_type_name(value), ZSTR_VAL(obj->ce->name), ZSTR_VAL(name)); + } + return true; +} + +// Properties table with $meta/$metrics replaced by their snapshots. +static zend_array *dd_span_properties_with_tags(zend_object *obj, zend_array *props) { + zend_array *ht = zend_new_array(zend_hash_num_elements(props)); + zend_string *key; + zend_ulong h; + zval *val; + ZEND_HASH_FOREACH_KEY_VAL_IND(props, h, key, val) { + int bucket = key ? dd_tags_bucket_of(key) : -1; + zval copy; + if (bucket >= 0) { + dd_tags_snapshot(dd_tags_attrs_read(OBJ_SPANDATA(obj)), bucket, ©); + } else { + ZVAL_COPY(©, val); + } + if (key) { + zend_hash_add_new(ht, key, ©); + } else { + zend_hash_index_add_new(ht, h, ©); + } + } ZEND_HASH_FOREACH_END(); + return ht; +} + +#if PHP_VERSION_ID >= 70400 +static zend_array *dd_span_get_properties_for(DD_OBJ_ARG, zend_prop_purpose purpose) { + if (purpose == ZEND_PROP_PURPOSE_SERIALIZE) { + return zend_std_get_properties_for(object, purpose); + } + return dd_span_properties_with_tags(DD_OBJ, std_object_handlers.get_properties(object)); +} +#else +static HashTable *dd_span_get_debug_info(zval *object, int *is_temp) { + *is_temp = 1; + return dd_span_properties_with_tags(Z_OBJ_P(object), std_object_handlers.get_properties(object)); +} +#endif + +void ddtrace_span_tags_view_install(zend_object_handlers *handlers) { + handlers->read_property = dd_span_read_property; + handlers->get_property_ptr_ptr = dd_span_get_property_ptr_ptr; + handlers->has_property = dd_span_has_property; + handlers->unset_property = dd_span_unset_property; +#if PHP_VERSION_ID >= 70400 + handlers->get_properties_for = dd_span_get_properties_for; +#else + handlers->get_debug_info = dd_span_get_debug_info; +#endif +} diff --git a/tracer/span_tags_view.h b/tracer/span_tags_view.h new file mode 100644 index 0000000000..1b4e9e0982 --- /dev/null +++ b/tracer/span_tags_view.h @@ -0,0 +1,19 @@ +#ifndef DD_SPAN_TAGS_VIEW_H +#define DD_SPAN_TAGS_VIEW_H + +#include +#include + +#include "span.h" + +// SpanData::$meta / $metrics are views onto SpanData::$attributes: meta holds the non-numeric +// entries, metrics the numeric ones. +extern zend_class_entry *ddtrace_ce_span_tags_view; + +void ddtrace_register_span_tags_view(void); +void ddtrace_span_tags_view_install(zend_object_handlers *handlers); +void ddtrace_span_tags_views_release(ddtrace_span_data *span); +// Handles assignments to $meta/$metrics; false for any other property. +bool ddtrace_span_tags_view_write_property(zend_object *obj, zend_string *name, zval *value); + +#endif // DD_SPAN_TAGS_VIEW_H diff --git a/tracer/trace_filter.c b/tracer/trace_filter.c index 4479a2da53..fc6178a825 100644 --- a/tracer/trace_filter.c +++ b/tracer/trace_filter.c @@ -44,28 +44,30 @@ static const char *ddtrace_root_tag_value(const void *ctx, const char *key, uint CHECK_PROP("resource", property_resource) #undef CHECK_PROP - // Meta hash: string tags. - zend_array *meta = ddtrace_property_array(&root->property_meta); - if (meta) { - zval *val = zend_hash_str_find(meta, key, key_len); - if (val && Z_TYPE_P(val) == IS_STRING) { - *out_len = Z_STRLEN_P(val); - return Z_STRVAL_P(val); + // Attributes: string tags as-is, numbers as stringified floats, bools as on the v0.4 wire. + zval *attr = zend_hash_str_find(ddtrace_property_array(&root->property_attributes), key, key_len); + if (attr) { + ZVAL_DEREF(attr); + switch (Z_TYPE_P(attr)) { + case IS_STRING: + *out_len = Z_STRLEN_P(attr); + return Z_STRVAL_P(attr); + case IS_TRUE: + *out_len = 4; + return "true"; + case IS_FALSE: + *out_len = 5; + return "false"; + case IS_LONG: + case IS_DOUBLE: { + ZEND_TLS char attr_buf[32]; + int len = snprintf(attr_buf, sizeof(attr_buf), "%g", zval_get_double(attr)); + *out_len = (uintptr_t)(len > 0 ? len : 0); + return attr_buf; + } } } - // Metrics hash: numeric tags returned as stringified float. - zend_array *metrics = ddtrace_property_array(&root->property_metrics); - if (metrics) { - zval *val = zend_hash_str_find(metrics, key, key_len); - if (val) { - ZEND_TLS char metric_buf[32]; - double d = zval_get_double(val); - int len = snprintf(metric_buf, sizeof(metric_buf), "%g", d); - *out_len = (uintptr_t)(len > 0 ? len : 0); - return metric_buf; - } - } // Meta struct: key-presence only (value is unrepresentable as a string). zend_array *meta_struct = ddtrace_property_array(&root->property_meta_struct); diff --git a/tracer/trace_source.c b/tracer/trace_source.c index 4873ae766f..994c110490 100644 --- a/tracer/trace_source.c +++ b/tracer/trace_source.c @@ -56,7 +56,7 @@ void ddtrace_trace_source_set_asm_source() { return; } - zend_array *meta = ddtrace_property_array(&root_span->property_meta);; + zend_array *meta = ddtrace_property_array(&root_span->property_attributes); if (!meta) { return; } @@ -66,7 +66,7 @@ void ddtrace_trace_source_set_asm_source() { ddtrace_trace_source_add_propagated_tag(encoded); } -bool ddtrace_trace_source_is_meta_asm_sourced(zend_array *meta) { +bool ddtrace_trace_source_is_meta_asm_sourced(zend_array *meta) { if (!meta) { return false; } diff --git a/tracer/tracer_tag_propagation/tracer_tag_propagation.c b/tracer/tracer_tag_propagation/tracer_tag_propagation.c index 5998d6a64d..c783ce7fcc 100644 --- a/tracer/tracer_tag_propagation/tracer_tag_propagation.c +++ b/tracer/tracer_tag_propagation/tracer_tag_propagation.c @@ -11,11 +11,15 @@ ZEND_EXTERN_MODULE_GLOBALS(datadog); -void ddtrace_clean_tracer_tags(zend_array *root_meta, zend_array *propagated_tags) { +void ddtrace_drop_propagated_tags(zend_array *tags, zend_array *propagated_tags) { zend_string *tagname; ZEND_HASH_FOREACH_STR_KEY(propagated_tags, tagname) { - zend_hash_del(root_meta, tagname); + zend_hash_del(tags, tagname); } ZEND_HASH_FOREACH_END(); +} + +void ddtrace_clean_tracer_tags(zend_array *root_meta, zend_array *propagated_tags) { + ddtrace_drop_propagated_tags(root_meta, propagated_tags); zend_hash_clean(propagated_tags); } @@ -90,16 +94,18 @@ static zend_array *ddtrace_get_propagated() { return propagated; } +// Propagated tag values live in the root span's $attributes (the preset before a root exists). static zend_array *ddtrace_get_root_meta() { zend_array *root_meta = &DDTRACE_G(root_span_tags_preset); ddtrace_root_span_data *root_span = DDTRACE_G(active_stack)->root_span; if (root_span) { - root_meta = ddtrace_property_array(&root_span->property_meta); + root_meta = ddtrace_property_array(&root_span->property_attributes); } return root_meta; } + zval *ddtrace_propagated_tags_get_tag(const char *tag) { if (!tag) { return NULL; diff --git a/tracer/tracer_tag_propagation/tracer_tag_propagation.h b/tracer/tracer_tag_propagation/tracer_tag_propagation.h index a296fbcd29..e27fcd7be8 100644 --- a/tracer/tracer_tag_propagation/tracer_tag_propagation.h +++ b/tracer/tracer_tag_propagation/tracer_tag_propagation.h @@ -5,6 +5,8 @@ #include +// Deletes the values of `propagated_tags` from `tags`, keeping the propagated list. +void ddtrace_drop_propagated_tags(zend_array *tags, zend_array *propagated_tags); void ddtrace_clean_tracer_tags(zend_array *root_meta, zend_array *propagated_tags); void ddtrace_add_tracer_tags_from_header(zend_string *headerstr, zend_array *root_meta, zend_array *propagated_tags); void ddtrace_add_tracer_tags_from_array(zend_array *array, zend_array *root_meta, zend_array *propagated_tags); diff --git a/tracer/tracer_telemetry.c b/tracer/tracer_telemetry.c index eea6724ef1..b95846c5ef 100644 --- a/tracer/tracer_telemetry.c +++ b/tracer/tracer_telemetry.c @@ -191,13 +191,19 @@ void ddtrace_telemetry_notify_integration_version(const char *name, size_t name_ } void ddtrace_telemetry_inc_spans_created(ddtrace_span_data *span) { + // Prefer the $span->component property; the tag mirror only happens later at serialization, + // so fall back to the "component" tag for spans (e.g. userland integrations) that set it directly. + zval *component_prop = &span->property_component; + ZVAL_DEREF(component_prop); zval *component = NULL; - if (Z_TYPE(span->property_meta) == IS_ARRAY) { - component = zend_hash_str_find(Z_ARRVAL(span->property_meta), ZEND_STRL("component")); + if (!(Z_TYPE_P(component_prop) == IS_STRING && Z_STRLEN_P(component_prop) > 0)) { + component = ddtrace_span_find_tag(span, ZEND_STRL("component")); } zend_string *integration = NULL; - if (component && Z_TYPE_P(component) == IS_STRING) { + if (Z_TYPE_P(component_prop) == IS_STRING && Z_STRLEN_P(component_prop) > 0) { + integration = zend_string_copy(Z_STR_P(component_prop)); + } else if (component && Z_TYPE_P(component) == IS_STRING) { integration = zend_string_copy(Z_STR_P(component)); } else if (span->flags & DDTRACE_SPAN_FLAG_OPENTELEMETRY) { integration = zend_string_init(ZEND_STRL("otel"), 0); From e6fde00a4b689f8d7627b0cdeca144900558fc4c Mon Sep 17 00:00:00 2001 From: Alexandre Rulleau Date: Thu, 1 Oct 2026 18:01:48 +0200 Subject: [PATCH 2/5] refactor(integrations): write span tags through the attributes store Use typed SpanData::$attributes and the promoted env/version/component/span_kind properties instead of $meta/$metrics string conversions in the userland integrations and the OpenTelemetry bridge. Drop the userland App Analytics plumbing (addTraceAnalyticsIfEnabled, requiresExplicitTraceAnalyticsEnabling, markForTraceAnalytics and the per-integration candidates). TraceAnalyticsProcessor::normalizeAnalyticsValue and Tag::ANALYTICS_KEY are now deprecated no-ops; the serializer still maps an analytics.event tag to _dd1.sr.eausr. --- .../Integrations/AMQP/AMQPIntegration.php | 2 +- .../CakePHP/CakePHPIntegration.php | 13 +------ .../CakePHP/V2/CakePHPIntegrationLoader.php | 4 +- .../CakePHP/V3/CakePHPIntegrationLoader.php | 4 +- .../CodeIgniter/V2/CodeIgniterIntegration.php | 9 ++--- .../Integrations/Curl/CurlIntegration.php | 3 +- .../DatabaseIntegrationHelper.php | 4 +- .../Integrations/Drupal/DrupalIntegration.php | 12 +----- .../V1/ElasticSearchIntegration.php | 29 ++++++-------- .../V8/ElasticSearchIntegration.php | 1 - .../Integrations/Exec/ExecIntegration.php | 19 +++++----- .../Frankenphp/FrankenphpIntegration.php | 13 +------ .../GoogleSpannerIntegration.php | 8 ---- .../Integrations/Guzzle/GuzzleIntegration.php | 4 +- src/DDTrace/Integrations/Integration.php | 38 ++++++------------- .../Laminas/LaminasIntegration.php | 16 ++++---- .../Laravel/LaravelIntegration.php | 31 +++++---------- .../Integrations/Lumen/LumenIntegration.php | 20 +++------- .../Magento/MagentoIntegration.php | 2 +- .../Memcache/MemcacheIntegration.php | 18 --------- .../Memcached/MemcachedIntegration.php | 26 ------------- .../Integrations/Mongo/MongoIntegration.php | 16 ++------ .../MongoDB/MongoDBIntegration.php | 1 - .../Integrations/Mysqli/MysqliIntegration.php | 9 +---- .../Integrations/Nette/NetteIntegration.php | 15 ++------ .../Integrations/PDO/PDOIntegration.php | 5 +-- .../PHPRedis/PHPRedisIntegration.php | 6 +-- .../Integrations/Predis/PredisIntegration.php | 2 - .../Integrations/Psr18/Psr18Integration.php | 2 +- .../Ratchet/RatchetIntegration.php | 28 ++++++-------- .../Roadrunner/RoadrunnerIntegration.php | 11 +----- .../Integrations/SQLSRV/SQLSRVIntegration.php | 4 +- .../Integrations/Slim/SlimIntegration.php | 7 ++-- .../Integrations/Swoole/SwooleIntegration.php | 28 +++++--------- .../Symfony/SymfonyIntegration.php | 26 ++++--------- .../WordPress/WordPressIntegration.php | 8 ---- .../WordPress/WordPressIntegrationLoader.php | 7 ++-- .../Integrations/Yii/YiiIntegration.php | 13 +------ .../ZendFramework/V1/TraceRequest.php | 12 +++--- .../ZendFrameworkIntegration.php | 17 ++------- src/DDTrace/OpenTelemetry/Context.php | 6 ++- src/DDTrace/OpenTelemetry/Convention.php | 2 +- src/DDTrace/OpenTelemetry/Span.php | 19 ++++------ .../Processing/TraceAnalyticsProcessor.php | 24 ++++-------- src/DDTrace/Span.php | 23 +++++------ src/api/GlobalTracer.php | 3 ++ src/api/Tag.php | 1 + src/ddtrace_php_api.stubs.php | 9 +++-- 48 files changed, 182 insertions(+), 398 deletions(-) diff --git a/src/DDTrace/Integrations/AMQP/AMQPIntegration.php b/src/DDTrace/Integrations/AMQP/AMQPIntegration.php index 4a6c8a9561..7e5861d9fd 100644 --- a/src/DDTrace/Integrations/AMQP/AMQPIntegration.php +++ b/src/DDTrace/Integrations/AMQP/AMQPIntegration.php @@ -491,7 +491,7 @@ public static function setGenericTags( $span->meta[Tag::SPAN_KIND] = $spanKind; $span->type = 'queue'; $span->service = 'amqp'; - $span->meta['_dd.svc_src'] = AMQPIntegration::NAME; + $span->attributes['_dd.svc_src'] = AMQPIntegration::NAME; $span->meta[Tag::COMPONENT] = self::NAME; $span->meta[Tag::MQ_SYSTEM] = self::SYSTEM; diff --git a/src/DDTrace/Integrations/CakePHP/CakePHPIntegration.php b/src/DDTrace/Integrations/CakePHP/CakePHPIntegration.php index 9adf769112..4ea4702751 100644 --- a/src/DDTrace/Integrations/CakePHP/CakePHPIntegration.php +++ b/src/DDTrace/Integrations/CakePHP/CakePHPIntegration.php @@ -18,14 +18,6 @@ class CakePHPIntegration extends Integration public static $setStatusCodeFn; public static $parseRouteFn; - /** - * {@inheritdoc} - */ - public static function requiresExplicitTraceAnalyticsEnabling(): bool - { - return false; - } - public static function init(): int { self::$setRootSpanInfoFn = static function () { @@ -35,7 +27,6 @@ public static function init(): int } self::$appName = \ddtrace_config_app_name(CakePHPIntegration::NAME); - self::addTraceAnalyticsIfEnabled($rootSpan); $rootSpan->service = self::$appName; Integration::tagFrameworkServiceSource($rootSpan, CakePHPIntegration::NAME); if ('cli' === PHP_SAPI) { @@ -45,7 +36,7 @@ public static function init(): int : 'cake_console'; } else { $rootSpan->name = 'cakephp.request'; - $rootSpan->meta[Tag::SPAN_KIND] = 'server'; + $rootSpan->attributes[Tag::SPAN_KIND] = 'server'; } $rootSpan->meta[Tag::COMPONENT] = CakePHPIntegration::NAME; }; @@ -60,7 +51,7 @@ public static function init(): int self::$setStatusCodeFn = static function ($This, $scope, $args, $retval) { $rootSpan = \DDTrace\root_span(); if ($rootSpan) { - $rootSpan->meta[Tag::HTTP_STATUS_CODE] = $retval; + $rootSpan->attributes[Tag::HTTP_STATUS_CODE] = $retval; } }; diff --git a/src/DDTrace/Integrations/CakePHP/V2/CakePHPIntegrationLoader.php b/src/DDTrace/Integrations/CakePHP/V2/CakePHPIntegrationLoader.php index 0d6b6744ae..732030ae3e 100644 --- a/src/DDTrace/Integrations/CakePHP/V2/CakePHPIntegrationLoader.php +++ b/src/DDTrace/Integrations/CakePHP/V2/CakePHPIntegrationLoader.php @@ -43,8 +43,8 @@ function (SpanData $span, array $args) { $_SERVER['REQUEST_METHOD'] . ' ' . $this->name . 'Controller@' . $request->params['action']; } - if (!array_key_exists(Tag::HTTP_URL, $rootSpan->meta)) { - $rootSpan->meta[Tag::HTTP_URL] = Router::url($request->here, true) + if (!Integration::hasTag($rootSpan, Tag::HTTP_URL)) { + $rootSpan->attributes[Tag::HTTP_URL] = Router::url($request->here, true) . Normalizer::sanitizedQueryString(); } $rootSpan->meta['cakephp.route.controller'] = $request->params['controller']; diff --git a/src/DDTrace/Integrations/CakePHP/V3/CakePHPIntegrationLoader.php b/src/DDTrace/Integrations/CakePHP/V3/CakePHPIntegrationLoader.php index 77a681baf4..acb36e83ae 100644 --- a/src/DDTrace/Integrations/CakePHP/V3/CakePHPIntegrationLoader.php +++ b/src/DDTrace/Integrations/CakePHP/V3/CakePHPIntegrationLoader.php @@ -40,8 +40,8 @@ function (SpanData $span) { $_SERVER['REQUEST_METHOD'] . ' ' . $this->name . 'Controller@' . $request->getParam('action'); } - if (!array_key_exists(Tag::HTTP_URL, $rootSpan->meta)) { - $rootSpan->meta[Tag::HTTP_URL] = Router::url($request->getAttribute('here'), true) + if (!Integration::hasTag($rootSpan, Tag::HTTP_URL)) { + $rootSpan->attributes[Tag::HTTP_URL] = Router::url($request->getAttribute('here'), true) . Normalizer::sanitizedQueryString(); } $rootSpan->meta['cakephp.route.controller'] = $request->getParam('controller'); diff --git a/src/DDTrace/Integrations/CodeIgniter/V2/CodeIgniterIntegration.php b/src/DDTrace/Integrations/CodeIgniter/V2/CodeIgniterIntegration.php index 15c8f684f6..c92a90f137 100644 --- a/src/DDTrace/Integrations/CodeIgniter/V2/CodeIgniterIntegration.php +++ b/src/DDTrace/Integrations/CodeIgniter/V2/CodeIgniterIntegration.php @@ -39,11 +39,10 @@ public static function init($router = null): int public static function registerIntegration(\CI_Router $router, SpanData $rootSpan, $service) { - self::addTraceAnalyticsIfEnabled($rootSpan); $rootSpan->name = 'codeigniter.request'; $rootSpan->service = $service; $rootSpan->type = Type::WEB_SERVLET; - $rootSpan->meta[Tag::SPAN_KIND] = 'server'; + $rootSpan->attributes[Tag::SPAN_KIND] = 'server'; $rootSpan->meta[Tag::COMPONENT] = self::NAME; $controller = $router->fetch_class(); @@ -64,8 +63,8 @@ function (SpanData $span) use ($rootSpan, $method, $service) { if (property_exists($this, 'load') && $this->load && \method_exists($this->load, 'helper')) { $this->load->helper('url'); - if (!array_key_exists(Tag::HTTP_URL, $rootSpan->meta)) { - $rootSpan->meta[Tag::HTTP_URL] = \DDTrace\Util\Normalizer::urlSanitize(base_url(uri_string())) + if (!Integration::hasTag($rootSpan, Tag::HTTP_URL)) { + $rootSpan->attributes[Tag::HTTP_URL] = \DDTrace\Util\Normalizer::urlSanitize(base_url(uri_string())) . Normalizer::sanitizedQueryString(); } $rootSpan->meta['app.endpoint'] = "{$class}::{$method}"; @@ -97,7 +96,7 @@ function (SpanData $span, $args, $retval, $ex) use ($rootSpan, $service) { if ($this->load && \method_exists($this->load, 'helper')) { $this->load->helper('url'); - $rootSpan->meta[Tag::HTTP_URL] = \DDTrace\Util\Normalizer::urlSanitize(base_url(uri_string())) + $rootSpan->attributes[Tag::HTTP_URL] = \DDTrace\Util\Normalizer::urlSanitize(base_url(uri_string())) . Normalizer::sanitizedQueryString(); $rootSpan->meta['app.endpoint'] = "{$class}::_remap"; } diff --git a/src/DDTrace/Integrations/Curl/CurlIntegration.php b/src/DDTrace/Integrations/Curl/CurlIntegration.php index e9880db186..d4aba6ee82 100644 --- a/src/DDTrace/Integrations/Curl/CurlIntegration.php +++ b/src/DDTrace/Integrations/Curl/CurlIntegration.php @@ -294,7 +294,6 @@ public static function setup_curl_span($span) { $span->type = Type::HTTP_CLIENT; $span->service = 'curl'; Integration::handleInternalSpanServiceName($span, self::NAME); - self::addTraceAnalyticsIfEnabled($span); $span->meta[Tag::COMPONENT] = self::NAME; $span->meta[Tag::SPAN_KIND] = Tag::SPAN_KIND_VALUE_CLIENT; } @@ -308,7 +307,7 @@ public static function set_curl_attributes($span, $info) { if (\dd_trace_env_config("DD_TRACE_HTTP_CLIENT_SPLIT_BY_DOMAIN")) { $span->service = Urls::hostnameForTag($sanitizedUrl); - $span->meta['_dd.svc_src'] = 'opt.http_client_split_by_domain'; + $span->attributes['_dd.svc_src'] = 'opt.http_client_split_by_domain'; } $span->resource = $normalizedPath; diff --git a/src/DDTrace/Integrations/DatabaseIntegrationHelper.php b/src/DDTrace/Integrations/DatabaseIntegrationHelper.php index 2362f063f6..dad6770346 100644 --- a/src/DDTrace/Integrations/DatabaseIntegrationHelper.php +++ b/src/DDTrace/Integrations/DatabaseIntegrationHelper.php @@ -98,7 +98,7 @@ public static function propagateViaSqlComments( $tags["dddbs"] = $databaseService; } - $env = $rootSpan->meta["env"] ?? $rootSpan->env ?? ""; + $env = $rootSpan->attributes["env"] ?? $rootSpan->meta["env"] ?? $rootSpan->env ?? ""; if ($env == "") { $env = ini_get("datadog.env"); } @@ -126,7 +126,7 @@ public static function propagateViaSqlComments( $tags["ddps"] = $service; } - $version = $rootSpan->meta["version"] ?? $rootSpan->version ?? ""; + $version = $rootSpan->attributes["version"] ?? $rootSpan->meta["version"] ?? $rootSpan->version ?? ""; if ($version == "") { $version = ini_get("datadog.version"); } diff --git a/src/DDTrace/Integrations/Drupal/DrupalIntegration.php b/src/DDTrace/Integrations/Drupal/DrupalIntegration.php index 76b5786142..cd4f1423fa 100644 --- a/src/DDTrace/Integrations/Drupal/DrupalIntegration.php +++ b/src/DDTrace/Integrations/Drupal/DrupalIntegration.php @@ -20,14 +20,6 @@ class DrupalIntegration extends Integration { const NAME = 'drupal'; - /** - * {@inheritdoc} - */ - public static function requiresExplicitTraceAnalyticsEnabling(): bool - { - return false; - } - public static function init(): int { ini_set('datadog.trace.spans_limit', max(1500, ini_get('datadog.trace.spans_limit'))); @@ -45,14 +37,14 @@ public static function init(): int $rootSpan->name = 'drupal.request'; $rootSpan->service = $service; Integration::tagFrameworkServiceSource($rootSpan, 'drupal'); - $rootSpan->meta[Tag::SPAN_KIND] = 'server'; + $rootSpan->attributes[Tag::SPAN_KIND] = 'server'; $rootSpan->meta[Tag::COMPONENT] = self::NAME; $span->name = 'drupal.kernel.handle'; $span->type = Type::WEB_SERVLET; $span->service = $service; Integration::tagFrameworkServiceSource($span, 'drupal'); - $span->meta[Tag::SPAN_KIND] = 'server'; + $span->attributes[Tag::SPAN_KIND] = 'server'; $span->meta[Tag::COMPONENT] = self::NAME; } ] diff --git a/src/DDTrace/Integrations/ElasticSearch/V1/ElasticSearchIntegration.php b/src/DDTrace/Integrations/ElasticSearch/V1/ElasticSearchIntegration.php index aead9d43e2..2e9d95c090 100644 --- a/src/DDTrace/Integrations/ElasticSearch/V1/ElasticSearchIntegration.php +++ b/src/DDTrace/Integrations/ElasticSearch/V1/ElasticSearchIntegration.php @@ -56,16 +56,16 @@ public static function init(): int self::traceClientMethod('existsScource'); self::traceClientMethod('explain'); self::traceClientMethod('fieldCaps'); - self::traceClientMethod('get', true); + self::traceClientMethod('get'); self::traceClientMethod('getScript'); self::traceClientMethod('getScriptContext'); self::traceClientMethod('getScriptLanguages'); self::traceClientMethod('getSource'); self::traceClientMethod('index'); - self::traceClientMethod('knnSearch', true); - self::traceClientMethod('mget', true); - self::traceClientMethod('msearch', true); - self::traceClientMethod('msearchTemplate', true); + self::traceClientMethod('knnSearch'); + self::traceClientMethod('mget'); + self::traceClientMethod('msearch'); + self::traceClientMethod('msearchTemplate'); self::traceClientMethod('mtermvectors'); self::traceClientMethod('openPointInTime'); self::traceClientMethod('ping'); @@ -76,11 +76,11 @@ public static function init(): int self::traceClientMethod('renderSearchTemplate'); self::traceClientMethod('scriptsPainlessExecute'); self::traceClientMethod('scroll'); - self::traceClientMethod('search', true); - self::traceClientMethod('searchMvt', true); - self::traceClientMethod('searchShards', true); - self::traceClientMethod('searchTemplate', true); - self::traceClientMethod('termsEnum', true); + self::traceClientMethod('search'); + self::traceClientMethod('searchMvt'); + self::traceClientMethod('searchShards'); + self::traceClientMethod('searchTemplate'); + self::traceClientMethod('termsEnum'); self::traceClientMethod('termvectors'); self::traceClientMethod('update'); self::traceClientMethod('updateByQuery'); @@ -136,9 +136,8 @@ public static function init(): int } /** * @param string $name - * @param bool $isTraceAnalyticsCandidate */ - public static function traceClientMethod($name, $isTraceAnalyticsCandidate = false) + public static function traceClientMethod($name) { $class = 'Elasticsearch\Client'; @@ -152,13 +151,9 @@ public static function traceClientMethod($name, $isTraceAnalyticsCandidate = fal $class, $name, [ - 'prehook' => static function (SpanData $span, $args) use ($name, $isTraceAnalyticsCandidate) { + 'prehook' => static function (SpanData $span, $args) use ($name) { $span->name = "Elasticsearch.Client.$name"; - if ($isTraceAnalyticsCandidate) { - self::addTraceAnalyticsIfEnabled($span); - } - $span->meta[Tag::SPAN_KIND] = 'client'; Integration::handleInternalSpanServiceName($span, self::NAME); $span->type = Type::ELASTICSEARCH; diff --git a/src/DDTrace/Integrations/ElasticSearch/V8/ElasticSearchIntegration.php b/src/DDTrace/Integrations/ElasticSearch/V8/ElasticSearchIntegration.php index 46ba22ca83..bd9eeff386 100644 --- a/src/DDTrace/Integrations/ElasticSearch/V8/ElasticSearchIntegration.php +++ b/src/DDTrace/Integrations/ElasticSearch/V8/ElasticSearchIntegration.php @@ -132,7 +132,6 @@ public static function traceClientMethod($name, $isTraceAnalyticsCandidate = fal $span->name = "Elasticsearch.Client.$name"; if ($isTraceAnalyticsCandidate) { - self::addTraceAnalyticsIfEnabled($span); self::$logNextBody = true; } diff --git a/src/DDTrace/Integrations/Exec/ExecIntegration.php b/src/DDTrace/Integrations/Exec/ExecIntegration.php index 17630f1801..6d94c16412 100644 --- a/src/DDTrace/Integrations/Exec/ExecIntegration.php +++ b/src/DDTrace/Integrations/Exec/ExecIntegration.php @@ -60,7 +60,7 @@ static function (HookData $hook) { if ($hook->exception) { $span->exception = $hook->exception; } elseif (!is_resource($hook->returned)) { - $span->meta[Tag::ERROR_MSG] = 'popen() did not return a resource'; + $span->attributes[Tag::ERROR_MSG] = 'popen() did not return a resource'; } else { register_stream($hook->returned, $span); } @@ -121,7 +121,7 @@ static function (HookData $hook) { if ($hook->exception) { $span->exception = $hook->exception; } elseif (!is_resource($hook->returned)) { - $span->meta[Tag::ERROR_MSG] = 'proc_open() did not return a resource'; + $span->attributes[Tag::ERROR_MSG] = 'proc_open() did not return a resource'; } else { proc_assoc_span($hook->returned, $span); } @@ -155,10 +155,10 @@ static function (HookData $hook) { } if ($hook->returned['signaled']) { - $span->meta[Tag::ERROR_MSG] = 'The process was terminated by a signal'; - $span->meta[Tag::EXEC_EXIT_CODE] = $hook->returned['termsig']; + $span->attributes[Tag::ERROR_MSG] = 'The process was terminated by a signal'; + $span->attributes[Tag::EXEC_EXIT_CODE] = (string)$hook->returned['termsig']; } else { - $span->meta[Tag::EXEC_EXIT_CODE] = $hook->returned['exitcode']; + $span->attributes[Tag::EXEC_EXIT_CODE] = (string)$hook->returned['exitcode']; } self::finishSpanRestoreStack($span); @@ -195,8 +195,9 @@ static function (HookData $hook) { return; } - if ($hook->returned === -1 && isset($span->meta[Tag::EXEC_EXIT_CODE])) { - $hook->overrideReturnValue($span->meta[Tag::EXEC_EXIT_CODE]); + $exitCode = $span->attributes[Tag::EXEC_EXIT_CODE] ?? null; + if ($hook->returned === -1 && $exitCode !== null) { + $hook->overrideReturnValue((int)$exitCode); } } ); @@ -259,13 +260,13 @@ private static function postHookShell($variant) if ($hook->exception) { $span->exception = $hook->exception; } elseif ($hook->returned === false) { - $span->meta[Tag::ERROR_MSG] = "$variant() returned false"; + $span->attributes[Tag::ERROR_MSG] = "$variant() returned false"; } elseif ( !empty($retCodeArg) && isset($hook->args[$retCodeArg]) && $hook->args[$retCodeArg] !== null ) { - $span->meta[Tag::EXEC_EXIT_CODE] = $hook->args[$retCodeArg]; + $span->attributes[Tag::EXEC_EXIT_CODE] = (string)$hook->args[$retCodeArg]; } self::finishSpanRestoreStack($span); diff --git a/src/DDTrace/Integrations/Frankenphp/FrankenphpIntegration.php b/src/DDTrace/Integrations/Frankenphp/FrankenphpIntegration.php index 74fb17c218..17753f0d51 100644 --- a/src/DDTrace/Integrations/Frankenphp/FrankenphpIntegration.php +++ b/src/DDTrace/Integrations/Frankenphp/FrankenphpIntegration.php @@ -19,14 +19,6 @@ class FrankenphpIntegration extends Integration public static $is_hooked; - /** - * {@inheritdoc} - */ - public static function requiresExplicitTraceAnalyticsEnabling(): bool - { - return false; - } - public static function init(): int { ini_set("datadog.trace.auto_flush_enabled", 1); @@ -54,9 +46,8 @@ static function (HookData $hook) use (&$blockingException, &$rootSpan) { Integration::tagFrameworkServiceSource($rootSpan, self::NAME); $rootSpan->type = Type::WEB_SERVLET; $rootSpan->meta[Tag::COMPONENT] = self::NAME; - $rootSpan->meta[Tag::SPAN_KIND] = Tag::SPAN_KIND_VALUE_SERVER; - unset($rootSpan->meta["closure.declaration"]); - self::addTraceAnalyticsIfEnabled($rootSpan); + $rootSpan->attributes[Tag::SPAN_KIND] = Tag::SPAN_KIND_VALUE_SERVER; + unset($rootSpan->attributes["closure.declaration"]); consume_distributed_tracing_headers(null); diff --git a/src/DDTrace/Integrations/GoogleSpanner/GoogleSpannerIntegration.php b/src/DDTrace/Integrations/GoogleSpanner/GoogleSpannerIntegration.php index afa11fb83d..1d73d6f1bf 100644 --- a/src/DDTrace/Integrations/GoogleSpanner/GoogleSpannerIntegration.php +++ b/src/DDTrace/Integrations/GoogleSpanner/GoogleSpannerIntegration.php @@ -23,7 +23,6 @@ public static function init(): int $span->meta[Tag::DB_INSTANCE] = $instanceName; GoogleSpannerIntegration::setDefaultAttributes($span, 'google_spanner.instance', $args[0]); ObjectKVStore::put($this, GoogleSpannerIntegration::KEY_INSTANCE_NAME, $instanceName); - GoogleSpannerIntegration::addTraceAnalyticsIfEnabled($span); }); \DDTrace\trace_method('Google\Cloud\Spanner\Instance', 'database', function (SpanData $span, $args) { @@ -31,38 +30,31 @@ public static function init(): int $span->meta[Tag::DB_NAME] = $dbName; GoogleSpannerIntegration::setDefaultAttributes($span, 'google_spanner.database', $args[0]); ObjectKVStore::put($this, GoogleSpannerIntegration::KEY_DATABASE_NAME, $dbName); - GoogleSpannerIntegration::addTraceAnalyticsIfEnabled($span); }); \DDTrace\trace_method('Google\Cloud\Spanner\Database', 'execute', function (SpanData $span, $args) { $span->meta[Tag::DB_NAME] = $this->name(); GoogleSpannerIntegration::setDefaultAttributes($span, 'google_spanner.execute', $args[0]); - GoogleSpannerIntegration::addTraceAnalyticsIfEnabled($span); }); \DDTrace\trace_method('Google\Cloud\Spanner\Database', 'runTransaction', static function (SpanData $span, $args) { self::setDefaultAttributes($span, 'google_spanner.run_transaction', 'transaction'); - self::addTraceAnalyticsIfEnabled($span); }); \DDTrace\trace_method('Google\Cloud\Spanner\Database', 'transaction', static function (SpanData $span, $args) { self::setDefaultAttributes($span, 'google_spanner.transaction', 'transaction'); - self::addTraceAnalyticsIfEnabled($span); }); \DDTrace\trace_method('Google\Cloud\Spanner\Transaction', 'commit', static function (SpanData $span) { self::setDefaultAttributes($span, 'google_spanner.commit', "commit"); - self::addTraceAnalyticsIfEnabled($span); }); \DDTrace\trace_method('Google\Cloud\Spanner\Transaction', 'executeUpdate', static function (SpanData $span, $args) { self::setDefaultAttributes($span, 'google_spanner.execute_update', $args[0]); - self::addTraceAnalyticsIfEnabled($span); }); \DDTrace\trace_method('Google\Cloud\Spanner\Transaction', 'executeUpdateBatch', static function (SpanData $span) { self::setDefaultAttributes($span, 'google_spanner.execute_update_batch', 'execute_update_batch'); - self::addTraceAnalyticsIfEnabled($span); }); return Integration::LOADED; diff --git a/src/DDTrace/Integrations/Guzzle/GuzzleIntegration.php b/src/DDTrace/Integrations/Guzzle/GuzzleIntegration.php index 5dbfcbf2e8..3618f33e65 100644 --- a/src/DDTrace/Integrations/Guzzle/GuzzleIntegration.php +++ b/src/DDTrace/Integrations/Guzzle/GuzzleIntegration.php @@ -144,7 +144,7 @@ public static function addRequestInfo(SpanData $span, $request) if (\dd_trace_env_config("DD_TRACE_HTTP_CLIENT_SPLIT_BY_DOMAIN")) { $span->service = Urls::hostnameForTag($url); - $span->meta['_dd.svc_src'] = 'opt.http_client_split_by_domain'; + $span->attributes['_dd.svc_src'] = 'opt.http_client_split_by_domain'; } $span->meta[Tag::HTTP_METHOD] = $request->getMethod(); @@ -159,7 +159,7 @@ public static function addRequestInfo(SpanData $span, $request) } if (\dd_trace_env_config("DD_TRACE_HTTP_CLIENT_SPLIT_BY_DOMAIN")) { $span->service = Urls::hostnameForTag($url); - $span->meta['_dd.svc_src'] = 'opt.http_client_split_by_domain'; + $span->attributes['_dd.svc_src'] = 'opt.http_client_split_by_domain'; } $span->meta[Tag::HTTP_METHOD] = $request->getMethod(); diff --git a/src/DDTrace/Integrations/Integration.php b/src/DDTrace/Integrations/Integration.php index 2fe53f82c2..61c06f7946 100644 --- a/src/DDTrace/Integrations/Integration.php +++ b/src/DDTrace/Integrations/Integration.php @@ -16,25 +16,6 @@ public static function getName(): string return static::NAME; } - public static function addTraceAnalyticsIfEnabled(SpanData $span) - { - $name = static::NAME; - if (\DDTrace\Config\integration_analytics_enabled($name) - || (!static::requiresExplicitTraceAnalyticsEnabling() && \dd_trace_env_config("DD_TRACE_ANALYTICS_ENABLED"))) { - $span->metrics[Tag::ANALYTICS_KEY] = \DDTrace\Config\integration_analytics_sample_rate($name); - } - } - - /** - * Whether this integration trace analytics configuration is not enabled when DD_TRACE_ANALYTICS_ENABLED=1 is specified. - * - * Trace Analytics are generally enabled by default for top-level integrations, i.e. frameworks and webservers. - */ - public static function requiresExplicitTraceAnalyticsEnabling(): bool - { - return true; - } - /** * Tells whether the provided integration should be loaded. */ @@ -94,22 +75,27 @@ public static function handleInternalSpanServiceName(SpanData $span, string $fal $service = $mapping[$service]; } $span->service = $service; - unset($span->meta['_dd.svc_src']); + unset($span->attributes['_dd.svc_src']); if ($flatServiceNames) { - if ($rootSpan && isset($rootSpan->meta['_dd.svc_src'])) { - $span->meta['_dd.svc_src'] = $rootSpan->meta['_dd.svc_src']; + if ($rootSpan && isset($rootSpan->attributes['_dd.svc_src'])) { + $span->attributes['_dd.svc_src'] = $rootSpan->attributes['_dd.svc_src']; } } else { - $span->meta['_dd.svc_src'] = $fallbackName; + $span->attributes['_dd.svc_src'] = $fallbackName; } } + public static function hasTag(SpanData $span, $key) + { + return array_key_exists($key, $span->attributes); + } + public static function tagFrameworkServiceSource(SpanData $span, $integrationName) { if (\dd_trace_env_config('DD_SERVICE')) { - unset($span->meta['_dd.svc_src']); + unset($span->attributes['_dd.svc_src']); } else { - $span->meta['_dd.svc_src'] = $integrationName; + $span->attributes['_dd.svc_src'] = $integrationName; } } @@ -121,7 +107,7 @@ public static function setComponentMetadata(SpanData $span, $component, $service { if (!\dd_trace_env_config('DD_SERVICE')) { $span->service = $service ?? $component; - $span->meta['_dd.svc_src'] = $component; + $span->attributes['_dd.svc_src'] = $component; } $span->meta[Tag::COMPONENT] = $component; } diff --git a/src/DDTrace/Integrations/Laminas/LaminasIntegration.php b/src/DDTrace/Integrations/Laminas/LaminasIntegration.php index 8f72520fd4..d148f4af9d 100644 --- a/src/DDTrace/Integrations/Laminas/LaminasIntegration.php +++ b/src/DDTrace/Integrations/Laminas/LaminasIntegration.php @@ -177,7 +177,7 @@ static function (SpanData $span) { $rootSpan->name = 'laminas.request'; $rootSpan->service = \ddtrace_config_app_name('laminas'); Integration::tagFrameworkServiceSource($rootSpan, 'laminas'); - $rootSpan->meta[Tag::SPAN_KIND] = 'server'; + $rootSpan->attributes[Tag::SPAN_KIND] = 'server'; $rootSpan->meta[Tag::COMPONENT] = self::NAME; } ); @@ -238,9 +238,9 @@ function (SpanData $span, $args, $retval) { $request = $args[0]; $rootSpan = root_span(); - $rootSpan->meta[Tag::HTTP_METHOD] = $request->getMethod(); + $rootSpan->attributes[Tag::HTTP_METHOD] = $request->getMethod(); $rootSpan->meta[Tag::HTTP_VERSION] = $request->getVersion(); - $rootSpan->meta[Tag::HTTP_URL] = Normalizer::urlSanitize($request->getUriString()); + $rootSpan->attributes[Tag::HTTP_URL] = Normalizer::urlSanitize($request->getUriString()); $routeMatch = $retval; if (is_null($routeMatch)) { @@ -342,7 +342,7 @@ static function ($This, $scope, $args) { $rootSpan = root_span(); if ($rootSpan !== null) { $statusCode = $args[0]; - $rootSpan->meta[Tag::HTTP_STATUS_CODE] = "$statusCode"; + $rootSpan->attributes[Tag::HTTP_STATUS_CODE] = "$statusCode"; } } ); @@ -396,8 +396,8 @@ static function (SpanData $span, $args) { $method = $request->getMethod(); $rootSpan = root_span(); - $rootSpan->meta[Tag::HTTP_METHOD] = $method; - $rootSpan->meta[Tag::HTTP_URL] = Normalizer::urlSanitize($request->getUriString()); + $rootSpan->attributes[Tag::HTTP_METHOD] = $method; + $rootSpan->attributes[Tag::HTTP_URL] = Normalizer::urlSanitize($request->getUriString()); } ); @@ -589,7 +589,7 @@ static function (HookData $hook) { $detail = $args[1] ?? null; $activeSpan = active_span(); if ($detail instanceof \Throwable || $detail instanceof \Exception) { - if ($activeSpan !== null && !isset($activeSpan->meta[Tag::ERROR_TYPE])) { + if ($activeSpan !== null && !Integration::hasTag($activeSpan, Tag::ERROR_TYPE)) { $activeSpan->exception = $detail; } } elseif (is_string($detail)) { @@ -601,7 +601,7 @@ static function (HookData $hook) { ObjectKVStore::put($hook->instance, 'backtrace', $backtrace); - if ($activeSpan !== null && !isset($activeSpan->meta[Tag::ERROR_TYPE])) { + if ($activeSpan !== null && !Integration::hasTag($activeSpan, Tag::ERROR_TYPE)) { $activeSpan->meta[Tag::ERROR_TYPE] = 'ApiProblem'; $activeSpan->meta[Tag::ERROR_MSG] = $detail; $activeSpan->meta[Tag::ERROR_STACK] = $backtrace; diff --git a/src/DDTrace/Integrations/Laravel/LaravelIntegration.php b/src/DDTrace/Integrations/Laravel/LaravelIntegration.php index bfbf6815a3..aaa393a993 100644 --- a/src/DDTrace/Integrations/Laravel/LaravelIntegration.php +++ b/src/DDTrace/Integrations/Laravel/LaravelIntegration.php @@ -23,14 +23,6 @@ class LaravelIntegration extends Integration */ public static $serviceName; - /** - * {@inheritdoc} - */ - public static function requiresExplicitTraceAnalyticsEnabling(): bool - { - return false; - } - public static function isArtisanQueueCommand(): bool { $artisanCommand = isset($_SERVER['argv'][1]) ? $_SERVER['argv'][1] : ''; @@ -69,13 +61,12 @@ static function (SpanData $span, $args, $response) { // Overwriting the default web integration $rootSpan->name = 'laravel.request'; - self::addTraceAnalyticsIfEnabled($rootSpan); if (\method_exists($response, 'getStatusCode')) { - $rootSpan->meta[Tag::HTTP_STATUS_CODE] = $response->getStatusCode(); + $rootSpan->attributes[Tag::HTTP_STATUS_CODE] = $response->getStatusCode(); } $rootSpan->service = self::getServiceName(); Integration::tagFrameworkServiceSource($rootSpan, LaravelIntegration::NAME); - $rootSpan->meta[Tag::SPAN_KIND] = 'server'; + $rootSpan->attributes[Tag::SPAN_KIND] = 'server'; $rootSpan->meta[Tag::COMPONENT] = self::NAME; } ); @@ -119,7 +110,6 @@ static function ($This, $scope, $args, $route) { list($request) = $args; // Overwriting the default web integration - self::addTraceAnalyticsIfEnabled($rootSpan); $routeName = self::normalizeRouteName($route->getName()); if (dd_trace_env_config("DD_HTTP_SERVER_ROUTE_BASED_NAMING")) { @@ -135,8 +125,8 @@ static function ($This, $scope, $args, $route) { $rootSpan->meta['laravel.route.name'] = $routeName; $rootSpan->meta['laravel.route.action'] = $route->getActionName(); - if (!array_key_exists(Tag::HTTP_URL, $rootSpan->meta)) { - $rootSpan->meta[Tag::HTTP_URL] = \DDTrace\Util\Normalizer::urlSanitize($request->fullUrl()); + if (!Integration::hasTag($rootSpan, Tag::HTTP_URL)) { + $rootSpan->attributes[Tag::HTTP_URL] = \DDTrace\Util\Normalizer::urlSanitize($request->fullUrl()); } if (\method_exists($route, 'uri')) { $rootSpan->meta[Tag::HTTP_ROUTE] = $route->uri(); @@ -147,8 +137,8 @@ static function ($This, $scope, $args, $route) { \datadog\appsec\push_addresses(["server.request.path_params" => $parameters]); } } - $rootSpan->meta[Tag::HTTP_METHOD] = $request->method(); - $rootSpan->meta[Tag::SPAN_KIND] = 'server'; + $rootSpan->attributes[Tag::HTTP_METHOD] = $request->method(); + $rootSpan->attributes[Tag::SPAN_KIND] = 'server'; if (!\DDTrace\are_endpoints_collected()) { $routeCollection = $This->getRoutes(); @@ -186,8 +176,7 @@ function ($This, $scope, $args) { return; } - $ignoreError = isset($rootSpan->meta['error.ignored']) && $rootSpan->meta['error.ignored']; - if (isset($This->exception) && $This->getStatusCode() >= 500 && !$ignoreError) { + if (isset($This->exception) && $This->getStatusCode() >= 500 && !$rootSpan->ignoreError) { $rootSpan->exception = $This->exception; } } @@ -314,7 +303,7 @@ static function () { $rootSpan->name = 'laravel.artisan'; $rootSpan->resource = !empty($_SERVER['argv'][1]) ? 'artisan ' . $_SERVER['argv'][1] : 'artisan'; - unset($rootSpan->meta[Tag::SPAN_KIND]); + unset($rootSpan->attributes[Tag::SPAN_KIND]); $rootSpan->meta[Tag::COMPONENT] = self::NAME; } ); @@ -360,10 +349,10 @@ static function ($This, $scope, $args) { if ($args[0] && $exceptionHandler->shouldReport($args[0])) { $rootSpan->exception = $args[0]; - $rootSpan->meta['error.ignored'] = 0; + $rootSpan->ignoreError = false; } elseif ($args[0] && !$exceptionHandler->shouldReport($args[0])) { $rootSpan->exception = $args[0]; - $rootSpan->meta['error.ignored'] = 1; + $rootSpan->ignoreError = true; } }, 'recurse' => true, diff --git a/src/DDTrace/Integrations/Lumen/LumenIntegration.php b/src/DDTrace/Integrations/Lumen/LumenIntegration.php index aff0751cb2..0e8045defa 100644 --- a/src/DDTrace/Integrations/Lumen/LumenIntegration.php +++ b/src/DDTrace/Integrations/Lumen/LumenIntegration.php @@ -13,14 +13,6 @@ class LumenIntegration extends Integration { const NAME = 'lumen'; - /** - * {@inheritdoc} - */ - public static function requiresExplicitTraceAnalyticsEnabling(): bool - { - return false; - } - /** * @return int */ @@ -33,7 +25,7 @@ static function () { $rootSpan = \DDTrace\root_span(); if ($rootSpan !== null) { $rootSpan->meta[Tag::COMPONENT] = self::NAME; - $rootSpan->meta[Tag::SPAN_KIND] = 'server'; + $rootSpan->attributes[Tag::SPAN_KIND] = 'server'; } } ); @@ -49,11 +41,10 @@ static function (SpanData $span, $args) { $rootSpan->name = 'lumen.request'; $rootSpan->service = \ddtrace_config_app_name(self::NAME); Integration::tagFrameworkServiceSource($rootSpan, LumenIntegration::NAME); - self::addTraceAnalyticsIfEnabled($rootSpan); - if (!array_key_exists(Tag::HTTP_URL, $rootSpan->meta)) { - $rootSpan->meta[Tag::HTTP_URL] = \DDTrace\Util\Normalizer::urlSanitize($request->getUri()); + if (!Integration::hasTag($rootSpan, Tag::HTTP_URL)) { + $rootSpan->attributes[Tag::HTTP_URL] = \DDTrace\Util\Normalizer::urlSanitize($request->getUri()); } - $rootSpan->meta[Tag::HTTP_METHOD] = $request->getMethod(); + $rootSpan->attributes[Tag::HTTP_METHOD] = $request->getMethod(); return false; } @@ -95,7 +86,8 @@ static function (SpanData $span, $args) { && !\dd_trace_env_config("DD_TRACE_URL_AS_RESOURCE_NAMES_ENABLED") && \dd_trace_env_config("DD_HTTP_SERVER_ROUTE_BASED_NAMING") ) { - $rootSpan->resource = $rootSpan->meta[Tag::HTTP_METHOD] . ' ' . $resourceName; + $method = $rootSpan->attributes[Tag::HTTP_METHOD] ?? $rootSpan->meta[Tag::HTTP_METHOD]; + $rootSpan->resource = $method . ' ' . $resourceName; } }, ] diff --git a/src/DDTrace/Integrations/Magento/MagentoIntegration.php b/src/DDTrace/Integrations/Magento/MagentoIntegration.php index a797e72ad4..89073e57cc 100644 --- a/src/DDTrace/Integrations/Magento/MagentoIntegration.php +++ b/src/DDTrace/Integrations/Magento/MagentoIntegration.php @@ -171,7 +171,7 @@ function (SpanData $span) use (&$fullPageCached) { $rootSpan = root_span(); MagentoIntegration::setCommonSpanInfo($rootSpan, 'magento.request', $resource); - $rootSpan->meta[Tag::SPAN_KIND] = 'server'; + $rootSpan->attributes[Tag::SPAN_KIND] = 'server'; if (!$fullPageCached && isset($rootSpan->meta['magento.pathinfo'])) { $rootSpan->resource = $rootSpan->meta['magento.pathinfo']; diff --git a/src/DDTrace/Integrations/Memcache/MemcacheIntegration.php b/src/DDTrace/Integrations/Memcache/MemcacheIntegration.php index 2fd20dcd8d..0706a59909 100644 --- a/src/DDTrace/Integrations/Memcache/MemcacheIntegration.php +++ b/src/DDTrace/Integrations/Memcache/MemcacheIntegration.php @@ -99,7 +99,6 @@ public static function traceCommand($command) $span->meta['memcache.query'] = $command . ' ' . $queryParams; } $span->peerServiceSources = DatabaseIntegrationHelper::PEER_SERVICE_SOURCES; - MemcacheIntegration::markForTraceAnalytics($span, $command); }; \DDTrace\trace_method('Memcache', $command, $trace); \DDTrace\trace_function("memcache_$command", self::wrapClosureForTraceFunction($trace)); @@ -159,21 +158,4 @@ public static function setServerTags(SpanData $span, \Memcache $memcache) } } - /** - * @param SpanData $span - * @param string $command - */ - public static function markForTraceAnalytics(SpanData $span, $command) - { - $commandsForAnalytics = [ - 'add', - 'delete', - 'get', - 'set', - ]; - - if (in_array($command, $commandsForAnalytics)) { - self::addTraceAnalyticsIfEnabled($span); - } - } } diff --git a/src/DDTrace/Integrations/Memcached/MemcachedIntegration.php b/src/DDTrace/Integrations/Memcached/MemcachedIntegration.php index cff131d05e..2e431a51f6 100644 --- a/src/DDTrace/Integrations/Memcached/MemcachedIntegration.php +++ b/src/DDTrace/Integrations/Memcached/MemcachedIntegration.php @@ -111,7 +111,6 @@ function (SpanData $span, $args, $retval) use ($command) { } $span->peerServiceSources = DatabaseIntegrationHelper::PEER_SERVICE_SOURCES; - MemcachedIntegration::markForTraceAnalytics($span, $command); } ); } @@ -133,7 +132,6 @@ function (SpanData $span, $args, $retval) use ($command) { } $span->peerServiceSources = DatabaseIntegrationHelper::PEER_SERVICE_SOURCES; - MemcachedIntegration::markForTraceAnalytics($span, $command); } ); } @@ -151,7 +149,6 @@ function (SpanData $span, $args, $retval) use ($command) { MemcachedIntegration::setServerTags($span, $this); $span->meta['memcached.query'] = $command . ' ' . MemcachedIntegration::obfuscateIfNeeded($args[0], ','); $span->peerServiceSources = DatabaseIntegrationHelper::PEER_SERVICE_SOURCES; - MemcachedIntegration::markForTraceAnalytics($span, $command); } ); } @@ -171,7 +168,6 @@ function (SpanData $span, $args, $retval) use ($command) { $query = "$command " . MemcachedIntegration::obfuscateIfNeeded($args[1], ','); $span->meta['memcached.query'] = $query; $span->peerServiceSources = DatabaseIntegrationHelper::PEER_SERVICE_SOURCES; - MemcachedIntegration::markForTraceAnalytics($span, $command); } ); } @@ -221,28 +217,6 @@ public static function setServerTags(SpanData $span, \Memcached $memcached) } } - /** - * @param SpanData $span - * @param string $command - */ - public static function markForTraceAnalytics(SpanData $span, $command) - { - $commandsForAnalytics = [ - 'add', - 'addByKey', - 'delete', - 'deleteByKey', - 'get', - 'getByKey', - 'set', - 'setByKey', - ]; - - if (in_array($command, $commandsForAnalytics)) { - self::addTraceAnalyticsIfEnabled($span); - } - } - /* * Return either the obfuscated params or the params themselves, depending on the env var. */ diff --git a/src/DDTrace/Integrations/Mongo/MongoIntegration.php b/src/DDTrace/Integrations/Mongo/MongoIntegration.php index e4b3952ca4..5bc2c000f5 100644 --- a/src/DDTrace/Integrations/Mongo/MongoIntegration.php +++ b/src/DDTrace/Integrations/Mongo/MongoIntegration.php @@ -116,7 +116,6 @@ static function (SpanData $span, $args, $return) { \DDTrace\trace_method('MongoCollection', 'distinct', static function (SpanData $span, $args) { self::addSpanDefaultMetadata($span, 'MongoCollection', 'distinct'); - self::addTraceAnalyticsIfEnabled($span); if (isset($args[1])) { $span->meta[Tag::MONGODB_QUERY] = json_encode($args[1]); } @@ -133,11 +132,11 @@ static function (SpanData $span, $args) { } ); - self::traceMongoQuery('MongoCollection', 'count', false); + self::traceMongoQuery('MongoCollection', 'count'); self::traceMongoQuery('MongoCollection', 'find'); self::traceMongoQuery('MongoCollection', 'findAndModify'); self::traceMongoQuery('MongoCollection', 'findOne'); - self::traceMongoQuery('MongoCollection', 'remove', false); + self::traceMongoQuery('MongoCollection', 'remove'); self::traceMongoQuery('MongoCollection', 'update'); self::traceMongoMethod('MongoCollection', 'aggregate'); @@ -253,23 +252,16 @@ public static function traceMongoMethod($class, $method) /** * Utility method to trace all query methods that have the query as the first argument. - * If the param {$isTraceAnalithicsCandidate} is set to true (default behavior) the span - * generated is also marked as trace analytics candidate. - * * @param string $class * @param string $method - * @param boolean $isTraceAnalyticsCandidate [default: `true`] */ - public static function traceMongoQuery($class, $method, $isTraceAnalyticsCandidate = true) + public static function traceMongoQuery($class, $method) { \DDTrace\trace_method( $class, $method, - static function (SpanData $span, $args) use ($class, $method, $isTraceAnalyticsCandidate) { + static function (SpanData $span, $args) use ($class, $method) { self::addSpanDefaultMetadata($span, $class, $method); - if ($isTraceAnalyticsCandidate) { - self::addTraceAnalyticsIfEnabled($span); - } if (isset($args[0])) { $span->meta[Tag::MONGODB_QUERY] = json_encode($args[0]); } diff --git a/src/DDTrace/Integrations/MongoDB/MongoDBIntegration.php b/src/DDTrace/Integrations/MongoDB/MongoDBIntegration.php index 27f715a288..42b8be9fc6 100644 --- a/src/DDTrace/Integrations/MongoDB/MongoDBIntegration.php +++ b/src/DDTrace/Integrations/MongoDB/MongoDBIntegration.php @@ -616,6 +616,5 @@ public static function setMetadata( $span->meta[Tag::MONGODB_QUERY] = $serializedQuery; } $span->peerServiceSources = DatabaseIntegrationHelper::PEER_SERVICE_SOURCES; - self::addTraceAnalyticsIfEnabled($span); } } diff --git a/src/DDTrace/Integrations/Mysqli/MysqliIntegration.php b/src/DDTrace/Integrations/Mysqli/MysqliIntegration.php index bc5db373c9..389d2ad808 100644 --- a/src/DDTrace/Integrations/Mysqli/MysqliIntegration.php +++ b/src/DDTrace/Integrations/Mysqli/MysqliIntegration.php @@ -108,7 +108,6 @@ function (SpanData $span, $args) { $span = $hook->span(); $span->peerServiceSources = DatabaseIntegrationHelper::PEER_SERVICE_SOURCES; self::setDefaultAttributes($span, 'mysqli_query', $query); - self::addTraceAnalyticsIfEnabled($span); self::setConnectionInfo($span, $mysqli); DatabaseIntegrationHelper::injectDatabaseIntegrationData($hook, 'mysql', 1); @@ -133,7 +132,6 @@ function (SpanData $span, $args) { $span = $hook->span(); $span->peerServiceSources = DatabaseIntegrationHelper::PEER_SERVICE_SOURCES; self::setDefaultAttributes($span, 'mysqli_real_query', $query); - self::addTraceAnalyticsIfEnabled($span); self::setConnectionInfo($span, $mysqli); DatabaseIntegrationHelper::injectDatabaseIntegrationData($hook, 'mysql', 1); @@ -178,7 +176,6 @@ function (SpanData $span, $args) { $span = $hook->span(); $span->peerServiceSources = DatabaseIntegrationHelper::PEER_SERVICE_SOURCES; MysqliIntegration::setDefaultAttributes($span, 'mysqli.query', $query); - MysqliIntegration::addTraceAnalyticsIfEnabled($span); MysqliIntegration::setConnectionInfo($span, $hook->instance); DatabaseIntegrationHelper::injectDatabaseIntegrationData($hook, 'mysql'); @@ -205,7 +202,6 @@ function (SpanData $span, $args) { $span = $hook->span(); $span->peerServiceSources = DatabaseIntegrationHelper::PEER_SERVICE_SOURCES; MysqliIntegration::setDefaultAttributes($span, 'mysqli.real_query', $query); - MysqliIntegration::addTraceAnalyticsIfEnabled($span); MysqliIntegration::setConnectionInfo($span, $hook->instance); DatabaseIntegrationHelper::injectDatabaseIntegrationData($hook, 'mysql'); @@ -262,7 +258,6 @@ function (SpanData $span, $args) { $span = $hook->span(); $span->peerServiceSources = DatabaseIntegrationHelper::PEER_SERVICE_SOURCES; self::setDefaultAttributes($span, 'mysqli_execute_query', $query); - self::addTraceAnalyticsIfEnabled($span); DatabaseIntegrationHelper::injectDatabaseIntegrationData($hook, 'mysql', 1); self::handleRasp($span); @@ -287,7 +282,6 @@ function (SpanData $span, $args) { $span = $hook->span(); $span->peerServiceSources = DatabaseIntegrationHelper::PEER_SERVICE_SOURCES; self::setDefaultAttributes($span, 'mysqli.execute_query', $query); - self::addTraceAnalyticsIfEnabled($span); DatabaseIntegrationHelper::injectDatabaseIntegrationData($hook, 'mysql'); self::handleRasp($span); @@ -366,7 +360,6 @@ static function (HookData $hook) { \DDTrace\trace_method('mysqli_stmt', 'execute', function (SpanData $span) { $resource = MysqliCommon::retrieveQuery($this, 'mysqli_stmt.execute'); MysqliIntegration::setDefaultAttributes($span, 'mysqli_stmt.execute', $resource); - MysqliIntegration::addTraceAnalyticsIfEnabled($span); MysqliIntegration::setConnectionInfo($span, ObjectKVStore::get($this, MysqliIntegration::KEY_MYSQLI_INSTANCE)); $span->peerServiceSources = DatabaseIntegrationHelper::PEER_SERVICE_SOURCES; }); @@ -425,7 +418,7 @@ public static function setConnectionInfo(SpanData $span, $mysqli) if (isset($hostInfo[Tag::TARGET_HOST])) { $span->service .= '-' . \DDTrace\Util\Normalizer::normalizeHostUdsAsService($hostInfo[Tag::TARGET_HOST]); - $span->meta['_dd.svc_src'] = 'opt.db_client_split_by_instance'; + $span->attributes['_dd.svc_src'] = 'opt.db_client_split_by_instance'; } } $dbName = ObjectKVStore::get($mysqli, self::KEY_DATABASE_NAME); diff --git a/src/DDTrace/Integrations/Nette/NetteIntegration.php b/src/DDTrace/Integrations/Nette/NetteIntegration.php index 620ecaf9b7..6a774b58d1 100644 --- a/src/DDTrace/Integrations/Nette/NetteIntegration.php +++ b/src/DDTrace/Integrations/Nette/NetteIntegration.php @@ -11,14 +11,6 @@ class NetteIntegration extends Integration { const NAME = 'nette'; - /** - * {@inheritdoc} - */ - public static function requiresExplicitTraceAnalyticsEnabling(): bool - { - return false; - } - /** * {@inheritdoc} */ @@ -32,9 +24,8 @@ public static function init(): int return; } - $rootSpan->meta[Tag::SPAN_KIND] = 'server'; + $rootSpan->attributes[Tag::SPAN_KIND] = 'server'; - self::addTraceAnalyticsIfEnabled($rootSpan); $rootSpan->service = $service; $rootSpan->meta[Tag::COMPONENT] = self::NAME; }; @@ -63,7 +54,7 @@ static function (SpanData $span) use ($service) { $span->meta[Tag::COMPONENT] = self::NAME; $rootSpan = \DDTrace\root_span(); - $rootSpan->meta[Tag::HTTP_STATUS_CODE] = http_response_code(); + $rootSpan->attributes[Tag::HTTP_STATUS_CODE] = http_response_code(); } ); @@ -85,7 +76,7 @@ static function (SpanData $span, $args) use ($service) { $action = $request->getParameter('action'); $rootSpan = \DDTrace\root_span(); - $rootSpan->meta[Tag::HTTP_METHOD] = $request->getMethod(); + $rootSpan->attributes[Tag::HTTP_METHOD] = $request->getMethod(); $rootSpan->meta['nette.route.presenter'] = $presenter; $rootSpan->meta['nette.route.action'] = $action; } diff --git a/src/DDTrace/Integrations/PDO/PDOIntegration.php b/src/DDTrace/Integrations/PDO/PDOIntegration.php index 7172089a8a..e44bf851ca 100644 --- a/src/DDTrace/Integrations/PDO/PDOIntegration.php +++ b/src/DDTrace/Integrations/PDO/PDOIntegration.php @@ -74,7 +74,6 @@ public static function init(): int $span->peerServiceSources = DatabaseIntegrationHelper::PEER_SERVICE_SOURCES; $instance = $hook->instance; PDOIntegration::setCommonSpanInfo($instance, $span); - PDOIntegration::addTraceAnalyticsIfEnabled($span); PDOIntegration::injectDBIntegration($instance, $hook); PDOIntegration::handleRasp($instance, $span); @@ -100,7 +99,6 @@ public static function init(): int $span->peerServiceSources = DatabaseIntegrationHelper::PEER_SERVICE_SOURCES; $instance = $hook->instance; PDOIntegration::setCommonSpanInfo($instance, $span); - PDOIntegration::addTraceAnalyticsIfEnabled($span); PDOIntegration::injectDBIntegration($instance, $hook); PDOIntegration::handleRasp($instance, $span); @@ -170,7 +168,6 @@ static function (HookData $hook) { } } PDOIntegration::setCommonSpanInfo($instance, $span); - PDOIntegration::addTraceAnalyticsIfEnabled($span); PDOIntegration::detectError($instance, $span); $span->resource = PDOIntegration::useQuestionMarkPlaceholders($span->resource); @@ -324,7 +321,7 @@ public static function setCommonSpanInfo($source, SpanData $span) Integration::handleInternalSpanServiceName($span, self::NAME, true); $span->service = $span->service . '-' . \DDTrace\Util\Normalizer::normalizeHostUdsAsService($storedConnectionInfo[Tag::TARGET_HOST]); - $span->meta['_dd.svc_src'] = 'opt.db_client_split_by_instance'; + $span->attributes['_dd.svc_src'] = 'opt.db_client_split_by_instance'; } else { Integration::handleInternalSpanServiceName($span, self::NAME); } diff --git a/src/DDTrace/Integrations/PHPRedis/PHPRedisIntegration.php b/src/DDTrace/Integrations/PHPRedis/PHPRedisIntegration.php index f7c3e358b5..de7c0d50a4 100644 --- a/src/DDTrace/Integrations/PHPRedis/PHPRedisIntegration.php +++ b/src/DDTrace/Integrations/PHPRedis/PHPRedisIntegration.php @@ -329,15 +329,15 @@ public static function enrichSpan(SpanData $span, $instance, $class, $method = n if (!empty($clusterName)) { $normalizedClusterName = \DDTrace\Util\Normalizer::normalizeHostUdsAsService($clusterName); $span->service = $serviceNamePrefix . $normalizedClusterName; - $span->meta['_dd.svc_src'] = 'opt.redis_client_split_by_host'; + $span->attributes['_dd.svc_src'] = 'opt.redis_client_split_by_host'; } elseif (!empty($firstHostOrUDS)) { $normalizedHost = \DDTrace\Util\Normalizer::normalizeHostUdsAsService($firstHostOrUDS); $span->service = $serviceNamePrefix . $normalizedHost; - $span->meta['_dd.svc_src'] = 'opt.redis_client_split_by_host'; + $span->attributes['_dd.svc_src'] = 'opt.redis_client_split_by_host'; } elseif (!empty($host)) { $normalizedHost = \DDTrace\Util\Normalizer::normalizeHostUdsAsService($host); $span->service = $serviceNamePrefix . $normalizedHost; - $span->meta['_dd.svc_src'] = 'opt.redis_client_split_by_host'; + $span->attributes['_dd.svc_src'] = 'opt.redis_client_split_by_host'; } else { Integration::handleInternalSpanServiceName($span, self::NAME); } diff --git a/src/DDTrace/Integrations/Predis/PredisIntegration.php b/src/DDTrace/Integrations/Predis/PredisIntegration.php index b971b57ca7..1c14c81271 100644 --- a/src/DDTrace/Integrations/Predis/PredisIntegration.php +++ b/src/DDTrace/Integrations/Predis/PredisIntegration.php @@ -52,7 +52,6 @@ public static function init(): int $span->name = 'Predis.Client.executeCommand'; $span->type = Type::REDIS; PredisIntegration::setMetaAndServiceFromConnection($this, $span); - PredisIntegration::addTraceAnalyticsIfEnabled($span); // We default resource name to 'Predis.Client.executeCommand', but if we are able below to extract the query // then we replace it with the query @@ -77,7 +76,6 @@ public static function init(): int $span->name = 'Predis.Client.executeRaw'; $span->type = Type::REDIS; PredisIntegration::setMetaAndServiceFromConnection($this, $span); - PredisIntegration::addTraceAnalyticsIfEnabled($span); // We default resource name to 'Predis.Client.executeRaw', but if we are able below to extract the query // then we replace it with the query diff --git a/src/DDTrace/Integrations/Psr18/Psr18Integration.php b/src/DDTrace/Integrations/Psr18/Psr18Integration.php index 727d6e0fa1..c1ce8eb702 100644 --- a/src/DDTrace/Integrations/Psr18/Psr18Integration.php +++ b/src/DDTrace/Integrations/Psr18/Psr18Integration.php @@ -57,7 +57,7 @@ public static function addRequestInfo(SpanData $span, $request) if (\dd_trace_env_config("DD_TRACE_HTTP_CLIENT_SPLIT_BY_DOMAIN")) { $span->service = Urls::hostnameForTag($url); - $span->meta['_dd.svc_src'] = 'opt.http_client_split_by_domain'; + $span->attributes['_dd.svc_src'] = 'opt.http_client_split_by_domain'; } $span->meta[Tag::HTTP_METHOD] = $request->getMethod(); diff --git a/src/DDTrace/Integrations/Ratchet/RatchetIntegration.php b/src/DDTrace/Integrations/Ratchet/RatchetIntegration.php index 2b1fcc30e6..c7feb8c6f5 100644 --- a/src/DDTrace/Integrations/Ratchet/RatchetIntegration.php +++ b/src/DDTrace/Integrations/Ratchet/RatchetIntegration.php @@ -44,14 +44,6 @@ class RatchetIntegration extends Integration { const NAME = 'ratchet'; - /** - * {@inheritdoc} - */ - public static function requiresExplicitTraceAnalyticsEnabling(): bool - { - return false; - } - /** * @return int */ @@ -78,7 +70,7 @@ public static function init(): int \DDTrace\collect_code_origins(1); if (\dd_trace_env_config("DD_TRACE_HTTP_CLIENT_SPLIT_BY_DOMAIN")) { $span->service = Urls::hostnameForTag($url); - $span->meta['_dd.svc_src'] = 'opt.http_client_split_by_domain'; + $span->attributes['_dd.svc_src'] = 'opt.http_client_split_by_domain'; } }, static function (HookData $hook) { $span = $hook->data; @@ -182,8 +174,7 @@ public static function init(): int $activeSpan->name = "web.request"; $activeSpan->type = Type::WEB_SERVLET; $activeSpan->meta[Tag::COMPONENT] = self::NAME; - $activeSpan->meta[Tag::SPAN_KIND] = 'server'; - RatchetIntegration::addTraceAnalyticsIfEnabled($activeSpan); + $activeSpan->attributes[Tag::SPAN_KIND] = 'server'; ObjectKVStore::put($parentConn, "handshake", $activeSpan); @@ -201,7 +192,7 @@ public static function init(): int \DDTrace\install_hook(CloseResponseTrait::class . "::close", static function (HookData $hook) { if ($rootSpan = \DDTrace\root_span()) { - $rootSpan->meta[Tag::HTTP_STATUS_CODE] = $hook->args[1] ?? 400; + $rootSpan->attributes[Tag::HTTP_STATUS_CODE] = $hook->args[1] ?? 400; notify_commit($rootSpan, 400, []); } }); @@ -262,8 +253,10 @@ public static function init(): int $span = $hook->span($rootTrace ? new SpanStack : null); $span->type = Type::WEBSOCKET; $span->service = $handshake->service; - if (isset($handshake->meta['_dd.svc_src'])) { - $span->meta['_dd.svc_src'] = $handshake->meta['_dd.svc_src']; + $handshakeServiceSource = $handshake->attributes['_dd.svc_src'] + ?? $handshake->meta['_dd.svc_src'] ?? null; + if ($handshakeServiceSource !== null) { + $span->attributes['_dd.svc_src'] = $handshakeServiceSource; } $resourceParts = explode(" ", $handshake->resource, 2); $span->resource = "websocket " . end($resourceParts); @@ -280,8 +273,9 @@ public static function init(): int $span->meta["_dd.dm.resource"] = $rootSpan->resource; } foreach ($rootSpan->propagatedTags as $key => $_) { - if (isset($rootSpan->meta[$key])) { - $span->meta[$key] = $rootSpan->meta[$key]; + $value = $rootSpan->attributes[$key] ?? $rootSpan->meta[$key] ?? null; + if ($value !== null) { + $span->attributes[$key] = $value; } } $span->baggage = $rootSpan->baggage; @@ -302,7 +296,7 @@ public static function init(): int } if ($isServer) { - unset($span->meta["closure.declaration"]); + unset($span->attributes["closure.declaration"]); } RatchetIntegration::addLink($span, $handshake, true, $isServer, $frameNum++); diff --git a/src/DDTrace/Integrations/Roadrunner/RoadrunnerIntegration.php b/src/DDTrace/Integrations/Roadrunner/RoadrunnerIntegration.php index 314d17f9db..e03033bec7 100644 --- a/src/DDTrace/Integrations/Roadrunner/RoadrunnerIntegration.php +++ b/src/DDTrace/Integrations/Roadrunner/RoadrunnerIntegration.php @@ -17,14 +17,6 @@ class RoadrunnerIntegration extends Integration { const NAME = 'roadrunner'; - /** - * {@inheritdoc} - */ - public static function requiresExplicitTraceAnalyticsEnabling(): bool - { - return false; - } - public static function build_req_spec(\Spiral\RoadRunner\Http\Request $req) { $ret = array(); @@ -159,8 +151,7 @@ function (HookData $hook) use (&$activeSpan, &$suppressResponse, $service, &$rec $activeSpan->name = "web.request"; $activeSpan->type = Type::WEB_SERVLET; $activeSpan->meta[Tag::COMPONENT] = RoadrunnerIntegration::NAME; - $activeSpan->meta[Tag::SPAN_KIND] = 'server'; - RoadrunnerIntegration::addTraceAnalyticsIfEnabled($activeSpan); + $activeSpan->attributes[Tag::SPAN_KIND] = 'server'; if ($hook->exception) { $activeSpan->exception = $hook->exception; \DDTrace\close_span(); diff --git a/src/DDTrace/Integrations/SQLSRV/SQLSRVIntegration.php b/src/DDTrace/Integrations/SQLSRV/SQLSRVIntegration.php index 929a860c00..48694ad984 100644 --- a/src/DDTrace/Integrations/SQLSRV/SQLSRVIntegration.php +++ b/src/DDTrace/Integrations/SQLSRV/SQLSRVIntegration.php @@ -45,7 +45,6 @@ public static function init(): int $span = $hook->span(); self::setDefaultAttributes($conn, $span, 'sqlsrv_query', $query); - self::addTraceAnalyticsIfEnabled($span); $span->peerServiceSources = DatabaseIntegrationHelper::PEER_SERVICE_SOURCES; DatabaseIntegrationHelper::injectDatabaseIntegrationData($hook, 'sqlsrv', 1); @@ -99,7 +98,6 @@ public static function init(): int $query = resource_weak_get($stmt, self::QUERY_TAGS_KEY); } self::setDefaultAttributes($stmt, $span, 'sqlsrv_execute', $query ?? "", $retval); - self::addTraceAnalyticsIfEnabled($span); $span->peerServiceSources = DatabaseIntegrationHelper::PEER_SERVICE_SOURCES; if ($retval) { self::setMetrics($span, $args[0]); @@ -182,7 +180,7 @@ public static function setDefaultAttributes($source, SpanData $span, $name, $que if (\dd_trace_env_config("DD_TRACE_DB_CLIENT_SPLIT_BY_INSTANCE")) { if ($targetName !== "") { $span->service .= '-' . \DDTrace\Util\Normalizer::normalizeHostUdsAsService($targetName); - $span->meta['_dd.svc_src'] = 'opt.db_client_split_by_instance'; + $span->attributes['_dd.svc_src'] = 'opt.db_client_split_by_instance'; } } } diff --git a/src/DDTrace/Integrations/Slim/SlimIntegration.php b/src/DDTrace/Integrations/Slim/SlimIntegration.php index d135e66d81..a6a20fab08 100644 --- a/src/DDTrace/Integrations/Slim/SlimIntegration.php +++ b/src/DDTrace/Integrations/Slim/SlimIntegration.php @@ -30,11 +30,10 @@ function ($app) { // Overwrite root span info $rootSpan = \DDTrace\root_span(); - SlimIntegration::addTraceAnalyticsIfEnabled($rootSpan); $rootSpan->name = 'slim.request'; $rootSpan->service = \ddtrace_config_app_name(SlimIntegration::NAME); Integration::tagFrameworkServiceSource($rootSpan, SlimIntegration::NAME); - $rootSpan->meta[Tag::SPAN_KIND] = 'server'; + $rootSpan->attributes[Tag::SPAN_KIND] = 'server'; $rootSpan->meta[Tag::COMPONENT] = SlimIntegration::NAME; if ('4' === $majorVersion) { @@ -115,8 +114,8 @@ static function ($router, $scope, $args, $return) use ($rootSpan) { /** @var ServerRequestInterface $request */ $request = $args[1]; - if (!array_key_exists(Tag::HTTP_URL, $rootSpan->meta)) { - $rootSpan->meta[Tag::HTTP_URL] = + if (!Integration::hasTag($rootSpan, Tag::HTTP_URL)) { + $rootSpan->attributes[Tag::HTTP_URL] = \DDTrace\Util\Normalizer::urlSanitize((string) $request->getUri()); } diff --git a/src/DDTrace/Integrations/Swoole/SwooleIntegration.php b/src/DDTrace/Integrations/Swoole/SwooleIntegration.php index e83d329c7a..dcd95f38aa 100644 --- a/src/DDTrace/Integrations/Swoole/SwooleIntegration.php +++ b/src/DDTrace/Integrations/Swoole/SwooleIntegration.php @@ -19,14 +19,6 @@ class SwooleIntegration extends Integration { const NAME = 'swoole'; - /** - * {@inheritdoc} - */ - public static function requiresExplicitTraceAnalyticsEnabling(): bool - { - return false; - } - public static function instrumentRequestStart(callable $callback, Server $server) { $scheme = $server->ssl ? 'https://' : 'http://'; @@ -40,8 +32,7 @@ static function (HookData $hook) use ($server, $scheme) { Integration::tagFrameworkServiceSource($rootSpan, self::NAME); $rootSpan->type = Type::WEB_SERVLET; $rootSpan->meta[Tag::COMPONENT] = self::NAME; - $rootSpan->meta[Tag::SPAN_KIND] = Tag::SPAN_KIND_VALUE_SERVER; - self::addTraceAnalyticsIfEnabled($rootSpan); + $rootSpan->attributes[Tag::SPAN_KIND] = Tag::SPAN_KIND_VALUE_SERVER; $args = $hook->args; /** @var Request $request */ @@ -53,7 +44,7 @@ static function (HookData $hook) use ($server, $scheme) { $headers[strtolower($name)] = $value; $normalizedHeader = preg_replace("([^a-z0-9-])", "_", strtolower($name)); if (\array_key_exists($normalizedHeader, $allowedHeaders)) { - $rootSpan->meta["http.request.headers.$normalizedHeader"] = $value; + $rootSpan->attributes["http.request.headers.$normalizedHeader"] = $value; } } consume_distributed_tracing_headers(static function ($key) use ($headers) { @@ -66,7 +57,7 @@ static function (HookData $hook) use ($server, $scheme) { } if (isset($headers["user-agent"])) { - $rootSpan->meta["http.useragent"] = $headers["user-agent"]; + $rootSpan->attributes["http.useragent"] = $headers["user-agent"]; } if (!empty(\dd_trace_env_config('DD_TRACE_HTTP_POST_DATA_PARAM_ALLOWED'))) { @@ -96,15 +87,15 @@ static function (HookData $hook) use ($server, $scheme) { ?? '/' ); $rootSpan->resource = $request->server['request_method'] . ' ' . $normalizedPath; - $rootSpan->meta[Tag::HTTP_METHOD] = $request->server['request_method']; + $rootSpan->attributes[Tag::HTTP_METHOD] = $request->server['request_method']; $host = $headers['host'] ?? ($request->server['remote_addr'] . ':' . $request->server['server_port']); $path = $request->server['request_uri'] ?? $request->server['path_info'] ?? ''; $query = isset($request->server['query_string']) ? '?' . $request->server['query_string'] : ''; $url = $scheme . $host . $path . $query; - $rootSpan->meta[Tag::HTTP_URL] = Normalizer::urlSanitize($url); + $rootSpan->attributes[Tag::HTTP_URL] = Normalizer::urlSanitize($url); - unset($rootSpan->meta['closure.declaration']); + unset($rootSpan->attributes['closure.declaration']); } ); } @@ -173,7 +164,8 @@ static function ($response, $scope, $args) { // Note: The response's body can be retrieved here, from the args if (!$rootSpan->exception - && ((int)$rootSpan->meta[Tag::HTTP_STATUS_CODE]) >= 500 + && ((int)($rootSpan->attributes[Tag::HTTP_STATUS_CODE] + ?? $rootSpan->meta[Tag::HTTP_STATUS_CODE] ?? 0)) >= 500 && $ex = \DDTrace\find_active_exception() ) { $rootSpan->exception = $ex; @@ -196,7 +188,7 @@ static function ($response, $scope, $args) { $allowedHeaders = \dd_trace_env_config("DD_TRACE_HEADER_TAGS"); $normalizedHeader = preg_replace("([^a-z0-9-])", "_", strtolower($key)); if (\array_key_exists($normalizedHeader, $allowedHeaders)) { - $rootSpan->meta["http.response.headers.$normalizedHeader"] = $value; + $rootSpan->attributes["http.response.headers.$normalizedHeader"] = $value; } } ); @@ -207,7 +199,7 @@ static function ($response, $scope, $args) { static function ($response, $scope, $args) { $rootSpan = \DDTrace\root_span(); if ($rootSpan && \count($args) > 0) { - $rootSpan->meta[Tag::HTTP_STATUS_CODE] = $args[0]; + $rootSpan->attributes[Tag::HTTP_STATUS_CODE] = $args[0]; } } ); diff --git a/src/DDTrace/Integrations/Symfony/SymfonyIntegration.php b/src/DDTrace/Integrations/Symfony/SymfonyIntegration.php index 2ac324ec74..2e8c7fc9ba 100644 --- a/src/DDTrace/Integrations/Symfony/SymfonyIntegration.php +++ b/src/DDTrace/Integrations/Symfony/SymfonyIntegration.php @@ -22,14 +22,6 @@ class SymfonyIntegration extends Integration public static $kernel; - /** - * {@inheritdoc} - */ - public static function requiresExplicitTraceAnalyticsEnabling(): bool - { - return false; - } - /** * Load the integration * @@ -51,16 +43,15 @@ public static function init(): int $rootSpan->name = 'symfony.request'; $rootSpan->service = $service; Integration::tagFrameworkServiceSource($rootSpan, SymfonyIntegration::NAME); - $rootSpan->meta[Tag::SPAN_KIND] = 'server'; + $rootSpan->attributes[Tag::SPAN_KIND] = 'server'; $rootSpan->meta[Tag::COMPONENT] = SymfonyIntegration::NAME; - SymfonyIntegration::addTraceAnalyticsIfEnabled($rootSpan); $span->name = 'symfony.httpkernel.kernel.handle'; $span->resource = \get_class($this); $span->type = Type::WEB_SERVLET; $span->service = $service; Integration::tagFrameworkServiceSource($span, SymfonyIntegration::NAME); - $span->meta[Tag::SPAN_KIND] = 'server'; + $span->attributes[Tag::SPAN_KIND] = 'server'; $span->meta[Tag::COMPONENT] = SymfonyIntegration::NAME; }, ] @@ -476,16 +467,15 @@ static function(SpanData $span, $args, $response) use ($handle_http_route) { $span->meta[Tag::COMPONENT] = self::NAME; $rootSpan = \DDTrace\root_span(); - $rootSpan->meta[Tag::HTTP_METHOD] = $request->getMethod(); + $rootSpan->attributes[Tag::HTTP_METHOD] = $request->getMethod(); $rootSpan->meta[Tag::COMPONENT] = self::$frameworkPrefix; - $rootSpan->meta[Tag::SPAN_KIND] = 'server'; - self::addTraceAnalyticsIfEnabled($rootSpan); + $rootSpan->attributes[Tag::SPAN_KIND] = 'server'; - if (!array_key_exists(Tag::HTTP_URL, $rootSpan->meta)) { - $rootSpan->meta[Tag::HTTP_URL] = Normalizer::urlSanitize($request->getUri()); + if (!Integration::hasTag($rootSpan, Tag::HTTP_URL)) { + $rootSpan->attributes[Tag::HTTP_URL] = Normalizer::urlSanitize($request->getUri()); } if (isset($response)) { - $rootSpan->meta[Tag::HTTP_STATUS_CODE] = $response->getStatusCode(); + $rootSpan->attributes[Tag::HTTP_STATUS_CODE] = $response->getStatusCode(); } $route_name = $request->attributes->get('_route'); @@ -634,7 +624,7 @@ static function(HookData $hook) use ($controllerName) { if (isset($retval) && \method_exists($retval, 'getStatusCode') && $retval->getStatusCode() < 500) { // It means that the exception event associated with the exception had a response, which certainly // means that the exception was handled. - \DDTrace\root_span()->meta['error.ignored'] = 1; + \DDTrace\root_span()->ignoreError = true; } }; // Symfony 4.3- diff --git a/src/DDTrace/Integrations/WordPress/WordPressIntegration.php b/src/DDTrace/Integrations/WordPress/WordPressIntegration.php index 8a3774dc26..6643abf5ae 100644 --- a/src/DDTrace/Integrations/WordPress/WordPressIntegration.php +++ b/src/DDTrace/Integrations/WordPress/WordPressIntegration.php @@ -8,14 +8,6 @@ class WordPressIntegration extends Integration { const NAME = 'wordpress'; - /** - * {@inheritdoc} - */ - public static function requiresExplicitTraceAnalyticsEnabling(): bool - { - return false; - } - /** * {@inheritdoc} */ diff --git a/src/DDTrace/Integrations/WordPress/WordPressIntegrationLoader.php b/src/DDTrace/Integrations/WordPress/WordPressIntegrationLoader.php index 72413204c9..a407df5771 100644 --- a/src/DDTrace/Integrations/WordPress/WordPressIntegrationLoader.php +++ b/src/DDTrace/Integrations/WordPress/WordPressIntegrationLoader.php @@ -204,16 +204,15 @@ public static function load() // Overwrite the default web integration $rootSpan = \DDTrace\root_span(); if ($rootSpan) { - WordPressIntegration::addTraceAnalyticsIfEnabled($rootSpan); $rootSpan->name = 'wordpress.request'; $rootSpan->service = \ddtrace_config_app_name(WordPressIntegration::NAME);; $rootSpan->meta[Tag::COMPONENT] = WordPressIntegration::NAME; - $rootSpan->meta[Tag::SPAN_KIND] = 'server'; + $rootSpan->attributes[Tag::SPAN_KIND] = 'server'; if ('cli' !== PHP_SAPI) { $normalizedPath = Normalizer::uriNormalizeincomingPath($_SERVER['REQUEST_URI']); $rootSpan->resource = $_SERVER['REQUEST_METHOD'] . ' ' . $normalizedPath; - if (!array_key_exists(Tag::HTTP_URL, $rootSpan->meta)) { - $rootSpan->meta[Tag::HTTP_URL] = Normalizer::urlSanitize(home_url(add_query_arg($_GET))); + if (!Integration::hasTag($rootSpan, Tag::HTTP_URL)) { + $rootSpan->attributes[Tag::HTTP_URL] = Normalizer::urlSanitize(home_url(add_query_arg($_GET))); } } } diff --git a/src/DDTrace/Integrations/Yii/YiiIntegration.php b/src/DDTrace/Integrations/Yii/YiiIntegration.php index 91fa862d5f..6bbb54c95b 100644 --- a/src/DDTrace/Integrations/Yii/YiiIntegration.php +++ b/src/DDTrace/Integrations/Yii/YiiIntegration.php @@ -13,14 +13,6 @@ class YiiIntegration extends Integration { const NAME = 'yii'; - /** - * {@inheritdoc} - */ - public static function requiresExplicitTraceAnalyticsEnabling(): bool - { - return false; - } - /** * {@inheritdoc} */ @@ -37,8 +29,7 @@ static function () { $rootSpan = \DDTrace\root_span(); if ($rootSpan !== null) { $rootSpan->meta[Tag::COMPONENT] = self::NAME; - $rootSpan->meta[Tag::SPAN_KIND] = 'server'; - self::addTraceAnalyticsIfEnabled($rootSpan); + $rootSpan->attributes[Tag::SPAN_KIND] = 'server'; } } ); @@ -104,7 +95,7 @@ function (SpanData $span, $args) use (&$firstController) { $endpoint = "{$controller}::{$this->action->actionMethod}"; $rootSpan->meta["app.endpoint"] = $endpoint; - $rootSpan->meta[Tag::HTTP_URL] = + $rootSpan->attributes[Tag::HTTP_URL] = \DDTrace\Util\Normalizer::urlSanitize(Url::base(true) . Url::current()); } diff --git a/src/DDTrace/Integrations/ZendFramework/V1/TraceRequest.php b/src/DDTrace/Integrations/ZendFramework/V1/TraceRequest.php index cf4aa4a07a..38b3487241 100644 --- a/src/DDTrace/Integrations/ZendFramework/V1/TraceRequest.php +++ b/src/DDTrace/Integrations/ZendFramework/V1/TraceRequest.php @@ -2,6 +2,7 @@ namespace DDTrace\Integrations\ZendFramework\V1; +use DDTrace\Integrations\Integration; use DDTrace\Integrations\ZendFramework\ZendFrameworkIntegration; use DDTrace\Tag; use Zend_Controller_Front; @@ -21,7 +22,6 @@ public function preDispatch(Zend_Controller_Request_Abstract $request) return; } // Overwriting the default web integration - ZendFrameworkIntegration::addTraceAnalyticsIfEnabled($span); $controller = $request->getControllerName(); $action = $request->getActionName(); $route = Zend_Controller_Front::getInstance()->getRouter()->getCurrentRouteName(); @@ -31,12 +31,12 @@ public function preDispatch(Zend_Controller_Request_Abstract $request) if (dd_trace_env_config("DD_HTTP_SERVER_ROUTE_BASED_NAMING")) { $span->resource = $controller . '@' . $action . ' ' . $route; } - $span->meta[Tag::HTTP_METHOD] = $request->getMethod(); - $span->meta[Tag::SPAN_KIND] = 'server'; + $span->attributes[Tag::HTTP_METHOD] = $request->getMethod(); + $span->attributes[Tag::SPAN_KIND] = 'server'; $span->meta[Tag::COMPONENT] = ZendFrameworkIntegration::NAME; - if (!array_key_exists(Tag::HTTP_URL, $span->meta)) { - $span->meta[Tag::HTTP_URL] = \DDTrace\Util\Normalizer::urlSanitize( + if (!Integration::hasTag($span, Tag::HTTP_URL)) { + $span->attributes[Tag::HTTP_URL] = \DDTrace\Util\Normalizer::urlSanitize( $request->getScheme() . '://' . $request->getHttpHost() . $request->getRequestUri() @@ -53,6 +53,6 @@ public function postDispatch(Zend_Controller_Request_Abstract $request) if (null === $span) { return; } - $span->meta[Tag::HTTP_STATUS_CODE] = $this->getResponse()->getHttpResponseCode(); + $span->attributes[Tag::HTTP_STATUS_CODE] = $this->getResponse()->getHttpResponseCode(); } } diff --git a/src/DDTrace/Integrations/ZendFramework/ZendFrameworkIntegration.php b/src/DDTrace/Integrations/ZendFramework/ZendFrameworkIntegration.php index 8974413674..25c27e606c 100644 --- a/src/DDTrace/Integrations/ZendFramework/ZendFrameworkIntegration.php +++ b/src/DDTrace/Integrations/ZendFramework/ZendFrameworkIntegration.php @@ -15,14 +15,6 @@ class ZendFrameworkIntegration extends Integration { const NAME = 'zendframework'; - /** - * {@inheritdoc} - */ - public static function requiresExplicitTraceAnalyticsEnabling(): bool - { - return false; - } - /** * Loads the zend framework integration. * @@ -48,7 +40,6 @@ static function ($broker, $scope, $args) { try { /** @var Zend_Controller_Request_Abstract $request */ list($request) = $args; - self::addTraceAnalyticsIfEnabled($rootSpan); $rootSpan->name = self::getOperationName(); // For backward compatibility with the legacy API we are not using the integration // name 'zendframework', we are instead using the 'zf1' prefix. @@ -63,12 +54,12 @@ static function ($broker, $scope, $args) { if (dd_trace_env_config("DD_HTTP_SERVER_ROUTE_BASED_NAMING")) { $rootSpan->resource = $controller . '@' . $action . ' ' . $route; } - $rootSpan->meta[Tag::HTTP_METHOD] = $request->getMethod(); - $rootSpan->meta[Tag::SPAN_KIND] = 'server'; + $rootSpan->attributes[Tag::HTTP_METHOD] = $request->getMethod(); + $rootSpan->attributes[Tag::SPAN_KIND] = 'server'; $rootSpan->meta[Tag::COMPONENT] = self::NAME; - if (!array_key_exists(Tag::HTTP_URL, $rootSpan->meta)) { - $rootSpan->meta[Tag::HTTP_URL] = \DDTrace\Util\Normalizer::urlSanitize( + if (!Integration::hasTag($rootSpan, Tag::HTTP_URL)) { + $rootSpan->attributes[Tag::HTTP_URL] = \DDTrace\Util\Normalizer::urlSanitize( $request->getScheme() . '://' . $request->getHttpHost() . $request->getRequestUri() diff --git a/src/DDTrace/OpenTelemetry/Context.php b/src/DDTrace/OpenTelemetry/Context.php index 47efb029ae..be653be3a6 100644 --- a/src/DDTrace/OpenTelemetry/Context.php +++ b/src/DDTrace/OpenTelemetry/Context.php @@ -211,7 +211,11 @@ private static function activateParent(?SpanData $currentSpan): ContextInterface $currentSpan, API\SpanContext::create($currentTraceId, $currentSpanId, $traceFlags, $traceState), // $context self::getDDInstrumentationScope(), // $instrumentationScope - isset($currentSpan->meta[Tag::SPAN_KIND]) ? self::convertDDSpanKindToOtel($currentSpan->meta[Tag::SPAN_KIND]) : API\SpanKind::KIND_INTERNAL, // $kind + isset($currentSpan->attributes[Tag::SPAN_KIND]) || isset($currentSpan->meta[Tag::SPAN_KIND]) + ? self::convertDDSpanKindToOtel( + $currentSpan->attributes[Tag::SPAN_KIND] ?? $currentSpan->meta[Tag::SPAN_KIND] + ) + : API\SpanKind::KIND_INTERNAL, // $kind API\Span::fromContext($parentContext), // $parentSpan (TODO: Handle null parent span) ? $parentContext, // $parentContext NoopSpanProcessor::getInstance(), // $spanProcessor diff --git a/src/DDTrace/OpenTelemetry/Convention.php b/src/DDTrace/OpenTelemetry/Convention.php index 3ba0d21880..95121cbc15 100644 --- a/src/DDTrace/OpenTelemetry/Convention.php +++ b/src/DDTrace/OpenTelemetry/Convention.php @@ -10,7 +10,7 @@ class Convention { public static function defaultOperationName(SpanData $span): string { - $meta = $span->meta; + $meta = $span->attributes + $span->meta; $spanKind = $meta[Tag::SPAN_KIND] ?? null; switch (true) { diff --git a/src/DDTrace/OpenTelemetry/Span.php b/src/DDTrace/OpenTelemetry/Span.php index d298013ca4..1b5317d39d 100644 --- a/src/DDTrace/OpenTelemetry/Span.php +++ b/src/DDTrace/OpenTelemetry/Span.php @@ -276,7 +276,7 @@ public function getKind(): int */ public function getAttribute(string $key): mixed { - return $this->span->meta[$key] ?? ($this->span->metrics[$key] ?? null); + return $this->span->attributes[$key] ?? null; } public function getStartEpochNanos(): int @@ -305,19 +305,14 @@ public function isRecording(): bool private static function _setAttribute(SpanData $span, string $key, $value): void { if ($value === null) { - unset($span->meta[$key]); - unset($span->metrics[$key]); + unset($span->attributes[$key]); } elseif ($key[0] === '_' && \strncmp($key, '_dd.p.', 6) === 0) { $distributedKey = \substr($key, 6); // strlen('_dd.p.') === 6 \DDTrace\add_distributed_tag($distributedKey, $value); - } elseif (\is_float($value) - || \is_int($value) - || (\is_array($value) && \count($value) > 0 && \is_numeric($value[0]))) { // Note: Assumes attribute with primitive, homogeneous array values - $span->metrics[$key] = $value; } elseif ($key === 'service.name') { $span->service = $value; } else { - $span->meta[$key] = $value; + $span->attributes[$key] = $value; } } @@ -445,11 +440,11 @@ public function setStatus(string $code, ?string $description = null): SpanInterf } if ($this->status->getCode() === API\StatusCode::STATUS_UNSET && $code === API\StatusCode::STATUS_ERROR) { - $this->span->meta[Tag::ERROR_MSG] = $description; + $this->span->attributes[Tag::ERROR_MSG] = $description; } elseif ($this->status->getCode() === API\StatusCode::STATUS_ERROR && $code === API\StatusCode::STATUS_OK) { - unset($this->span->meta[Tag::ERROR_MSG]); - unset($this->span->meta[Tag::ERROR_TYPE]); - unset($this->span->meta[Tag::ERROR_STACK]); + unset($this->span->attributes[Tag::ERROR_MSG]); + unset($this->span->attributes[Tag::ERROR_TYPE]); + unset($this->span->attributes[Tag::ERROR_STACK]); } $this->status = StatusData::create($code, $description); diff --git a/src/DDTrace/Processing/TraceAnalyticsProcessor.php b/src/DDTrace/Processing/TraceAnalyticsProcessor.php index 86c6b735bb..cd78b9bafd 100644 --- a/src/DDTrace/Processing/TraceAnalyticsProcessor.php +++ b/src/DDTrace/Processing/TraceAnalyticsProcessor.php @@ -2,29 +2,19 @@ namespace DDTrace\Processing; -use DDTrace\Data\Span as DataSpan; -use DDTrace\Tag; - /** - * A span processor in charge of adding the trace analytics client config metric when appropriate. - * - * NOTE: this may be transformer into a filter for consistency with other tracers, but for now we did not implement - * any filtering functionality so giving it such name as of now might be misleading. + * @deprecated App Analytics is deprecated and no longer has any effect. */ final class TraceAnalyticsProcessor { /** - * @param array $metrics - * @param bool|float $value - */ + * @deprecated App Analytics is deprecated. This is now a no-op and does not + * modify $metrics or emit the _dd1.sr.eausr metric. + * + * @param array $metrics + * @param bool|float $value + */ public static function normalizeAnalyticsValue(&$metrics, $value) { - if (true === $value) { - $metrics[Tag::ANALYTICS_KEY] = 1.0; - } elseif (false === $value) { - unset($metrics[Tag::ANALYTICS_KEY]); - } elseif (is_numeric($value) && 0 <= $value && $value <= 1) { - $metrics[Tag::ANALYTICS_KEY] = (float)$value; - } } } diff --git a/src/DDTrace/Span.php b/src/DDTrace/Span.php index 82cba27474..a928f23e0b 100644 --- a/src/DDTrace/Span.php +++ b/src/DDTrace/Span.php @@ -146,7 +146,7 @@ public function setTag($key, $value, $setIfFinished = false) } if ($key === Tag::ERROR_MSG) { - $this->internalSpan->meta[$key] = (string)$value; + $this->internalSpan->attributes[$key] = (string)$value; $this->setError(true); return; } @@ -182,8 +182,8 @@ public function setTag($key, $value, $setIfFinished = false) if ($key === Tag::HTTP_STATUS_CODE && $value >= 500) { $this->hasError = true; - if (!isset($this->internalSpan->meta[Tag::ERROR_TYPE])) { - $this->internalSpan->meta[Tag::ERROR_TYPE] = 'Internal Server Error'; + if (!isset($this->internalSpan->attributes[Tag::ERROR_TYPE])) { + $this->internalSpan->attributes[Tag::ERROR_TYPE] = 'Internal Server Error'; } } @@ -198,7 +198,7 @@ public function setTag($key, $value, $setIfFinished = false) } } - $this->internalSpan->meta[$key] = (string)$value; + $this->internalSpan->attributes[$key] = (string)$value; } /** @@ -244,7 +244,8 @@ public function setMetric($key, $value) return; } - $this->internalSpan->metrics[$key] = $value; + // As a double, which is what the metrics bucket held on the wire. + $this->internalSpan->attributes[$key] = is_array($value) ? $value : (float)$value; } /** @@ -275,9 +276,9 @@ public function setError($error) { if (($error instanceof Exception) || ($error instanceof Throwable)) { $this->hasError = true; - $this->internalSpan->meta[Tag::ERROR_MSG] = $error->getMessage(); - $this->internalSpan->meta[Tag::ERROR_TYPE] = get_class($error); - $this->internalSpan->meta[Tag::ERROR_STACK] = $error->getTraceAsString(); + $this->internalSpan->attributes[Tag::ERROR_MSG] = $error->getMessage(); + $this->internalSpan->attributes[Tag::ERROR_TYPE] = get_class($error); + $this->internalSpan->attributes[Tag::ERROR_STACK] = $error->getTraceAsString(); return; } @@ -300,8 +301,8 @@ public function setError($error) public function setRawError($message, $type) { $this->hasError = true; - $this->internalSpan->meta[Tag::ERROR_MSG] = $message; - $this->internalSpan->meta[Tag::ERROR_TYPE] = $type; + $this->internalSpan->attributes[Tag::ERROR_MSG] = $message; + $this->internalSpan->attributes[Tag::ERROR_TYPE] = $type; } public function hasError() @@ -377,7 +378,7 @@ public function log(array $fields = [], $timestamp = null) // messages, and logging multiple messages is not prohibited by the OpenTracing spec: // https://opentracing.io/docs/overview/tags-logs-baggage/#logs // We want to deprecate this behavior and change it. In the meantime we apply this workaround. - $this->internalSpan->meta[Tag::ERROR_MSG] = (string)$value; + $this->internalSpan->attributes[Tag::ERROR_MSG] = (string)$value; } elseif ($key === Tag::LOG_STACK) { $this->setTag(Tag::ERROR_STACK, $value); } diff --git a/src/api/GlobalTracer.php b/src/api/GlobalTracer.php index a3bd94eb18..339535b453 100644 --- a/src/api/GlobalTracer.php +++ b/src/api/GlobalTracer.php @@ -9,6 +9,9 @@ use DDTrace\Contracts\Tracer as TracerInterface; +/* + * @deprecated This class is deprecated, you should use the Otel or the extension API instead. + */ final class GlobalTracer { /** diff --git a/src/api/Tag.php b/src/api/Tag.php index f2cb6b7c1e..4bfdecd184 100644 --- a/src/api/Tag.php +++ b/src/api/Tag.php @@ -38,6 +38,7 @@ class Tag const TARGET_HOST = 'out.host'; const TARGET_PORT = 'out.port'; const BYTES_OUT = 'net.out.bytes'; + /** @deprecated App Analytics is deprecated; setting this metric no longer has any effect. */ const ANALYTICS_KEY = '_dd1.sr.eausr'; const HOSTNAME = '_dd.hostname'; const ORIGIN = '_dd.origin'; diff --git a/src/ddtrace_php_api.stubs.php b/src/ddtrace_php_api.stubs.php index 6b32afbcc7..16c79106d1 100644 --- a/src/ddtrace_php_api.stubs.php +++ b/src/ddtrace_php_api.stubs.php @@ -301,14 +301,14 @@ public static function createFromLocalSpan(\DDTrace\SpanData $span, bool $sample } namespace DDTrace\Processing { /** - * A span processor in charge of adding the trace analytics client config metric when appropriate. - * - * NOTE: this may be transformer into a filter for consistency with other tracers, but for now we did not implement - * any filtering functionality so giving it such name as of now might be misleading. + * @deprecated App Analytics is deprecated and no longer has any effect. */ final class TraceAnalyticsProcessor { /** + * @deprecated App Analytics is deprecated. This is now a no-op and does not + * modify $metrics or emit the _dd1.sr.eausr metric. + * * @param array $metrics * @param bool|float $value */ @@ -2241,6 +2241,7 @@ class Tag const TARGET_HOST = 'out.host'; const TARGET_PORT = 'out.port'; const BYTES_OUT = 'net.out.bytes'; + /** @deprecated App Analytics is deprecated; setting this metric no longer has any effect. */ const ANALYTICS_KEY = '_dd1.sr.eausr'; const HOSTNAME = '_dd.hostname'; const ORIGIN = '_dd.origin'; From aa9c20fdf7d115837d6f4181a0cdbc7815041159 Mon Sep 17 00:00:00 2001 From: Alexandre Rulleau Date: Thu, 1 Oct 2026 18:02:45 +0200 Subject: [PATCH 3/5] test: migrate tests to the V1 span introspection shape dd_trace_serialize_closed_spans() now reports the V1 shape: a typed attributes map with promoted fields (span_kind, component, sampling_priority, ...) and native span links and events. Migrate the phpt, PHPUnit and snapshot tests to it, and add coverage for the V1 and v0.4 wires, span attributes, ignoreError and the default root component. Remove tests for the retired userland msgpack serializer and thread sender (dd_trace_serialize_msgpack, dd_trace_send_traces_via_thread, the in-process background sender capability tests) and for the removed App Analytics trace search config. --- .../api_security_telemetry_missing_route.phpt | 4 +- .../client_init_record_span_tags.phpt | 2 + .../extension/rinit_record_span_tags.phpt | 2 + .../extension/rinit_root_span_add_tag.phpt | 1 + .../extension/rinit_rshutdown_basic.phpt | Bin 5232 -> 5238 bytes appsec/tests/extension/root_span_add_tag.phpt | 37 +-- .../EndpointFallbackSamplingTests.groovy | 4 +- .../test_ddtrace_is_fully_loaded.php | 8 +- .../API/MessagePackSerializationBench.php | 41 ---- tests/Common/CLITestCase.php | 11 +- tests/Common/SnapshotTestTrait.php | 3 +- tests/Common/SpanAssertionTrait.php | 11 +- tests/Common/SpanChecker.php | 215 ++++++++++++++++-- tests/Common/TracerTestTrait.php | 12 + .../Composer/ComposerInteroperabilityTest.php | 10 + tests/DistributedTracing/SyntheticsTest.php | 1 + tests/Integration/DatabaseMonitoringTest.php | 8 +- .../LongRunning/LongRunningScriptTest.php | 11 +- tests/Integration/ResponseStatusCodeTest.php | 2 + tests/Integration/TracerTest.php | 24 +- .../Integrations/Curl/CurlIntegrationTest.php | 106 +-------- .../Custom/Autoloaded/CommonScenariosTest.php | 3 + .../Custom/Autoloaded/FatalErrorTest.php | 1 + .../Autoloaded/TraceSearchConfigTest.php | 54 ----- .../HttpHeadersConfiguredTest.php | 1 + .../HttpHeadersNotConfiguredTest.php | 1 + .../NotAutoloaded/IncomingUserInfoTest.php | 1 + .../Integrations/Exec/ExecIntegrationTest.php | 8 +- .../Guzzle/V5/GuzzleIntegrationTest.php | 3 +- .../Guzzle/V6/GuzzleIntegrationTest.php | 2 +- .../Laravel/V4/TraceSearchConfigTest.php | 88 ------- .../Laravel/V5_7/TraceSearchConfigTest.php | 85 ------- tests/Integrations/Laravel/V5_8/QueueTest.php | 11 +- .../Laravel/V5_8/TraceSearchConfigTest.php | 85 ------- tests/Integrations/Laravel/V8_x/QueueTest.php | 11 +- .../Laravel/V8_x/TraceSearchConfigTest.php | 84 ------- .../Lumen/V10_0/TraceSearchConfigTest.php | 73 ------ .../Lumen/V5_2/TraceSearchConfigTest.php | 73 ------ .../Lumen/V5_6/TraceSearchConfigTest.php | 73 ------ .../Lumen/V5_8/TraceSearchConfigTest.php | 73 ------ .../Lumen/V8_1/TraceSearchConfigTest.php | 73 ------ .../Lumen/V9_0/TraceSearchConfigTest.php | 73 ------ .../MongoDB/Latest/MongoDBTest.php | 4 +- tests/Integrations/Mysqli/MysqliTest.php | 2 +- tests/Integrations/PDO/PDOTest.php | 15 +- .../Integrations/PHPRedis/V5/PHPRedisTest.php | 4 +- .../Integrations/Predis/Latest/PredisTest.php | 12 +- .../Integrations/Ratchet/V0_4/RatchetTest.php | 2 +- tests/Integrations/SQLSRV/SQLSRVTest.php | 15 +- .../Symfony/Latest/TraceSearchConfigTest.php | 11 - .../Symfony/V3_0/TraceSearchConfigTest.php | 73 ------ .../Symfony/V3_3/TraceSearchConfigTest.php | 82 ------- .../Symfony/V3_4/TraceSearchConfigTest.php | 84 ------- .../Symfony/V4_0/TraceSearchConfigTest.php | 83 ------- .../Symfony/V4_2/TraceSearchConfigTest.php | 84 ------- .../Symfony/V4_4/TraceSearchConfigTest.php | 83 ------- .../Symfony/V5_0/TraceSearchConfigTest.php | 83 ------- .../Symfony/V5_1/TraceSearchConfigTest.php | 83 ------- .../Symfony/V5_2/TraceSearchConfigTest.php | 81 ------- .../Symfony/V6_2/TraceSearchConfigTest.php | 81 ------- .../Symfony/V7_3/TraceSearchConfigTest.php | 11 - .../V1/TraceSearchConfigTest.php | 57 ----- .../V1_21/TraceSearchConfigTest.php | 57 ----- .../Integration/API/BaggageTest.php | 8 +- .../Integration/API/TracerTest.php | 106 ++++----- .../Integration/InteroperabilityTest.php | 101 ++++++-- .../Integration/SpanProvenanceTest.php | 2 +- tests/Unit/ConfigurationTest.php | 41 ---- .../TraceAnalyticsProcessorTest.php | 31 +-- tests/Unit/SpanTest.php | 22 +- tests/WebServer.php | 6 + tests/ext/active_span.phpt | 41 +++- ...al_tag_on_userland_and_internal_spans.phpt | 8 +- tests/ext/analytics_event.phpt | 43 ++++ .../dd_init_open_basedir.phpt | 2 +- .../error_get_last_is_unaffected.phpt | 2 +- .../autoload-php-files/file_not_found.phpt | 2 +- .../ignores_exceptions.phpt | 2 +- .../ignores_fatal_errors.phpt | 2 +- .../ext/background-sender/agent_headers.phpt | 4 +- .../agent_headers_container_id.phpt | 3 +- .../agent_headers_container_id_empty.phpt | 3 +- .../agent_headers_container_id_fargate.phpt | 3 +- .../agent_headers_ignore_userland.phpt | 49 ---- .../agent_headers_unix_domain_socket.phpt | 1 + .../ext/background-sender/agent_sampling.phpt | 7 +- ...ckground_sender_restores_capabilities.phpt | 79 ------- .../background_sender_survives_setuid.phpt | 77 ------- tests/ext/base_service.phpt | 10 +- tests/ext/client_side_stats_top_level.phpt | 2 +- tests/ext/close_spans_until.phpt | 16 +- .../dd_trace_send_traces_via_thread_001.phpt | 23 -- .../dd_trace_send_traces_via_thread_002.phpt | 21 -- .../dd_trace_serialize_header_to_meta.phpt | 8 +- tests/ext/dd_trace_serialize_msgpack.phpt | 40 ---- .../ext/dd_trace_serialize_msgpack_error.phpt | 34 --- ...dd_trace_serialize_msgpack_id_in_meta.phpt | 36 --- .../dd_trace_serialize_msgpack_reference.phpt | 47 ---- tests/ext/dd_trace_span_data_get_link.phpt | 2 +- ...ce_span_data_serialization_with_links.phpt | 89 ++++++-- ...n_link_event_native_nested_attributes.phpt | 62 +++++ .../distributed_trace_asm_standalone_01.phpt | 40 ++-- .../distributed_trace_asm_standalone_02.phpt | 36 ++- .../distributed_trace_asm_standalone_03.phpt | 2 +- .../distributed_trace_asm_standalone_04.phpt | 2 +- .../distributed_trace_asm_standalone_05.phpt | 2 +- .../distributed_trace_asm_standalone_06.phpt | 6 +- .../distributed_trace_asm_standalone_07.phpt | 4 +- .../distributed_trace_asm_standalone_08.phpt | 2 +- .../distributed_trace_asm_standalone_09.phpt | 2 +- .../distributed_trace_bogus_ids.phpt | 31 ++- .../distributed_trace_inherit.phpt | 38 ++-- ...stributed_trace_overwrite_active_span.phpt | 21 +- ...f_class_or_function_exists_by_default.phpt | 2 - tests/ext/env_meta_fallback_promoted.phpt | 35 +++ tests/ext/extract_ip_private_01.phpt | 2 +- tests/ext/extract_server_values.phpt | 19 +- tests/ext/fibers/fiber_observer_bailout.phpt | 6 +- tests/ext/fibers/fiber_stack_switch.phpt | 6 +- tests/ext/flush-autofinish.phpt | 4 +- tests/ext/force_flush_traces.phpt | 2 +- tests/ext/generate_128_bit_trace_id.phpt | 4 +- ...t_resource_renaming_always_simplified.phpt | 8 +- ...http_endpoint_resource_renaming_basic.phpt | 9 +- tests/ext/includes/fake_tracer.inc | 4 +- tests/ext/inferred_proxy/alter_service.phpt | 47 ++-- tests/ext/inferred_proxy/basic_test.phpt | 49 ++-- .../consume_distributed_tracing_headers.phpt | 40 ++-- .../inferred_proxy/distributed_tracing.phpt | 50 ++-- .../ext/inferred_proxy/error_propagated.phpt | 53 ++--- .../inferred_proxy/fallback_service_name.phpt | 49 ++-- .../inferred_proxy/incomplete_headers.phpt | 39 ++-- tests/ext/inferred_proxy/multiple_traces.phpt | 74 +++--- .../propagated_tags_after_span_start.phpt | 49 ++-- .../propagated_tags_before_span_start.phpt | 45 ++-- tests/ext/inferred_proxy/sampling_rules.phpt | 37 ++- .../security_headers_forwarded.phpt | 8 +- .../serialization-sampling-chunk.phpt | 10 +- tests/ext/inherit_meta_from_parent.phpt | 9 +- .../curl/distributed_tracing_curl.phpt | 2 +- .../distributed_tracing_curl_copy_handle.phpt | 2 +- .../distributed_tracing_curl_drop_dm.phpt | 2 +- ...ted_tracing_curl_existing_headers_001.phpt | 2 +- ...ted_tracing_curl_existing_headers_002.phpt | 2 +- ...ted_tracing_curl_existing_headers_003.phpt | 2 +- ...distributed_tracing_curl_invalid_tags.phpt | 2 +- ...stributed_tracing_curl_multi_exec_001.phpt | 2 +- ...stributed_tracing_curl_multi_exec_002.phpt | 2 +- ...stributed_tracing_curl_multi_exec_003.phpt | 2 +- ...d_tracing_curl_multi_exec_copy_handle.phpt | 2 +- ..._curl_multi_exec_existing_headers_001.phpt | 2 +- ..._curl_multi_exec_existing_headers_002.phpt | 2 +- .../distributed_tracing_curl_tracestate.phpt | 2 +- .../drupal/drupal_integration.inc | 4 +- ...me_engine_service_dropped_nested_span.phpt | 2 +- .../theme_render_dropped_nested_span.phpt | 2 +- .../distributed_tracing_http_streams.phpt | 10 +- ...acing_http_streams_with_headers_array.phpt | 2 +- ...cing_http_streams_with_headers_string.phpt | 2 +- ...t_metadata_injection_from_valid_files.phpt | 4 +- ...metadata_injection_from_invalid_files.phpt | 78 ++++--- .../source_code/commit_sha_env_var.phpt | 31 ++- .../git_metadata_injection_from_env.phpt | 39 ++-- ...t_metadata_injection_from_global_tags.phpt | 43 ++-- ...injection_remove_credentials_from_env.phpt | 37 ++- .../source_code/repository_url_env_var.phpt | 33 ++- tests/ext/ip_collection_01.phpt | 2 +- tests/ext/ip_collection_02.phpt | 2 +- tests/ext/ip_collection_03.phpt | 2 +- tests/ext/ip_collection_04.phpt | 2 +- tests/ext/ip_collection_05.phpt | 2 +- tests/ext/limiter/002-limiter-reached.phpt | 4 +- .../003-limiter-with-asm-standalone.phpt | 2 +- .../debugger_span_decoration_probe.phpt | 10 +- tests/ext/nested_exceptions.phpt | 10 +- ...l_http_response_status_code_remapping.phpt | 6 +- ...onse_status_code_remapping_precedence.phpt | 6 +- .../ext/otel_http_status_code_remapping.phpt | 6 +- .../pcntl_fork_long_running_autoflush.phpt | 8 +- tests/ext/peer_service_disabled_default.phpt | 12 +- tests/ext/peer_service_honor_user_value.phpt | 18 +- tests/ext/peer_service_remapping.phpt | 30 +-- ...rvice_sources_not_serialized_when_set.phpt | 4 +- ...ice_sources_not_serialized_when_unset.phpt | 4 +- .../peer_service_use_first_available_tag.phpt | 24 +- tests/ext/peer_service_wrong_values.phpt | 18 +- ...-rule-name-as-glob-with-question-mark.phpt | 3 +- .../serialization-chunk.phpt | 12 +- tests/ext/process_tags.phpt | 6 +- tests/ext/referrer_extraction_01.phpt | 25 +- tests/ext/referrer_extraction_02.phpt | 27 +-- tests/ext/referrer_extraction_03.phpt | 25 +- tests/ext/referrer_extraction_04.phpt | 25 +- tests/ext/referrer_extraction_05.phpt | 27 +-- .../request-replayer/analytics_event_v04.phpt | 57 +++++ .../client_side_stats_dd_tags_env.phpt | 63 +++++ ...ent_side_stats_inferred_span_sampling.phpt | 69 ++++++ .../dd_trace_exception_span_event.phpt | 37 ++- .../request-replayer/dd_trace_span_event.phpt | 43 +++- .../dd_trace_span_link_with_exception.phpt | 22 +- .../serializer_wire_inprocess_multitrace.phpt | 67 ++++++ .../serializer_wire_inprocess_v04.phpt | 61 +++++ .../serializer_wire_inprocess_v1.phpt | 53 +++++ .../serializer_wire_sidecar_forced_v04.phpt | 43 ++++ .../serializer_wire_sidecar_v1.phpt | 56 +++++ .../span_attributes_v04_wire.phpt | 69 ++++++ .../span_link_event_attributes_v04_wire.phpt | 76 +++++++ .../top_level_marked_on_v1_wire.phpt | 64 ++++++ .../traced_attribute_tags_v04_wire.phpt | 72 ++++++ tests/ext/root_span_default_component.phpt | 17 ++ .../ext/root_span_default_component_cli.phpt | 15 ++ ...span_default_component_framework_wins.phpt | 17 ++ tests/ext/root_span_http_client_ip.phpt | 2 +- ...oot_span_http_client_ip_custom_header.phpt | 2 +- ...n_http_client_ip_duplicate_ip_headers.phpt | 14 +- ...t_span_http_client_ip_x_forwarded_for.phpt | 2 +- tests/ext/root_span_http_useragent.phpt | 2 +- .../root_span_security_testing_headers.phpt | 4 +- ..._span_security_testing_headers_absent.phpt | 4 +- .../ext/root_span_url_as_resource_names.phpt | 29 +-- ...ot_span_url_as_resource_names_no_host.phpt | 29 +-- tests/ext/root_span_url_with_post_array.phpt | 8 +- ...root_span_url_with_post_array_allowed.phpt | 6 +- tests/ext/root_span_url_with_post_fields.phpt | 12 +- ...span_url_with_post_implicit_array_key.phpt | 4 +- .../ext/root_span_url_with_post_no_param.phpt | 19 +- .../root_span_url_with_post_no_param_set.phpt | 19 +- ...pan_url_with_post_only_allowed_params.phpt | 8 +- ...t_span_url_with_post_simple_whitelist.phpt | 6 +- .../ext/root_span_url_with_query_params.phpt | 2 +- ...pan_url_with_query_params_obfuscation.phpt | 2 +- ...l_with_query_params_obfuscation_empty.phpt | 2 +- ..._span_url_with_query_params_whitelist.phpt | 2 +- .../root_span_url_without_query_params.phpt | 2 +- ...ampling_mechanism_from_decision_maker.phpt | 29 +++ .../ext/sandbox-prehook/dd_trace_method.phpt | 68 +++--- .../sandbox-prehook/exception_error_log.phpt | 2 +- .../sandbox-prehook/exception_handling.phpt | 12 +- .../class_resolver_bailout_hook.phpt | 2 +- .../limiter_reset_flush_with_open_spans.phpt | 8 +- .../nested_dropped_spans.phpt | 2 - .../reset_configured_overrides.phpt | 9 +- tests/ext/sandbox/auto_flush.phpt | 6 +- .../sandbox/auto_flush_attach_exception.phpt | 2 +- .../sandbox/auto_flush_disables_tracing.phpt | 6 +- .../sandbox/auto_flush_sandbox_exception.phpt | 2 +- .../auto_flush_userland_root_span.phpt | 6 +- tests/ext/sandbox/dd_dumper.inc | 32 +-- .../ext/sandbox/dd_trace_function_alias.phpt | 2 - .../sandbox/dd_trace_function_complex.phpt | 101 ++++---- .../sandbox/dd_trace_function_internal.phpt | 27 +-- .../sandbox/dd_trace_function_userland.phpt | 4 +- tests/ext/sandbox/dd_trace_method.phpt | 76 +++---- tests/ext/sandbox/dd_trace_method_alias.phpt | 2 - .../ext/sandbox/default_span_properties.phpt | 6 +- .../default_span_properties_method.phpt | 2 - .../deferred_load_attempt_loading_once.phpt | 2 +- tests/ext/sandbox/die_in_sandbox.phpt | 6 +- .../errors_are_flagged_from_userland.phpt | 31 ++- tests/ext/sandbox/exception_error_log.phpt | 2 +- ...tion_from_user_error_handler_internal.phpt | 6 +- ...ption_handled_for_correct_catch_block.phpt | 2 +- ...eption_handled_in_correct_catch_frame.phpt | 4 +- .../exception_handled_in_multicatch.phpt | 2 +- .../exception_handled_with_finally.phpt | 2 +- tests/ext/sandbox/exception_handling.phpt | 12 +- ...ons_are_passed_to_the_tracing_closure.phpt | 4 +- ...inal_call_rethrown_in_tracing_closure.phpt | 2 +- .../sandbox/fatal_errors_are_tracked_001.phpt | 6 +- .../sandbox/fatal_errors_are_tracked_002.phpt | 6 +- .../sandbox/fatal_errors_are_tracked_003.phpt | 6 +- .../sandbox/fatal_errors_are_tracked_004.phpt | 6 +- .../sandbox/fatal_errors_are_tracked_005.phpt | 6 +- .../ext/sandbox/generator_with_exception.phpt | 2 +- tests/ext/sandbox/hook_function/03.phpt | 2 +- .../hook_does_not_leak_error.phpt | 2 +- .../hook_function/posthook_error_02.phpt | 2 +- .../hook_function/posthook_exceptions_04.phpt | 2 +- .../hook_function/prehook_error_02.phpt | 2 +- .../hook_function/prehook_exceptions_02.phpt | 2 +- .../hook_function/prehook_exceptions_04.phpt | 2 +- tests/ext/sandbox/hook_method/03.phpt | 2 +- .../ext/sandbox/hook_method/posthook_07.phpt | 2 +- .../hook_method/posthook_error_02.phpt | 2 +- .../sandbox/hook_method/prehook_error_02.phpt | 2 +- .../hook_method/prehook_exceptions_02.phpt | 2 +- .../install_hook/hook_scoped_file.phpt | 2 - .../sandbox/install_hook/trace_callable.phpt | 3 - .../sandbox/install_hook/trace_closure.phpt | 8 - .../trace_closure_from_callable.phpt | 6 +- .../install_hook/trace_closure_ge_php_84.phpt | 8 - .../ext/sandbox/install_hook/trace_file.phpt | 4 - .../sandbox/install_hook/trace_function.phpt | 2 - .../sandbox/install_hook/trace_generator.phpt | 1 - .../trace_generator_ge_php_84.phpt | 1 - tests/ext/sandbox/manual_flush.phpt | 4 +- .../retval_is_null_with_exception.phpt | 2 +- .../ext/sandbox/safe_to_string_metadata.phpt | 114 ++++++---- ...to_string_metadata_drops_invalid_keys.phpt | 4 +- .../safe_to_string_metadata_ge_php_84.phpt | 115 ++++++---- tests/ext/sandbox/safe_to_string_metrics.phpt | 50 +++- tests/ext/sandbox/span_clone.phpt | 140 ++++++++---- ...c_tracing_closures_will_not_bind_this.phpt | 2 +- tests/ext/sdk_otlp_export_marker.phpt | 2 +- .../accept-single-span.phpt | 6 +- .../check-sample-rate.phpt | 8 +- .../limited-single-span-with-match.phpt | 6 +- .../limited-single-span.phpt | 4 +- .../name-matching-single-span.phpt | 4 +- ...single-span-sampling-config-from-file.phpt | 4 +- tests/ext/span_attributes_empty_keys.phpt | 27 +++ tests/ext/span_attributes_input.phpt | 119 ++++++++++ tests/ext/span_data_attributes_init.phpt | 47 ++++ tests/ext/span_data_meta_view.phpt | 141 ++++++++++++ tests/ext/span_data_meta_view_jit.phpt | 48 ++++ tests/ext/span_ignore_error.phpt | 65 ++++++ .../ext/span_kind_meta_fallback_promoted.phpt | 30 +++ .../span_link_event_recursive_attributes.phpt | 57 +++++ tests/ext/span_on_close.phpt | 6 +- tests/ext/span_stack/span_stack_clone.phpt | 10 - tests/ext/span_stack/span_stack_swap.phpt | 4 - .../span_stack_swap_traced_function.phpt | 2 - .../span_trace_stack_autoclose.phpt | 2 - tests/ext/span_stack/span_trace_swap.phpt | 4 - .../ext/span_stack/start_span_new_trace.phpt | 4 - tests/ext/span_stack/start_span_stack.phpt | 2 - .../start_top_level_span_stack.phpt | 2 - tests/ext/span_with_removed_exception.phpt | 81 +++---- tests/ext/start_span_with_all_properties.phpt | 62 +++-- tests/ext/start_span_without_closing.phpt | 27 +-- ...start_span_without_closing_autofinish.phpt | 4 +- tests/ext/svc_auto_tag_cli.phpt | 2 +- tests/ext/svc_auto_tag_otel.phpt | 2 +- tests/ext/svc_runtime_change.phpt | 2 +- tests/ext/svc_src_default_cleared.phpt | 4 +- tests/ext/svc_src_inheritance.phpt | 4 +- tests/ext/svc_src_manual_override.phpt | 4 +- tests/ext/svc_user_tag.phpt | 2 +- tests/ext/telemetry/broken_pipe.phpt | 2 +- tests/ext/test_special_attributes.phpt | 17 +- tests/ext/test_special_attributes_bis.phpt | 17 +- tests/ext/traced_attribute.phpt | 22 +- tests/ext/traced_attribute_delayed.phpt | 4 - ...ed_attribute_tags_recursive_and_empty.phpt | 32 +++ tests/ext/ust.phpt | 60 +++-- tests/ext/ust_precedence_over_ddtags.phpt | 8 +- tests/ext/ust_via_ddtags.phpt | 8 +- .../dd_trace_send_traces_via_thread.phpt | 59 ----- .../span_attributes_immutable_arrays.phpt | 45 ++++ ...oller_test.test_scenario_health_check.json | 1 + ..._test.test_silenced_spans_are_dropped.json | 13 ++ ..._test.test_silenced_spans_are_dropped.json | 13 ++ ..._test.test_silenced_spans_are_dropped.json | 13 ++ ..._test.test_silenced_spans_are_dropped.json | 13 ++ ..._test.test_silenced_spans_are_dropped.json | 13 ++ ..._test.test_scenario_get_parameterized.json | 1 + ..._test.test_scenario_get_return_string.json | 1 + ...st.test_scenario_get_to_missing_route.json | 1 + ...est_scenario_get_to_missing_route_cgi.json | 1 + ...test.test_scenario_get_with_exception.json | 1 + ....test_scenario_get_with_exception_cgi.json | 1 + ...rios_test.test_scenario_get_with_view.json | 1 + ...ter.v3_1.exit_test.test_scenario_exit.json | 1 + ...st.test_scenario_get_to_missing_route.json | 1 + ...test.test_scenario_get_with_exception.json | 1 + ...rios_test.test_scenario_get_with_view.json | 1 + ...st.test_scenario_get_to_missing_route.json | 1 + ...test.test_scenario_get_with_exception.json | 1 + ...rios_test.test_scenario_get_with_view.json | 1 + ...st.test_scenario_get_to_missing_route.json | 1 + ...test.test_scenario_get_with_exception.json | 1 + ...rios_test.test_scenario_get_with_view.json | 1 + ...stributed_tracing_high_level_producer.json | 1 + ...t.test_span_links_high_level_consumer.json | 2 + ...t.test_span_links_high_level_producer.json | 1 + ...st.test_span_links_low_level_consumer.json | 3 + ...st.test_span_links_low_level_producer.json | 1 + ...atest.rest_test.test_scenario_rest2xx.json | 1 + ...atest.rest_test.test_scenario_rest4xx.json | 1 + ...atest.rest_test.test_scenario_rest5xx.json | 1 + ..._test.test_scenario_get_return_string.json | 1 + ...st.test_scenario_get_to_missing_route.json | 1 + ...test.test_scenario_get_with_exception.json | 1 + ...rios_test.test_scenario_get_with_view.json | 1 + ..._test.test_scenario_get_return_string.json | 1 + ...st.test_scenario_get_to_missing_route.json | 1 + ...test.test_scenario_get_with_exception.json | 1 + ...rios_test.test_scenario_get_with_view.json | 1 + ...pigw_test.test_laravel_inferred_proxy.json | 4 + ...test_laravel_inferred_proxy_exception.json | 4 + ..._test.test_scenario_get_dynamic_route.json | 1 + ..._test.test_scenario_get_return_string.json | 1 + ...st.test_scenario_get_to_missing_route.json | 1 + ...test.test_scenario_get_with_exception.json | 1 + ...t_scenario_get_with_ignored_exception.json | 1 + ...rios_test.test_scenario_get_with_view.json | 1 + ...octane.apigw_test.test_inferred_proxy.json | 4 + ...gw_test.test_inferred_proxy_exception.json | 4 + ..._test.test_scenario_get_dynamic_route.json | 1 + ..._test.test_scenario_get_return_string.json | 1 + ...st.test_scenario_get_to_missing_route.json | 1 + ...test.test_scenario_get_with_exception.json | 1 + ...t_scenario_get_with_ignored_exception.json | 1 + ...rios_test.test_scenario_get_with_view.json | 1 + ..._test.test_scenario_get_dynamic_route.json | 1 + ..._test.test_scenario_get_return_string.json | 1 + ...st.test_scenario_get_to_missing_route.json | 1 + ...test.test_scenario_get_with_exception.json | 1 + ...rios_test.test_scenario_get_with_view.json | 1 + ..._test.test_scenario_get_dynamic_route.json | 10 + ..._test.test_scenario_get_return_string.json | 10 + ...st.test_scenario_get_to_missing_route.json | 10 + ...test.test_scenario_get_with_exception.json | 10 + ...rios_test.test_scenario_get_with_view.json | 10 + ..._test.test_scenario_get_dynamic_route.json | 1 + ..._test.test_scenario_get_return_string.json | 1 + ...st.test_scenario_get_to_missing_route.json | 1 + ...test.test_scenario_get_with_exception.json | 1 + ...rios_test.test_scenario_get_with_view.json | 1 + ..._test.test_scenario_get_dynamic_route.json | 1 + ..._test.test_scenario_get_return_string.json | 1 + ...st.test_scenario_get_to_missing_route.json | 1 + ...test.test_scenario_get_with_exception.json | 1 + ...rios_test.test_scenario_get_with_view.json | 1 + ...aravel.v8_x.queue_test.test_broadcast.json | 1 + ..._test.test_scenario_get_dynamic_route.json | 1 + ..._test.test_scenario_get_return_string.json | 1 + ...st.test_scenario_get_to_missing_route.json | 1 + ...test.test_scenario_get_with_exception.json | 1 + ...rios_test.test_scenario_get_with_view.json | 1 + ..._test.test_scenario_get_return_string.json | 1 + ...st.test_scenario_get_to_missing_route.json | 1 + ...test.test_scenario_get_with_exception.json | 1 + ...rios_test.test_scenario_get_with_view.json | 1 + ..._test.test_scenario_get_return_string.json | 1 + ...st.test_scenario_get_to_missing_route.json | 1 + ...test.test_scenario_get_with_exception.json | 1 + ...rios_test.test_scenario_get_with_view.json | 1 + ...runner.apigw_test.test_inferred_proxy.json | 4 + ...gw_test.test_inferred_proxy_exception.json | 4 + ...st.test_scenario_get_to_missing_route.json | 1 + ...nger_test.test_async_success_consumer.json | 5 + ..._test.test_scenario_get_return_string.json | 1 + ...st.test_scenario_get_to_missing_route.json | 1 + ...test.test_scenario_get_with_exception.json | 1 + ...rios_test.test_scenario_get_with_view.json | 1 + ...ame_test.test_resource_to_uri_mapping.json | 1 + ..._test.test_scenario_get_return_string.json | 1 + ...st.test_scenario_get_to_missing_route.json | 1 + ...test.test_scenario_get_with_exception.json | 1 + ...rios_test.test_scenario_get_with_view.json | 1 + ...ame_test.test_resource_to_uri_mapping.json | 1 + ...st.test_scenario_get_to_missing_route.json | 1 + ...nger_test.test_async_success_consumer.json | 5 + ..._test.test_scenario_get_return_string.json | 1 + ...test.test_scenario_get_with_exception.json | 1 + ...acks_test.test_scenario_get_with_view.json | 1 + ..._test.test_scenario_get_return_string.json | 1 + ...test.test_scenario_get_with_exception.json | 1 + ...rios_test.test_scenario_get_with_view.json | 1 + ..._test.test_scenario_get_return_string.json | 1 + ...st.test_scenario_get_to_missing_route.json | 1 + ...test.test_scenario_get_with_exception.json | 1 + ...acks_test.test_scenario_get_with_view.json | 1 + ..._test.test_scenario_get_return_string.json | 1 + ...st.test_scenario_get_to_missing_route.json | 1 + ...test.test_scenario_get_with_exception.json | 1 + ...rios_test.test_scenario_get_with_view.json | 1 + ..._test.test_scenario_get_return_string.json | 1 + ...st.test_scenario_get_to_missing_route.json | 1 + ...test.test_scenario_get_with_exception.json | 1 + ...acks_test.test_scenario_get_with_view.json | 1 + ..._test.test_scenario_get_return_string.json | 1 + ...st.test_scenario_get_to_missing_route.json | 1 + ...test.test_scenario_get_with_exception.json | 1 + ...rios_test.test_scenario_get_with_view.json | 1 + ..._test.test_scenario_get_return_string.json | 1 + ...test.test_scenario_get_with_exception.json | 1 + ...acks_test.test_scenario_get_with_view.json | 1 + ..._test.test_scenario_get_return_string.json | 1 + ...test.test_scenario_get_with_exception.json | 1 + ...rios_test.test_scenario_get_with_view.json | 1 + 482 files changed, 3985 insertions(+), 4352 deletions(-) delete mode 100644 tests/Benchmarks/API/MessagePackSerializationBench.php delete mode 100644 tests/Integrations/Custom/Autoloaded/TraceSearchConfigTest.php delete mode 100644 tests/Integrations/Laravel/V4/TraceSearchConfigTest.php delete mode 100644 tests/Integrations/Laravel/V5_7/TraceSearchConfigTest.php delete mode 100644 tests/Integrations/Laravel/V5_8/TraceSearchConfigTest.php delete mode 100644 tests/Integrations/Laravel/V8_x/TraceSearchConfigTest.php delete mode 100644 tests/Integrations/Lumen/V10_0/TraceSearchConfigTest.php delete mode 100644 tests/Integrations/Lumen/V5_2/TraceSearchConfigTest.php delete mode 100644 tests/Integrations/Lumen/V5_6/TraceSearchConfigTest.php delete mode 100644 tests/Integrations/Lumen/V5_8/TraceSearchConfigTest.php delete mode 100644 tests/Integrations/Lumen/V8_1/TraceSearchConfigTest.php delete mode 100644 tests/Integrations/Lumen/V9_0/TraceSearchConfigTest.php delete mode 100644 tests/Integrations/Symfony/Latest/TraceSearchConfigTest.php delete mode 100644 tests/Integrations/Symfony/V3_0/TraceSearchConfigTest.php delete mode 100644 tests/Integrations/Symfony/V3_3/TraceSearchConfigTest.php delete mode 100644 tests/Integrations/Symfony/V3_4/TraceSearchConfigTest.php delete mode 100644 tests/Integrations/Symfony/V4_0/TraceSearchConfigTest.php delete mode 100644 tests/Integrations/Symfony/V4_2/TraceSearchConfigTest.php delete mode 100644 tests/Integrations/Symfony/V4_4/TraceSearchConfigTest.php delete mode 100644 tests/Integrations/Symfony/V5_0/TraceSearchConfigTest.php delete mode 100644 tests/Integrations/Symfony/V5_1/TraceSearchConfigTest.php delete mode 100644 tests/Integrations/Symfony/V5_2/TraceSearchConfigTest.php delete mode 100644 tests/Integrations/Symfony/V6_2/TraceSearchConfigTest.php delete mode 100644 tests/Integrations/Symfony/V7_3/TraceSearchConfigTest.php delete mode 100644 tests/Integrations/ZendFramework/V1/TraceSearchConfigTest.php delete mode 100644 tests/Integrations/ZendFramework/V1_21/TraceSearchConfigTest.php create mode 100644 tests/ext/analytics_event.phpt delete mode 100644 tests/ext/background-sender/agent_headers_ignore_userland.phpt delete mode 100644 tests/ext/background-sender/background_sender_restores_capabilities.phpt delete mode 100644 tests/ext/background-sender/background_sender_survives_setuid.phpt delete mode 100644 tests/ext/dd_trace_send_traces_via_thread_001.phpt delete mode 100644 tests/ext/dd_trace_send_traces_via_thread_002.phpt delete mode 100644 tests/ext/dd_trace_serialize_msgpack.phpt delete mode 100644 tests/ext/dd_trace_serialize_msgpack_error.phpt delete mode 100644 tests/ext/dd_trace_serialize_msgpack_id_in_meta.phpt delete mode 100644 tests/ext/dd_trace_serialize_msgpack_reference.phpt create mode 100644 tests/ext/dd_trace_span_link_event_native_nested_attributes.phpt create mode 100644 tests/ext/env_meta_fallback_promoted.phpt create mode 100644 tests/ext/request-replayer/analytics_event_v04.phpt create mode 100644 tests/ext/request-replayer/client_side_stats_dd_tags_env.phpt create mode 100644 tests/ext/request-replayer/client_side_stats_inferred_span_sampling.phpt create mode 100644 tests/ext/request-replayer/serializer_wire_inprocess_multitrace.phpt create mode 100644 tests/ext/request-replayer/serializer_wire_inprocess_v04.phpt create mode 100644 tests/ext/request-replayer/serializer_wire_inprocess_v1.phpt create mode 100644 tests/ext/request-replayer/serializer_wire_sidecar_forced_v04.phpt create mode 100644 tests/ext/request-replayer/serializer_wire_sidecar_v1.phpt create mode 100644 tests/ext/request-replayer/span_attributes_v04_wire.phpt create mode 100644 tests/ext/request-replayer/span_link_event_attributes_v04_wire.phpt create mode 100644 tests/ext/request-replayer/top_level_marked_on_v1_wire.phpt create mode 100644 tests/ext/request-replayer/traced_attribute_tags_v04_wire.phpt create mode 100644 tests/ext/root_span_default_component.phpt create mode 100644 tests/ext/root_span_default_component_cli.phpt create mode 100644 tests/ext/root_span_default_component_framework_wins.phpt create mode 100644 tests/ext/sampling_mechanism_from_decision_maker.phpt create mode 100644 tests/ext/span_attributes_empty_keys.phpt create mode 100644 tests/ext/span_attributes_input.phpt create mode 100644 tests/ext/span_data_attributes_init.phpt create mode 100644 tests/ext/span_data_meta_view.phpt create mode 100644 tests/ext/span_data_meta_view_jit.phpt create mode 100644 tests/ext/span_ignore_error.phpt create mode 100644 tests/ext/span_kind_meta_fallback_promoted.phpt create mode 100644 tests/ext/span_link_event_recursive_attributes.phpt create mode 100644 tests/ext/traced_attribute_tags_recursive_and_empty.phpt delete mode 100644 tests/ext/wrong-parameter-errors/dd_trace_send_traces_via_thread.phpt create mode 100644 tests/opcache/span_attributes_immutable_arrays.phpt diff --git a/appsec/tests/extension/api_security_telemetry_missing_route.phpt b/appsec/tests/extension/api_security_telemetry_missing_route.phpt index ee15a5c136..c7fc6d3bd3 100644 --- a/appsec/tests/extension/api_security_telemetry_missing_route.phpt +++ b/appsec/tests/extension/api_security_telemetry_missing_route.phpt @@ -42,7 +42,7 @@ var_dump(rshutdown()); $c = $helper->get_commands(); echo "Sampler hash sent: ", $c[0][1][1], "\n"; -match_log('/Telemetry metric api_security\.missing_route added with tags framework:unknown and value 1/'); +match_log('/Telemetry metric api_security\.missing_route added with tags framework:cgi-fcgi and value 1/'); no_match_log('/api_security\.request\./'); ?> @@ -50,5 +50,5 @@ no_match_log('/api_security\.request\./'); bool(true) bool(true) Sampler hash sent: 0 -found message in log matching /Telemetry metric api_security\.missing_route added with tags framework:unknown and value 1/ +found message in log matching /Telemetry metric api_security\.missing_route added with tags framework:cgi-fcgi and value 1/ no message in log matching /api_security\.request\./ diff --git a/appsec/tests/extension/client_init_record_span_tags.phpt b/appsec/tests/extension/client_init_record_span_tags.phpt index cac10102fe..b96e69d0fa 100644 --- a/appsec/tests/extension/client_init_record_span_tags.phpt +++ b/appsec/tests/extension/client_init_record_span_tags.phpt @@ -76,6 +76,7 @@ Array [http.url] => https://localhost:8888/foo [http.method] => GET [span.kind] => server + [component] => cgi-fcgi [http.useragent] => my user agent ) rinit @@ -94,6 +95,7 @@ Array [_dd.runtime_family] => php [_dd.sdk.otlp_export] => false [appsec.event] => true + [component] => cgi-fcgi [http.endpoint] => /foo [http.method] => GET [http.request.headers.user-agent] => my user agent diff --git a/appsec/tests/extension/rinit_record_span_tags.phpt b/appsec/tests/extension/rinit_record_span_tags.phpt index 3562a1d81c..6af3eb9b13 100644 --- a/appsec/tests/extension/rinit_record_span_tags.phpt +++ b/appsec/tests/extension/rinit_record_span_tags.phpt @@ -71,6 +71,7 @@ Array [http.url] => https://localhost:8888/foo [http.method] => GET [span.kind] => server + [component] => cgi-fcgi [http.useragent] => my user agent ) rinit @@ -89,6 +90,7 @@ Array [_dd.runtime_family] => php [_dd.sdk.otlp_export] => false [appsec.event] => true + [component] => cgi-fcgi [http.endpoint] => /foo [http.method] => GET [http.request.headers.user-agent] => my user agent diff --git a/appsec/tests/extension/rinit_root_span_add_tag.phpt b/appsec/tests/extension/rinit_root_span_add_tag.phpt index 144575c847..ec798f7c8f 100644 --- a/appsec/tests/extension/rinit_root_span_add_tag.phpt +++ b/appsec/tests/extension/rinit_root_span_add_tag.phpt @@ -63,6 +63,7 @@ Array [_dd.p.dm] => -0 [_dd.p.tid] => %s [_dd.sdk.otlp_export] => false + [component] => cgi-fcgi [ddappsec] => true [env] => staging [http.method] => GET diff --git a/appsec/tests/extension/rinit_rshutdown_basic.phpt b/appsec/tests/extension/rinit_rshutdown_basic.phpt index 06db245c719e5fd9d89ea1576f227c38daa74e8d..3a87dfc12a2b2f303f49beb7475172a799f1f27f 100644 GIT binary patch delta 23 ecmeyM@l9hxBMVnzNl8&=QfWzQ@#a>R*Zcr`y9x6E delta 17 YcmeyS@j+ulBMVDzYDwbeZkE^l07ilbQvd(} diff --git a/appsec/tests/extension/root_span_add_tag.phpt b/appsec/tests/extension/root_span_add_tag.phpt index 3d1b8b72c5..bf3be9f7cc 100644 --- a/appsec/tests/extension/root_span_add_tag.phpt +++ b/appsec/tests/extension/root_span_add_tag.phpt @@ -29,9 +29,11 @@ bool(true) bool(false) array(1) { [0]=> - array(10) { + array(12) { ["trace_id"]=> string(%d) "%d" + ["trace_id_high"]=> + string(16) "%s" ["span_id"]=> string(%d) "%d" ["start"]=> @@ -46,33 +48,14 @@ array(1) { string(12) "appsec_tests" ["type"]=> string(3) "cli" - ["meta"]=> - array(5) { - ["_dd.p.dm"]=> - string(2) "-0" - ["_dd.p.tid"]=> - string(16) "%s" - ["_dd.sdk.otlp_export"]=> - string(5) "false" + ["sampling_priority"]=> + int(1) + ["sampling_mechanism"]=> + int(0) + ["attributes"]=> + array(%d) {%A ["after"]=> - string(9) "root_span" - ["runtime-id"]=> - string(%d) %s - } - ["metrics"]=> - array(6) { - [%s"]=> - float(%d) - ["_sampling_priority_v1"]=> - float(1) - ["php.compilation.total_time_ms"]=> - float(%s) - ["php.memory.peak_real_usage_bytes"]=> - float(%f) - ["php.memory.peak_usage_bytes"]=> - float(%f) - ["process_id"]=> - float(%f) + string(9) "root_span"%A } } } diff --git a/appsec/tests/integration/src/test/groovy/com/datadog/appsec/php/integration/EndpointFallbackSamplingTests.groovy b/appsec/tests/integration/src/test/groovy/com/datadog/appsec/php/integration/EndpointFallbackSamplingTests.groovy index c8c73394f3..b7670d1ad9 100644 --- a/appsec/tests/integration/src/test/groovy/com/datadog/appsec/php/integration/EndpointFallbackSamplingTests.groovy +++ b/appsec/tests/integration/src/test/groovy/com/datadog/appsec/php/integration/EndpointFallbackSamplingTests.groovy @@ -177,7 +177,9 @@ trait EndpointFallbackSamplingTests extends SamplingTestsInFpm { assert metric.namespace == 'appsec' assert metric.type == 'count' assert metric.points[0][1] >= 1.0 - assert 'framework:unknown' in metric.tags + // root span component now defaults to the SAPI name (fpm-fcgi here); + // this trait is only mixed into Apache2FpmTests + assert 'framework:fpm-fcgi' in metric.tags } } finally { resetFpm() diff --git a/loader/tests/functional/test_ddtrace_is_fully_loaded.php b/loader/tests/functional/test_ddtrace_is_fully_loaded.php index e5105cdbdb..72a2e9e312 100644 --- a/loader/tests/functional/test_ddtrace_is_fully_loaded.php +++ b/loader/tests/functional/test_ddtrace_is_fully_loaded.php @@ -34,14 +34,14 @@ [resource] => sh [service] => ddtrace.php [type] => system - [meta] => Array + [component] => subprocess + [attributes] => Array ( + [cmd.shell] => echo using passthru + [_dd.code_origin.type] => exit [_dd.code_origin.frames.1.file] => %s/fixtures/ddtrace.php [_dd.code_origin.frames.1.line] => 13 - [_dd.code_origin.type] => exit [cmd.exit_code] => 0 - [cmd.shell] => echo using passthru - [component] => subprocess ) %A EOS diff --git a/tests/Benchmarks/API/MessagePackSerializationBench.php b/tests/Benchmarks/API/MessagePackSerializationBench.php deleted file mode 100644 index 43220a80c9..0000000000 --- a/tests/Benchmarks/API/MessagePackSerializationBench.php +++ /dev/null @@ -1,41 +0,0 @@ -name = 'bench.trace_serialization'; - $span->meta['foo'] = 'bar'; - $span->metrics['bar'] = 1; - } - - for ($i = 0; $i < 100; $i++) { - \DDTrace\close_span(); - } - - $traceArray = \dd_trace_serialize_closed_spans(); - - return [ - [$traceArray], - ]; - } -} diff --git a/tests/Common/CLITestCase.php b/tests/Common/CLITestCase.php index e7cbf691c6..a48bcdfadd 100644 --- a/tests/Common/CLITestCase.php +++ b/tests/Common/CLITestCase.php @@ -75,9 +75,16 @@ public function getTracesFromCommand($arguments = '', $overrideEnvs = []) public function getAgentRequestFromCommand($arguments = '', $overrideEnvs = []) { $this->executeCommand($arguments, $overrideEnvs); - foreach ($this->retrieveDumpedTraceData() as $request) { + // retrieveDumpedTraceData()'s v0.4/v0.7-only filter misses a v1-sidecar trace + // (/v1.0/traces) and falls through to this runner's own command_execution span. + $isTraceRequest = function ($request) { $uri = $request['uri'] ?? ''; - if (strpos($uri, '/v0.4/traces') === 0 || strpos($uri, '/v0.7/traces') === 0) { + return strpos($uri, '/v0.4/traces') === 0 + || strpos($uri, '/v0.7/traces') === 0 + || strpos($uri, '/v1.0/traces') === 0; + }; + foreach ($this->retrieveDumpedData($isTraceRequest) as $request) { + if ($isTraceRequest($request)) { return $request; } } diff --git a/tests/Common/SnapshotTestTrait.php b/tests/Common/SnapshotTestTrait.php index be61583431..e39be05fc2 100644 --- a/tests/Common/SnapshotTestTrait.php +++ b/tests/Common/SnapshotTestTrait.php @@ -404,7 +404,8 @@ protected function ignoreSampledTraces($traces) { $sampledTraceIDs = []; foreach ($traces as $trace) { foreach ($trace as $span) { - if (isset($span['metrics']['_sampling_priority_v1']) && $span['metrics']['_sampling_priority_v1'] === 0) { + list(, $metrics) = SpanChecker::extractMetaMetrics($span); + if (isset($metrics['_sampling_priority_v1']) && (int) $metrics['_sampling_priority_v1'] === 0) { $sampledTraceIDs[$span['trace_id']] = true; } } diff --git a/tests/Common/SpanAssertionTrait.php b/tests/Common/SpanAssertionTrait.php index 96fd3388cf..489b22df13 100644 --- a/tests/Common/SpanAssertionTrait.php +++ b/tests/Common/SpanAssertionTrait.php @@ -65,24 +65,27 @@ public function assertError(array $span, $message, array $expectedStackLinesGrou { $this->assertSame(1, $span['error']); + // Normalize the V1 introspection shape (attributes) and the flat v0.4 wire to a meta view. + list($meta,) = SpanChecker::extractMetaMetrics($span); + // message assertion supports '*' wildcard but DOES NOT enforce order. $messagePartsByWildcard = \explode('*', $message); foreach ($messagePartsByWildcard as $messagePart) { $this->assertNotSame( false, - \strpos($span['meta'][Tag::ERROR_MSG], $messagePart), - \sprintf('Message "%s" does not contain "%s"', $span['meta'][Tag::ERROR_MSG], $message) + \strpos($meta[Tag::ERROR_MSG], $messagePart), + \sprintf('Message "%s" does not contain "%s"', $meta[Tag::ERROR_MSG], $message) ); } - $stackGroups = \explode('stack groups separator', $span['meta']['error.stack']); + $stackGroups = \explode('stack groups separator', $meta['error.stack']); if (count($stackGroups) !== count($expectedStackLinesGroups)) { $this->fail( \sprintf( 'Found %d stack groups, expected %d: %s', count($stackGroups), count($expectedStackLinesGroups), - $span['meta']['error.stack'] + $meta['error.stack'] ) ); } diff --git a/tests/Common/SpanChecker.php b/tests/Common/SpanChecker.php index 20dd5b22ab..3a6e321f97 100644 --- a/tests/Common/SpanChecker.php +++ b/tests/Common/SpanChecker.php @@ -63,6 +63,164 @@ public static function dumpTracesGraph(array $traces) return self::dumpSpansGraph($actualGraph); } + /** + * Derives the legacy flat `meta` (string tags) and `metrics` (numeric tags) views from a span. + * + * The V1 introspection shape (`dd_trace_serialize_closed_spans()`) merges the old string `meta` + * and numeric `metrics` maps into a single typed `attributes` map, and promotes some keys to + * top-level span fields. The v0.4 agent wire (parsed from the request replayer) keeps the old + * flat `meta`/`metrics`. Tests assert against the legacy model, so normalize both shapes to it. + * + * Reconstruction is the exact inverse of the reshape, so the derived `meta`/`metrics` match what + * master's introspection returned for the same span. + * + * @return array{0: array, 1: array} `[$meta, $metrics]` + */ + public static function extractMetaMetrics(array $span) + { + // Old flat shape (v0.4 wire): already split into meta/metrics. + if (\array_key_exists('meta', $span) || \array_key_exists('metrics', $span)) { + return [ + isset($span['meta']) ? $span['meta'] : [], + isset($span['metrics']) ? $span['metrics'] : [], + ]; + } + + // New V1 introspection shape: split attributes back by type and restore promoted keys. + $meta = []; + $metrics = []; + foreach (isset($span['attributes']) ? $span['attributes'] : [] as $key => $value) { + if (\is_int($value) || \is_float($value)) { + $metrics[$key] = $value; + } else { + // Strings and nested array/map attributes belong to the meta view. + $meta[$key] = $value; + } + } + // Promoted string keys move back into meta under their original tag names. + if (isset($span['env'])) { + $meta['env'] = $span['env']; + } + if (isset($span['version'])) { + $meta['version'] = $span['version']; + } + if (isset($span['component'])) { + $meta['component'] = $span['component']; + } + // span_kind is an int enum, ALWAYS present; 1 (Internal) is the default and was not emitted + // as a `span.kind` meta tag in the old shape, so only restore the explicit kinds (2-5). + if (isset($span['span_kind'])) { + $kinds = [2 => 'server', 3 => 'client', 4 => 'producer', 5 => 'consumer']; + if (isset($kinds[$span['span_kind']])) { + $meta['span.kind'] = $kinds[$span['span_kind']]; + } + } + // Chunk-level keys: introspection only emits these on the chunk's local root (as the wire). + if (isset($span['origin'])) { + $meta['_dd.origin'] = $span['origin']; + } + if (isset($span['trace_id_high'])) { + $meta['_dd.p.tid'] = $span['trace_id_high']; + } + // sampling_mechanism is the unsigned _dd.p.dm value (sign is always '-'). + if (isset($span['sampling_mechanism'])) { + $meta['_dd.p.dm'] = '-' . $span['sampling_mechanism']; + } + // sampling_priority (int) was the numeric _sampling_priority_v1 metric. + if (isset($span['sampling_priority'])) { + $metrics['_sampling_priority_v1'] = (float) $span['sampling_priority']; + } + return [$meta, $metrics]; + } + + /** + * Converts a V1 introspection span into the flat v0.4 shape the test agent expects, so + * introspection traces (from `flushAndGetTraces()`) can be sent to the agent for snapshotting. + * Old flat spans are returned unchanged. + */ + public static function spanToWireShape(array $span) + { + if (\array_key_exists('meta', $span) || \array_key_exists('metrics', $span)) { + return $span; + } + list($meta, $metrics) = self::extractMetaMetrics($span); + unset( + $span['attributes'], + $span['span_kind'], + $span['env'], + $span['version'], + $span['component'], + $span['origin'], + $span['trace_id_high'], + $span['sampling_priority'], + $span['sampling_mechanism'] + ); + if ($meta) { + $span['meta'] = $meta; + } + if ($metrics) { + $span['metrics'] = $metrics; + } + return $span; + } + + /** + * Moves native `span_links` (v0.4 downgrade wire, or V1 introspection) into the legacy + * `meta['_dd.span_links']` JSON string that the test agent accepts and that the stored + * snapshots were captured with. The test agent cannot decode a native `span_links` list. + */ + public static function spanLinksToLegacyMeta(array $span) + { + if (empty($span['span_links'])) { + unset($span['span_links']); + return $span; + } + $links = []; + foreach ($span['span_links'] as $link) { + $high = isset($link['trace_id_high']) ? $link['trace_id_high'] : 0; + // Introspection renders the high half as 16 hex digits, the wire as a decimal integer. + $highHex = \is_string($high) && \strlen($high) === 16 ? $high : self::decimalToHex($high, 16); + $legacy = [ + 'trace_id' => $highHex . self::decimalToHex($link['trace_id'], 16), + 'span_id' => self::decimalToHex($link['span_id'], 16), + ]; + if (!empty($link['trace_state'])) { + $legacy['trace_state'] = $link['trace_state']; + } elseif (!empty($link['tracestate'])) { + $legacy['trace_state'] = $link['tracestate']; + } + if (!empty($link['attributes'])) { + $legacy['attributes'] = $link['attributes']; + } + if (!empty($link['flags'])) { + $legacy['flags'] = $link['flags']; + } + $links[] = $legacy; + } + unset($span['span_links']); + $span['meta']['_dd.span_links'] = json_encode($links); + return $span; + } + + /** Decimal (int or numeric string, possibly above PHP_INT_MAX) to zero-padded lowercase hex. */ + private static function decimalToHex($decimal, $width) + { + $digits = (string)$decimal; + $hex = ''; + while ($digits !== '' && $digits !== '0') { + $quotient = ''; + $carry = 0; + foreach (str_split($digits) as $d) { + $carry = $carry * 10 + (int)$d; + $quotient .= intdiv($carry, 16); + $carry %= 16; + } + $hex = dechex($carry) . $hex; + $digits = ltrim($quotient, '0'); + } + return str_pad($hex, $width, '0', STR_PAD_LEFT); + } + public static function dumpSpansGraph(array $spansGraph, int $indent = 0) { $out = ""; @@ -85,23 +243,20 @@ public static function dumpSpansGraph(array $spansGraph, int $indent = 0) $out .= ' (' . implode(', ', $values) . ')'; } $out .= "\n"; - if (isset($span['meta'])) { - unset($span['meta']['_dd.p.dm']); - unset($span['meta']['_dd.p.tid']); - unset($span['meta']['_dd.sdk.otlp_export']); - unset($span['meta']['http.client_ip']); - foreach ($span['meta'] as $k => $v) { - $out .= str_repeat(' ', $indent) . ' ' . $k . ' => ' . $v . "\n"; - } + list($dumpMeta, $dumpMetrics) = self::extractMetaMetrics($span); + unset($dumpMeta['_dd.p.dm']); + unset($dumpMeta['_dd.p.tid']); + unset($dumpMeta['_dd.sdk.otlp_export']); + unset($dumpMeta['http.client_ip']); + foreach ($dumpMeta as $k => $v) { + $out .= str_repeat(' ', $indent) . ' ' . $k . ' => ' . (is_scalar($v) ? $v : json_encode($v)) . "\n"; } - if (isset($span['metrics'])) { - unset($span['metrics']['php.compilation.total_time_ms']); - unset($span['metrics']['php.memory.peak_usage_bytes']); - unset($span['metrics']['php.memory.peak_real_usage_bytes']); - unset($span['metrics']['process_id']); - foreach ($span['metrics'] as $k => $v) { - $out .= str_repeat(' ', $indent) . ' ' . $k . ' => ' . $v . "\n"; - } + unset($dumpMetrics['php.compilation.total_time_ms']); + unset($dumpMetrics['php.memory.peak_usage_bytes']); + unset($dumpMetrics['php.memory.peak_real_usage_bytes']); + unset($dumpMetrics['process_id']); + foreach ($dumpMetrics as $k => $v) { + $out .= str_repeat(' ', $indent) . ' ' . $k . ' => ' . (is_scalar($v) ? $v : json_encode($v)) . "\n"; } $out .= self::dumpSpansGraph($node['children'], $indent + 2); } @@ -388,20 +543,19 @@ public function assertSpan($span, SpanAssertion $exp) { TestCase::assertNotNull($span, 'Expected span was not found \'' . $exp->getOperationName() . '\'.'); - $spanMeta = isset($span['meta']) ? $span['meta'] : []; - $spanMetrics = isset($span['metrics']) ? $span['metrics'] : []; + list($spanMeta, $spanMetrics) = self::extractMetaMetrics($span); $namePrefix = $exp->getOperationName() . ': '; // Checking status code here because this can be tested also when we want to check only for existence if ($exp->getStatusCode() !== SpanAssertion::NOT_TESTED) { $actualStatusCode - = isset($span['meta']['http.status_code']) ? $span['meta']['http.status_code'] : ''; + = isset($spanMeta['http.status_code']) ? $spanMeta['http.status_code'] : ''; $expectedStatusCode = strval($exp->getStatusCode()); if ($actualStatusCode !== $expectedStatusCode) { TestCase::assertSame( $exp->getStatusCode(), - isset($span['meta']['http.status_code']) ? $span['meta']['http.status_code'] : '', + isset($spanMeta['http.status_code']) ? $spanMeta['http.status_code'] : '', $namePrefix . "Wrong value for 'status code'. " . "Expected: $expectedStatusCode. Actual: $actualStatusCode" . print_r($span, true) @@ -446,7 +600,16 @@ public function assertSpan($span, SpanAssertion $exp) } foreach ($exp->getExistingTagNames(true) as $key) { - TestCase::assertArrayHasKey($key, $spanMeta); + if ($key === '_dd.span_links') { + // Links live in the top-level native span_links (V1 introspection / dd_trace_serialize_closed_spans) + // OR the legacy '_dd.span_links' meta tag (v0.4 wire). Accept either so both paths pass. + TestCase::assertTrue( + !empty($span['span_links']) || isset($spanMeta['_dd.span_links']), + $exp->getOperationName() . ": expected span links but neither top-level span_links nor meta['_dd.span_links'] is present" + ); + } else { + TestCase::assertArrayHasKey($key, $spanMeta); + } } if ($exp->isOnlyCheckExistence()) { @@ -539,6 +702,12 @@ function ($key) use ($pattern) { if ($tagName === Tag::PID) { TestCase::assertArrayHasKey($tagName, $spanMetrics); unset($spanMetrics[Tag::PID]); + } elseif ($tagName === '_dd.span_links') { + // Links: top-level native span_links (introspection) OR legacy _dd.span_links meta (v0.4 wire). + TestCase::assertTrue( + !empty($span['span_links']) || isset($spanMeta['_dd.span_links']), + $exp->getOperationName() . ": expected span links but neither top-level span_links nor meta['_dd.span_links'] is present" + ); } else { TestCase::assertArrayHasKey($tagName, $spanMeta); } @@ -566,6 +735,10 @@ function ($key) use ($pattern) { // Set by sidecar only unset($spanMetrics['_top_level']); } + if (!isset($metrics['_dd.top_level'])) { + // Set by the sidecar on the V1 path unless explicitly tested + unset($spanMetrics['_dd.top_level']); + } TestCase::assertEquals( $metrics, $spanMetrics, diff --git a/tests/Common/TracerTestTrait.php b/tests/Common/TracerTestTrait.php index 9515d79ebb..be51045449 100644 --- a/tests/Common/TracerTestTrait.php +++ b/tests/Common/TracerTestTrait.php @@ -79,6 +79,18 @@ public function isolateTracer($fn, $tracer = null, $config = []) public function sendTracesToTestAgent($traces) { + // flushAndGetTraces() returns the V1 introspection shape (attributes + promoted keys). + // The test agent negotiates the v0.4 wire, so convert each span to the flat shape it + // expects (and that the stored snapshots were captured in) before sending. Native + // span_links become the legacy `_dd.span_links` meta JSON: the test agent rejects the list. + foreach ($traces as &$trace) { + foreach ($trace as &$span) { + $span = SpanChecker::spanLinksToLegacyMeta(SpanChecker::spanToWireShape($span)); + } + unset($span); + } + unset($trace); + // The data to be sent in the POST request $data_json = json_encode($traces); diff --git a/tests/Composer/ComposerInteroperabilityTest.php b/tests/Composer/ComposerInteroperabilityTest.php index a5ddf82020..24468d824f 100644 --- a/tests/Composer/ComposerInteroperabilityTest.php +++ b/tests/Composer/ComposerInteroperabilityTest.php @@ -103,6 +103,7 @@ function ($execute) { 'http.url' => 'http://127.0.0.1:' . self::$webserverPort . '/no-manual-tracing', 'http.status_code' => '200', 'span.kind' => 'server', + 'component' => \DDTrace\Tests\WebServer::defaultSapiName(), ]), ]); } @@ -138,6 +139,7 @@ function ($execute) { 'http.url' => 'http://127.0.0.1:' . self::$webserverPort . '/manual-tracing', 'http.status_code' => '200', 'span.kind' => 'server', + 'component' => \DDTrace\Tests\WebServer::defaultSapiName(), ]) ->withChildren([ SpanAssertion::build('my_operation', 'web.request', 'memcached', 'my_resource') @@ -180,6 +182,7 @@ function ($execute) { 'http.url' => 'http://127.0.0.1:' . self::$webserverPort . '/manual-tracing', 'http.status_code' => '200', 'span.kind' => 'server', + 'component' => \DDTrace\Tests\WebServer::defaultSapiName(), ]) ->withChildren([ SpanAssertion::build('my_operation', 'web.request', 'memcached', 'my_resource') @@ -222,6 +225,7 @@ function ($execute) { 'http.url' => 'http://127.0.0.1:' . self::$webserverPort . '/no-manual-tracing', 'http.status_code' => '200', 'span.kind' => 'server', + 'component' => \DDTrace\Tests\WebServer::defaultSapiName(), ]), ]); } @@ -257,6 +261,7 @@ function ($execute) { 'http.url' => 'http://127.0.0.1:' . self::$webserverPort . '/manual-tracing', 'http.status_code' => '200', 'span.kind' => 'server', + 'component' => \DDTrace\Tests\WebServer::defaultSapiName(), ]) ->withChildren([ SpanAssertion::build('my_operation', 'web.request', 'memcached', 'my_resource') @@ -293,6 +298,7 @@ function ($execute) { 'http.url' => 'http://127.0.0.1:' . self::$webserverPort . '/no-manual-tracing', 'http.status_code' => '200', 'span.kind' => 'server', + 'component' => \DDTrace\Tests\WebServer::defaultSapiName(), ]), ]); } @@ -322,6 +328,7 @@ function ($execute) { 'http.url' => 'http://127.0.0.1:' . self::$webserverPort . '/no-composer', 'http.status_code' => '200', 'span.kind' => 'server', + 'component' => \DDTrace\Tests\WebServer::defaultSapiName(), ]), ]); } @@ -356,6 +363,7 @@ function ($execute) { 'http.url' => 'http://127.0.0.1:' . self::$webserverPort . '/no-composer', 'http.status_code' => '200', 'span.kind' => 'server', + 'component' => \DDTrace\Tests\WebServer::defaultSapiName(), ]), ]); } @@ -392,6 +400,7 @@ function ($execute) { 'http.url' => 'http://127.0.0.1:' . self::$webserverPort . '/no-composer-autoload-fails', 'http.status_code' => '200', 'span.kind' => 'server', + 'component' => \DDTrace\Tests\WebServer::defaultSapiName(), ]), ]); } @@ -428,6 +437,7 @@ function ($execute) { 'http.url' => 'http://127.0.0.1:' . self::$webserverPort . '/composer-autoload-fails', 'http.status_code' => '200', 'span.kind' => 'server', + 'component' => \DDTrace\Tests\WebServer::defaultSapiName(), ]), ]); } diff --git a/tests/DistributedTracing/SyntheticsTest.php b/tests/DistributedTracing/SyntheticsTest.php index 995f4e9bef..f379128f5d 100644 --- a/tests/DistributedTracing/SyntheticsTest.php +++ b/tests/DistributedTracing/SyntheticsTest.php @@ -54,6 +54,7 @@ public function testSyntheticsRequest() 'http.url' => 'http://localhost/index.php', 'http.status_code' => '200', 'span.kind' => 'server', + 'component' => \DDTrace\Tests\WebServer::defaultSapiName(), '_dd.origin' => 'synthetics-browser', ])->withExactMetrics([ '_sampling_priority_v1' => 1, diff --git a/tests/Integration/DatabaseMonitoringTest.php b/tests/Integration/DatabaseMonitoringTest.php index b4c239d76b..68b6b4c378 100644 --- a/tests/Integration/DatabaseMonitoringTest.php +++ b/tests/Integration/DatabaseMonitoringTest.php @@ -325,7 +325,7 @@ public function testBaseHashInjection() $this->assertNotEmpty($matches, 'ddsh not found in SQL comment'); $ddshValue = $matches[1]; - $propagatedHash = $traces[0][1]['meta']['_dd.propagated_hash'] ?? null; + $propagatedHash = $traces[0][1]['attributes']['_dd.propagated_hash'] ?? null; $this->assertNotNull($propagatedHash, '_dd.propagated_hash not found in span'); $this->assertSame($ddshValue, $propagatedHash, 'ddsh in SQL comment does not match _dd.propagated_hash in span'); } @@ -361,7 +361,7 @@ public function testBaseHashInjectionWithoutContainerTagsHash() $this->assertNotEmpty($matches, 'ddsh not found in SQL comment'); $ddshValue = $matches[1]; - $propagatedHash = $traces[0][1]['meta']['_dd.propagated_hash'] ?? null; + $propagatedHash = $traces[0][1]['attributes']['_dd.propagated_hash'] ?? null; $this->assertNotNull($propagatedHash, '_dd.propagated_hash not found in span'); $this->assertSame($ddshValue, $propagatedHash, 'ddsh in SQL comment does not match _dd.propagated_hash in span'); } @@ -445,11 +445,11 @@ public function testDynamicServiceMode() ); $ddshValue = preg_replace('/^.*ddsh=\'([^\']+)\'.*$/', '$1', $commentedQuery); - $propagatedHash = $traces[0][1]['meta']['_dd.propagated_hash'] ?? null; + $propagatedHash = $traces[0][1]['attributes']['_dd.propagated_hash'] ?? null; $this->assertNotNull($propagatedHash, '_dd.propagated_hash not found in span'); $this->assertSame($ddshValue, $propagatedHash, 'ddsh in SQL comment does not match _dd.propagated_hash in span'); // dynamic_service is not full mode, so the trace-injected marker must be absent - $this->assertArrayNotHasKey('_dd.dbm_trace_injected', $traces[0][1]['meta']); + $this->assertArrayNotHasKey('_dd.dbm_trace_injected', $traces[0][1]['attributes']); } } diff --git a/tests/Integration/LongRunning/LongRunningScriptTest.php b/tests/Integration/LongRunning/LongRunningScriptTest.php index ea557f8da0..d0e3b7c985 100644 --- a/tests/Integration/LongRunning/LongRunningScriptTest.php +++ b/tests/Integration/LongRunning/LongRunningScriptTest.php @@ -23,12 +23,13 @@ public function testMultipleTracesFromLongRunningScriptSetCorrectTraceCountHeade 'DD_TRACE_BGS_TIMEOUT' => 3000, ]); - $headerName = 'X-Datadog-Trace-Count'; - if (\dd_trace_env_config("DD_TRACE_SIDECAR_TRACE_SENDER")) { - $headerName = strtolower($headerName); - } + // Header names are case-insensitive; the sender's casing (coms.c vs sidecar) is + // independent of this runner's own config, so accept either. + $traceCount = $agentRequest['headers']['X-Datadog-Trace-Count'] + ?? $agentRequest['headers']['x-datadog-trace-count'] + ?? null; - $this->assertSame('3', $agentRequest['headers'][$headerName]); + $this->assertSame('3', $traceCount); $this->assertCount(3, $this->loadTraces($agentRequest)); } diff --git a/tests/Integration/ResponseStatusCodeTest.php b/tests/Integration/ResponseStatusCodeTest.php index 58896f2e06..8e5b105366 100644 --- a/tests/Integration/ResponseStatusCodeTest.php +++ b/tests/Integration/ResponseStatusCodeTest.php @@ -40,6 +40,7 @@ function () { 'http.url' => 'http://localhost/success', 'http.status_code' => '200', 'span.kind' => 'server', + 'component' => \DDTrace\Tests\WebServer::defaultSapiName(), ]), ] ); @@ -66,6 +67,7 @@ function () { 'http.url' => 'http://localhost/error', 'http.status_code' => '500', 'span.kind' => 'server', + 'component' => \DDTrace\Tests\WebServer::defaultSapiName(), ] )->setError(), ] diff --git a/tests/Integration/TracerTest.php b/tests/Integration/TracerTest.php index 377561d549..27be186cad 100644 --- a/tests/Integration/TracerTest.php +++ b/tests/Integration/TracerTest.php @@ -44,9 +44,9 @@ public function testGlobalTagsArePresentOnLegacySpansByFlushTime() }); $this->assertSame('custom.name', $traces[0][0]['name']); - $this->assertSame('local', $traces[0][0]['meta']['local_tag']); - $this->assertSame('global', $traces[0][0]['meta']['global_tag']); - $this->assertSame('span_wins', $traces[0][0]['meta']['also_in_span']); + $this->assertSame('local', $traces[0][0]['attributes']['local_tag']); + $this->assertSame('global', $traces[0][0]['attributes']['global_tag']); + $this->assertSame('span_wins', $traces[0][0]['attributes']['also_in_span']); } public function testGlobalTagsArePresentOnInternalSpansByFlushTime() @@ -70,9 +70,9 @@ function (SpanData $span) { }); $this->assertSame('custom.name', $traces[0][0]['name']); - $this->assertSame('local', $traces[0][0]['meta']['local_tag']); - $this->assertSame('global', $traces[0][0]['meta']['global_tag']); - $this->assertSame('span_wins', $traces[0][0]['meta']['also_in_span']); + $this->assertSame('local', $traces[0][0]['attributes']['local_tag']); + $this->assertSame('global', $traces[0][0]['attributes']['global_tag']); + $this->assertSame('span_wins', $traces[0][0]['attributes']['also_in_span']); } /** @@ -246,7 +246,7 @@ public function testEnvironmentIsAddedToASpan() $scope->close(); }); - $this->assertSame('my-env', $traces[0][0]['meta']['env']); + $this->assertSame('my-env', $traces[0][0]['env']); } public function testEnvironmentIsOptional() @@ -257,7 +257,7 @@ public function testEnvironmentIsOptional() $scope->close(); }); - $this->assertTrue(empty($traces[0][0]['meta']['env'])); + $this->assertTrue(empty($traces[0][0]['env'])); } public function testServiceVersionIsAddedToASpan() @@ -268,7 +268,7 @@ public function testServiceVersionIsAddedToASpan() $scope->close(); }); - $this->assertSame('1.2.3', $traces[0][0]['meta']['version']); + $this->assertSame('1.2.3', $traces[0][0]['version']); } public function testServiceVersionIsOptional() @@ -279,7 +279,7 @@ public function testServiceVersionIsOptional() $scope->close(); }); - $this->assertTrue(empty($traces[0][0]['meta']['version'])); + $this->assertTrue(empty($traces[0][0]['version'])); } public function testTracerReset() @@ -431,7 +431,7 @@ public function testBaseService() }); $this->assertSame('changed_child', $traces[0][1]['service']); - $this->assertSame('original_service', $traces[0][1]['meta']['_dd.base_service']); + $this->assertSame('original_service', $traces[0][1]['attributes']['_dd.base_service']); } public function testBaseServiceWithMapping() @@ -448,7 +448,7 @@ public function testBaseServiceWithMapping() }); $this->assertSame('changed_child', $traces[0][1]['service']); - $this->assertSame('changed_service', $traces[0][1]['meta']['_dd.base_service']); + $this->assertSame('changed_service', $traces[0][1]['attributes']['_dd.base_service']); } public function dummyMethodGlobalTags() diff --git a/tests/Integrations/Curl/CurlIntegrationTest.php b/tests/Integrations/Curl/CurlIntegrationTest.php index e01c76154a..867fe9761d 100644 --- a/tests/Integrations/Curl/CurlIntegrationTest.php +++ b/tests/Integrations/Curl/CurlIntegrationTest.php @@ -41,7 +41,6 @@ protected function envsToCleanUpAtTearDown() { return [ 'DD_TRACE_PEER_SERVICE_DEFAULTS_ENABLED', - 'DD_CURL_ANALYTICS_ENABLED', 'DD_DISTRIBUTED_TRACING', 'DD_TRACE_HTTP_CLIENT_SPLIT_BY_DOMAIN', 'DD_TRACE_MEMORY_LIMIT', @@ -193,7 +192,7 @@ function ($execute) { $this->assertFlameGraph($traces, [ SpanAssertion::build('web.request', 'top_level_app', 'web', 'GET /curl_in_web_request.php') - ->withExistingTagsNames(['http.method', 'http.url', 'http.status_code', 'span.kind']) + ->withExistingTagsNames(['http.method', 'http.url', 'http.status_code', 'span.kind', 'component']) ->withChildren([ SpanAssertion::build('curl_exec', 'curl', 'http', 'http://' . HTTPBIN_INTEGRATION . '/status/?') ->withExactTags([ @@ -613,109 +612,6 @@ public function dataProviderWithAndWithoutRootSpan() { ]; } - /** - * @dataProvider dataProviderTestTraceAnalytics - */ - public function testTraceAnalytics($envsOverride, $expectedSampleRate) - { - $env = array_merge(['DD_SERVICE' => 'top_level_app', 'DD_TRACE_GENERATE_ROOT_SPAN' => 'true'], $envsOverride); - - $traces = $this->inWebServer( - function ($execute) { - $execute(GetSpec::create('GET', '/curl_in_web_request.php')); - }, - __DIR__ . '/curl_in_web_request.php', - $env - ); - - $metrics = []; - if (null !== $expectedSampleRate) { - $metrics = array_merge($metrics, [ '_dd1.sr.eausr' => $expectedSampleRate ]); - } - - $this->assertFlameGraph($traces, [ - SpanAssertion::build('web.request', 'top_level_app', 'web', 'GET /curl_in_web_request.php') - ->withExistingTagsNames(['http.method', 'http.url', 'http.status_code', 'span.kind']) - ->withExactMetrics(['_sampling_priority_v1' => 1, '_dd.agent_psr' => 1, 'process_id' => getmypid()]) - ->withChildren([ - SpanAssertion::build('curl_exec', 'curl', 'http', 'http://' . HTTPBIN_INTEGRATION . '/status/?') - ->withExactTags([ - 'http.url' => self::URL . '/status/200', - 'http.status_code' => '200', - 'span.kind' => 'client', - 'network.destination.name' => HTTPBIN_SERVICE_HOST, - Tag::COMPONENT => 'curl', - '_dd.svc_src' => 'curl', - '_dd.base_service' => 'top_level_app', - ]) - ->withExistingTagsNames(self::commonCurlInfoTags()) - ->skipTagsLike('/^curl\..*/'), - ]), - ]); - } - - public function dataProviderTestTraceAnalytics() - { - return [ - 'not set' => [ - [], - null, - ], - 'off no rate' => [ - [ - 'DD_TRACE_CURL_ANALYTICS_ENABLED' => false, - ], - null, - ], - 'off legacy name no rate' => [ - [ - 'DD_CURL_ANALYTICS_ENABLED' => false, - ], - null, - ], - 'off with rate' => [ - [ - 'DD_TRACE_CURL_ANALYTICS_ENABLED' => false, - 'DD_TRACE_CURL_ANALYTICS_SAMPLE_RATE' => 0.7, - ], - null, - ], - 'off legacy name with rate' => [ - [ - 'DD_CURL_ANALYTICS_ENABLED' => false, - 'DD_CURL_ANALYTICS_SAMPLE_RATE' => 0.7, - ], - null, - ], - 'enabled default rate' => [ - [ - 'DD_TRACE_CURL_ANALYTICS_ENABLED' => true, - ], - 1.0, - ], - 'enabled legacy name default rate' => [ - [ - 'DD_CURL_ANALYTICS_ENABLED' => true, - ], - 1.0, - ], - 'enabled specific rate' => [ - [ - 'DD_TRACE_CURL_ANALYTICS_ENABLED' => true, - 'DD_TRACE_CURL_ANALYTICS_SAMPLE_RATE' => 0.7, - ], - 0.7, - ], - 'enabled legacy name specific rate' => [ - [ - 'DD_CURL_ANALYTICS_ENABLED' => true, - 'DD_CURL_ANALYTICS_SAMPLE_RATE' => 0.7, - ], - 0.7, - ], - ]; - } - public function testPeerServiceEnabled() { $this->putEnvAndReloadConfig(['DD_TRACE_PEER_SERVICE_DEFAULTS_ENABLED=true']); diff --git a/tests/Integrations/Custom/Autoloaded/CommonScenariosTest.php b/tests/Integrations/Custom/Autoloaded/CommonScenariosTest.php index d53be6143f..5102883537 100644 --- a/tests/Integrations/Custom/Autoloaded/CommonScenariosTest.php +++ b/tests/Integrations/Custom/Autoloaded/CommonScenariosTest.php @@ -50,6 +50,7 @@ public function provideSpecs() 'http.url' => 'http://localhost/simple?key=value&', 'http.status_code' => '200', 'span.kind' => 'server', + 'component' => \DDTrace\Tests\WebServer::defaultSapiName(), ]), ], 'A simple GET request with a view' => [ @@ -63,6 +64,7 @@ public function provideSpecs() 'http.url' => 'http://localhost/simple_view?key=value&', 'http.status_code' => '200', 'span.kind' => 'server', + 'component' => \DDTrace\Tests\WebServer::defaultSapiName(), ]), ], 'A GET request with an exception' => [ @@ -76,6 +78,7 @@ public function provideSpecs() 'http.url' => 'http://localhost/error?key=value&', 'http.status_code' => '500', 'span.kind' => 'server', + 'component' => \DDTrace\Tests\WebServer::defaultSapiName(), ])->setError(), ], ] diff --git a/tests/Integrations/Custom/Autoloaded/FatalErrorTest.php b/tests/Integrations/Custom/Autoloaded/FatalErrorTest.php index cad7a21dca..4078e731b2 100644 --- a/tests/Integrations/Custom/Autoloaded/FatalErrorTest.php +++ b/tests/Integrations/Custom/Autoloaded/FatalErrorTest.php @@ -47,6 +47,7 @@ public function testScenario() 'http.url' => 'http://localhost/fatal', 'http.status_code' => '200', 'span.kind' => 'server', + 'component' => \DDTrace\Tests\WebServer::defaultSapiName(), ]) ->setError("E_ERROR", "Intentional E_ERROR") ->withExistingTagsNames(['error.stack']), diff --git a/tests/Integrations/Custom/Autoloaded/TraceSearchConfigTest.php b/tests/Integrations/Custom/Autoloaded/TraceSearchConfigTest.php deleted file mode 100644 index 717b6ddbc2..0000000000 --- a/tests/Integrations/Custom/Autoloaded/TraceSearchConfigTest.php +++ /dev/null @@ -1,54 +0,0 @@ - 'true', - 'DD_WEB_ANALYTICS_SAMPLE_RATE' => '0.3', - ]); - } - - /** - * @throws \Exception - */ - public function testScenario() - { - $traces = $this->tracesFromWebRequest(function () { - $this->call(GetSpec::create('Testing trace analytics config metric', '/simple')); - }); - - $this->assertExpectedSpans( - $traces, - [ - SpanAssertion::build( - 'web.request', - 'web.request', - 'web', - 'GET /simple' - )->withExactTags([ - 'http.method' => 'GET', - 'http.url' => 'http://localhost/simple', - 'http.status_code' => '200', - 'span.kind' => 'server', - ])->withExactMetrics([ - '_dd1.sr.eausr' => 0.3, - '_sampling_priority_v1' => 1, - 'process_id' => getmypid(), - ]), - ] - ); - } -} diff --git a/tests/Integrations/Custom/NotAutoloaded/HttpHeadersConfiguredTest.php b/tests/Integrations/Custom/NotAutoloaded/HttpHeadersConfiguredTest.php index 4e95479b97..7e33955d87 100644 --- a/tests/Integrations/Custom/NotAutoloaded/HttpHeadersConfiguredTest.php +++ b/tests/Integrations/Custom/NotAutoloaded/HttpHeadersConfiguredTest.php @@ -44,6 +44,7 @@ public function testSelectedHeadersAreIncluded() 'http.request.headers.forth-header' => '123', 'http.response.headers.third-header' => 'separated: with : colon', 'span.kind' => 'server', + 'component' => \DDTrace\Tests\WebServer::defaultSapiName(), ]; if (\getenv('DD_TRACE_TEST_SAPI') != 'apache2handler') { $tags['http.request.headers.w__rd-header'] = 'foo'; diff --git a/tests/Integrations/Custom/NotAutoloaded/HttpHeadersNotConfiguredTest.php b/tests/Integrations/Custom/NotAutoloaded/HttpHeadersNotConfiguredTest.php index 135b17939c..49c5ba56d8 100644 --- a/tests/Integrations/Custom/NotAutoloaded/HttpHeadersNotConfiguredTest.php +++ b/tests/Integrations/Custom/NotAutoloaded/HttpHeadersNotConfiguredTest.php @@ -47,6 +47,7 @@ public function testSelectedHeadersAreIncluded() 'http.url' => 'http://localhost/', 'http.status_code' => 200, 'span.kind' => 'server', + 'component' => \DDTrace\Tests\WebServer::defaultSapiName(), ]), ] ); diff --git a/tests/Integrations/Custom/NotAutoloaded/IncomingUserInfoTest.php b/tests/Integrations/Custom/NotAutoloaded/IncomingUserInfoTest.php index b9684547b8..5d7251fcad 100644 --- a/tests/Integrations/Custom/NotAutoloaded/IncomingUserInfoTest.php +++ b/tests/Integrations/Custom/NotAutoloaded/IncomingUserInfoTest.php @@ -38,6 +38,7 @@ public function testSelectedHeadersAreIncluded() 'http.url' => 'http://localhost/', 'http.status_code' => 200, 'span.kind' => 'server', + 'component' => \DDTrace\Tests\WebServer::defaultSapiName(), ]), ] ); diff --git a/tests/Integrations/Exec/ExecIntegrationTest.php b/tests/Integrations/Exec/ExecIntegrationTest.php index b9237a54ed..4cf99aff87 100644 --- a/tests/Integrations/Exec/ExecIntegrationTest.php +++ b/tests/Integrations/Exec/ExecIntegrationTest.php @@ -537,7 +537,7 @@ public function testShellRedaction($sf) $this->assertEquals( "md5(){ return; }; FOO=? BAR=? echo foo -- --password=? -pass ?; md5 ? ?", - $traces[0][0]['meta']['cmd.shell'] + $traces[0][0]['attributes']['cmd.shell'] ); } @@ -554,8 +554,9 @@ public function testShellTruncation() $this->assertEquals( 4 * 1024, - strlen($traces[0][0]['meta']['cmd.shell']) + strlen($traces[0][0]['attributes']['cmd.shell']) ); + $this->assertSame('true', $traces[0][0]['attributes']['cmd.truncated']); } /** @@ -582,8 +583,9 @@ public function testExecTruncation() $this->assertEquals( '["echo","' . str_repeat('a', 4092) . '",""]', - $traces[0][0]['meta']['cmd.exec'] + $traces[0][0]['attributes']['cmd.exec'] ); + $this->assertSame('true', $traces[0][0]['attributes']['cmd.truncated']); } public function testProcOpenInjectsSessionIds() diff --git a/tests/Integrations/Guzzle/V5/GuzzleIntegrationTest.php b/tests/Integrations/Guzzle/V5/GuzzleIntegrationTest.php index 8504ee23c4..3faddda75e 100644 --- a/tests/Integrations/Guzzle/V5/GuzzleIntegrationTest.php +++ b/tests/Integrations/Guzzle/V5/GuzzleIntegrationTest.php @@ -46,7 +46,6 @@ protected function envsToCleanUpAtTearDown() { return [ 'DD_TRACE_PEER_SERVICE_DEFAULTS_ENABLED', - 'DD_CURL_ANALYTICS_ENABLED', 'DD_DISTRIBUTED_TRACING', 'DD_TRACE_HTTP_CLIENT_SPLIT_BY_DOMAIN', 'DD_TRACE_MEMORY_LIMIT', @@ -373,7 +372,7 @@ function ($execute) { $this->assertFlameGraph($traces, [ SpanAssertion::build('web.request', 'top_level_app', 'web', 'GET /guzzle_in_web_request.php') - ->withExistingTagsNames(['http.method', 'http.url', 'http.status_code', 'span.kind']) + ->withExistingTagsNames(['http.method', 'http.url', 'http.status_code', 'span.kind', 'component']) ->withChildren([ SpanAssertion::build('GuzzleHttp\Client.send', 'guzzle', 'http', 'send') ->withExactTags([ diff --git a/tests/Integrations/Guzzle/V6/GuzzleIntegrationTest.php b/tests/Integrations/Guzzle/V6/GuzzleIntegrationTest.php index ea7942cae4..494fcf4449 100644 --- a/tests/Integrations/Guzzle/V6/GuzzleIntegrationTest.php +++ b/tests/Integrations/Guzzle/V6/GuzzleIntegrationTest.php @@ -396,7 +396,7 @@ function ($execute) { $this->assertFlameGraph($traces, [ SpanAssertion::build('web.request', 'top_level_app', 'web', 'GET /guzzle_in_web_request.php') - ->withExistingTagsNames(['http.method', 'http.url', 'http.status_code', 'span.kind']) + ->withExistingTagsNames(['http.method', 'http.url', 'http.status_code', 'span.kind', 'component']) ->withChildren([ SpanAssertion::build('GuzzleHttp\Client.send', 'guzzle', 'http', 'send') ->withExactTags([ diff --git a/tests/Integrations/Laravel/V4/TraceSearchConfigTest.php b/tests/Integrations/Laravel/V4/TraceSearchConfigTest.php deleted file mode 100644 index 3109b07dde..0000000000 --- a/tests/Integrations/Laravel/V4/TraceSearchConfigTest.php +++ /dev/null @@ -1,88 +0,0 @@ - 'true', - 'DD_LARAVEL_ANALYTICS_SAMPLE_RATE' => '0.3', - ]); - } - - /** - * @throws \Exception - */ - public function testScenario() - { - $traces = $this->tracesFromWebRequest(function () { - $this->call(GetSpec::create('Testing trace analytics config metric', '/simple')); - }); - - $this->assertFlameGraph( - $traces, - [ - SpanAssertion::build('laravel.request', 'laravel', 'web', 'HomeController@simple simple_route') - ->withExactTags([ - 'laravel.route.name' => 'simple_route', - 'laravel.route.action' => 'HomeController@simple', - 'http.method' => 'GET', - 'http.url' => 'http://localhost/simple', - 'http.status_code' => '200', - 'http.route' => 'simple', - TAG::SPAN_KIND => 'server', - Tag::COMPONENT => 'laravel', - '_dd.svc_src' => 'laravel', - ]) - ->withExactMetrics([ - '_dd1.sr.eausr' => 0.3, - '_sampling_priority_v1' => 1, - 'process_id' => getmypid(), - ]) - ->withChildren([ - SpanAssertion::exists('laravel.application.handle') - ->withChildren([ - SpanAssertion::build('laravel.action', 'laravel', 'web', 'simple') - ->withExactTags([ - Tag::COMPONENT => 'laravel', - '_dd.svc_src' => 'laravel', - ]), - SpanAssertion::exists('laravel.event.handle'), - SpanAssertion::exists('laravel.event.handle'), - SpanAssertion::exists('laravel.event.handle'), - SpanAssertion::exists('laravel.event.handle'), - ]), - SpanAssertion::exists( - 'laravel.provider.load', - 'Illuminate\Foundation\ProviderRepository::load' - )->withChildren([ - SpanAssertion::exists('laravel.event.handle'), - SpanAssertion::exists('laravel.event.handle'), - SpanAssertion::exists('laravel.event.handle'), - SpanAssertion::exists('laravel.event.handle'), - SpanAssertion::exists('laravel.event.handle'), - SpanAssertion::exists('laravel.event.handle'), - SpanAssertion::exists('laravel.event.handle'), - ]), - SpanAssertion::exists('laravel.event.handle'), - SpanAssertion::exists('laravel.event.handle'), - SpanAssertion::exists('laravel.event.handle'), - ]), - ] - ); - } -} diff --git a/tests/Integrations/Laravel/V5_7/TraceSearchConfigTest.php b/tests/Integrations/Laravel/V5_7/TraceSearchConfigTest.php deleted file mode 100644 index 402c38eab8..0000000000 --- a/tests/Integrations/Laravel/V5_7/TraceSearchConfigTest.php +++ /dev/null @@ -1,85 +0,0 @@ - 'true', - 'DD_LARAVEL_ANALYTICS_SAMPLE_RATE' => '0.3', - ]); - } - - /** - * @throws \Exception - */ - public function testScenario() - { - $traces = $this->tracesFromWebRequest(function () { - $this->call(GetSpec::create('Testing trace analytics config metric', '/simple')); - }); - - $this->assertFlameGraph( - $traces, - [ - SpanAssertion::build( - 'laravel.request', - 'Laravel', - 'web', - 'App\Http\Controllers\CommonSpecsController@simple simple_route' - ) - ->withExactTags([ - 'laravel.route.name' => 'simple_route', - 'laravel.route.action' => 'App\Http\Controllers\CommonSpecsController@simple', - 'http.method' => 'GET', - 'http.url' => 'http://localhost/simple', - 'http.status_code' => '200', - 'http.route' => 'simple', - TAG::SPAN_KIND => 'server', - TAG::COMPONENT => 'laravel', - '_dd.svc_src' => 'laravel', - ]) - ->withExactMetrics([ - '_dd1.sr.eausr' => 0.3, - '_sampling_priority_v1' => 1, - 'process_id' => getmypid(), - ]) - ->withChildren([ - SpanAssertion::exists('laravel.action'), - SpanAssertion::exists( - 'laravel.provider.load', - 'Illuminate\Foundation\ProviderRepository::load' - ), - SpanAssertion::exists('laravel.event.handle'), - SpanAssertion::exists('laravel.event.handle'), - SpanAssertion::exists('laravel.event.handle'), - SpanAssertion::exists('laravel.event.handle'), - SpanAssertion::exists('laravel.event.handle'), - SpanAssertion::exists('laravel.event.handle'), - SpanAssertion::exists('laravel.event.handle'), - SpanAssertion::exists('laravel.event.handle'), - SpanAssertion::exists('laravel.event.handle'), - SpanAssertion::exists('laravel.event.handle'), - SpanAssertion::exists('laravel.event.handle'), - SpanAssertion::exists('laravel.event.handle'), - SpanAssertion::exists('laravel.event.handle'), - SpanAssertion::exists('laravel.event.handle'), - ]), - ] - ); - } -} diff --git a/tests/Integrations/Laravel/V5_8/QueueTest.php b/tests/Integrations/Laravel/V5_8/QueueTest.php index 89e0c8a79c..b98993a42d 100644 --- a/tests/Integrations/Laravel/V5_8/QueueTest.php +++ b/tests/Integrations/Laravel/V5_8/QueueTest.php @@ -117,10 +117,13 @@ public function testSimplePushAndProcess() }); $processSpanFromArtisanTrace = array_values($processSpanFromArtisanTrace)[0]; - $spanLinks = $processSpanFromArtisanTrace['meta']['_dd.span_links']; - $spanLinks = json_decode($spanLinks, true)[0]; - $spanLinksTraceId = $spanLinks['trace_id']; - $spanLinksSpanId = $spanLinks['span_id']; + // v0.4 carries native span_links (ids as decimal integers); render them as hex. + $spanLinks = $processSpanFromArtisanTrace['span_links'][0]; + $toHex = function ($id) { + return str_pad(self::largeBaseConvert((string) $id, 10, 16), 16, '0', STR_PAD_LEFT); + }; + $spanLinksTraceId = $toHex($spanLinks['trace_id_high'] ?? 0) . $toHex($spanLinks['trace_id']); + $spanLinksSpanId = $toHex($spanLinks['span_id']); $processSpanFromProcessTrace = array_filter($processTrace1[0], function ($span) { return $span['name'] === 'laravel.queue.process'; diff --git a/tests/Integrations/Laravel/V5_8/TraceSearchConfigTest.php b/tests/Integrations/Laravel/V5_8/TraceSearchConfigTest.php deleted file mode 100644 index 3d8fd4681e..0000000000 --- a/tests/Integrations/Laravel/V5_8/TraceSearchConfigTest.php +++ /dev/null @@ -1,85 +0,0 @@ - 'true', - 'DD_LARAVEL_ANALYTICS_SAMPLE_RATE' => '0.3', - ]); - } - - /** - * @throws \Exception - */ - public function testScenario() - { - $traces = $this->tracesFromWebRequest(function () { - $this->call(GetSpec::create('Testing trace analytics config metric', '/simple')); - }); - - $this->assertFlameGraph( - $traces, - [ - SpanAssertion::build( - 'laravel.request', - 'Laravel', - 'web', - 'App\Http\Controllers\CommonSpecsController@simple simple_route' - ) - ->withExactTags([ - 'laravel.route.name' => 'simple_route', - 'laravel.route.action' => 'App\Http\Controllers\CommonSpecsController@simple', - 'http.method' => 'GET', - 'http.url' => 'http://localhost/simple', - 'http.status_code' => '200', - 'http.route' => 'simple', - TAG::SPAN_KIND => 'server', - Tag::COMPONENT => 'laravel', - '_dd.svc_src' => 'laravel', - ]) - ->withExactMetrics([ - '_dd1.sr.eausr' => 0.3, - '_sampling_priority_v1' => 1, - 'process_id' => getmypid(), - ]) - ->withChildren([ - SpanAssertion::exists('laravel.action'), - SpanAssertion::exists( - 'laravel.provider.load', - 'Illuminate\Foundation\ProviderRepository::load' - ), - SpanAssertion::exists('laravel.event.handle'), - SpanAssertion::exists('laravel.event.handle'), - SpanAssertion::exists('laravel.event.handle'), - SpanAssertion::exists('laravel.event.handle'), - SpanAssertion::exists('laravel.event.handle'), - SpanAssertion::exists('laravel.event.handle'), - SpanAssertion::exists('laravel.event.handle'), - SpanAssertion::exists('laravel.event.handle'), - SpanAssertion::exists('laravel.event.handle'), - SpanAssertion::exists('laravel.event.handle'), - SpanAssertion::exists('laravel.event.handle'), - SpanAssertion::exists('laravel.event.handle'), - SpanAssertion::exists('laravel.event.handle'), - SpanAssertion::exists('laravel.event.handle'), - ]), - ] - ); - } -} diff --git a/tests/Integrations/Laravel/V8_x/QueueTest.php b/tests/Integrations/Laravel/V8_x/QueueTest.php index 14a0f0d04a..be831f7f63 100644 --- a/tests/Integrations/Laravel/V8_x/QueueTest.php +++ b/tests/Integrations/Laravel/V8_x/QueueTest.php @@ -138,10 +138,13 @@ public function testSimplePushAndProcess() }); $processSpanFromArtisanTrace = array_values($processSpanFromArtisanTrace)[0]; - $spanLinks = $processSpanFromArtisanTrace['meta']['_dd.span_links']; - $spanLinks = json_decode($spanLinks, true)[0]; - $spanLinksTraceId = $spanLinks['trace_id']; - $spanLinksSpanId = $spanLinks['span_id']; + // v0.4 carries native span_links (ids as decimal integers); render them as hex. + $spanLinks = $processSpanFromArtisanTrace['span_links'][0]; + $toHex = function ($id) { + return str_pad(self::largeBaseConvert((string) $id, 10, 16), 16, '0', STR_PAD_LEFT); + }; + $spanLinksTraceId = $toHex($spanLinks['trace_id_high'] ?? 0) . $toHex($spanLinks['trace_id']); + $spanLinksSpanId = $toHex($spanLinks['span_id']); $processSpanFromProcessTrace = array_filter($processTrace1[0], function ($span) { return $span['name'] === 'laravel.queue.process'; diff --git a/tests/Integrations/Laravel/V8_x/TraceSearchConfigTest.php b/tests/Integrations/Laravel/V8_x/TraceSearchConfigTest.php deleted file mode 100644 index 0d76259fbc..0000000000 --- a/tests/Integrations/Laravel/V8_x/TraceSearchConfigTest.php +++ /dev/null @@ -1,84 +0,0 @@ - 'true', - 'DD_LARAVEL_ANALYTICS_SAMPLE_RATE' => '0.3', - ]); - } - - /** - * @throws \Exception - */ - public function testScenario() - { - $traces = $this->tracesFromWebRequest(function () { - $this->call(GetSpec::create('Testing trace analytics config metric', '/simple')); - }); - - $this->assertFlameGraph( - $traces, - [ - SpanAssertion::build( - 'laravel.request', - 'Laravel', - 'web', - 'App\Http\Controllers\CommonSpecsController@simple simple_route' - ) - ->withExactTags([ - 'laravel.route.name' => 'simple_route', - 'laravel.route.action' => 'App\Http\Controllers\CommonSpecsController@simple', - 'http.method' => 'GET', - 'http.url' => 'http://localhost/simple', - 'http.status_code' => '200', - 'http.route' => 'simple', - TAG::SPAN_KIND => 'server', - TAG::COMPONENT => 'laravel', - '_dd.svc_src' => 'laravel', - ]) - ->withExactMetrics([ - '_dd1.sr.eausr' => 0.3, - '_sampling_priority_v1' => 1, - ]) - ->withChildren([ - SpanAssertion::exists('laravel.action'), - SpanAssertion::exists( - 'laravel.provider.load', - 'Illuminate\Foundation\ProviderRepository::load' - ), - SpanAssertion::exists('laravel.event.handle'), - SpanAssertion::exists('laravel.event.handle'), - SpanAssertion::exists('laravel.event.handle'), - SpanAssertion::exists('laravel.event.handle'), - SpanAssertion::exists('laravel.event.handle'), - SpanAssertion::exists('laravel.event.handle'), - SpanAssertion::exists('laravel.event.handle'), - SpanAssertion::exists('laravel.event.handle'), - SpanAssertion::exists('laravel.event.handle'), - SpanAssertion::exists('laravel.event.handle'), - SpanAssertion::exists('laravel.event.handle'), - SpanAssertion::exists('laravel.event.handle'), - SpanAssertion::exists('laravel.event.handle'), - SpanAssertion::exists('laravel.event.handle'), - ]), - ] - ); - } -} diff --git a/tests/Integrations/Lumen/V10_0/TraceSearchConfigTest.php b/tests/Integrations/Lumen/V10_0/TraceSearchConfigTest.php deleted file mode 100644 index bee744eaa1..0000000000 --- a/tests/Integrations/Lumen/V10_0/TraceSearchConfigTest.php +++ /dev/null @@ -1,73 +0,0 @@ - 'true', - 'DD_LUMEN_ANALYTICS_SAMPLE_RATE' => '0.3', - ]); - } - - /** - * @throws \Exception - */ - public function testScenario() - { - $traces = $this->tracesFromWebRequest(function () { - $this->call(GetSpec::create('Testing trace analytics config metric', '/simple')); - }); - - $this->assertFlameGraph( - $traces, - [ - SpanAssertion::build( - 'lumen.request', - 'lumen', - 'web', - 'GET /simple' - ) - ->withExactTags([ - 'lumen.route.name' => 'simple_route', - 'lumen.route.action' => 'App\Http\Controllers\ExampleController@simple', - 'http.method' => 'GET', - 'http.url' => 'http://localhost/simple', - 'http.status_code' => '200', - Tag::SPAN_KIND => 'server', - Tag::COMPONENT => 'lumen', - '_dd.svc_src' => 'lumen', - ]) - ->withExactMetrics([ - '_dd1.sr.eausr' => 0.3, - '_sampling_priority_v1' => 1, - 'process_id' => getmypid(), - ]) - ->withChildren([ - SpanAssertion::build( - 'Laravel\Lumen\Application.handleFoundRoute', - 'lumen', - 'web', - 'simple_route' - )->withExactTags([ - 'lumen.route.action' => 'App\Http\Controllers\ExampleController@simple', - Tag::COMPONENT => 'lumen', - '_dd.svc_src' => 'lumen', - ]), - ]), - ] - ); - } -} diff --git a/tests/Integrations/Lumen/V5_2/TraceSearchConfigTest.php b/tests/Integrations/Lumen/V5_2/TraceSearchConfigTest.php deleted file mode 100644 index 962f268fbb..0000000000 --- a/tests/Integrations/Lumen/V5_2/TraceSearchConfigTest.php +++ /dev/null @@ -1,73 +0,0 @@ - 'true', - 'DD_LUMEN_ANALYTICS_SAMPLE_RATE' => '0.3', - ]); - } - - /** - * @throws \Exception - */ - public function testScenario() - { - $traces = $this->tracesFromWebRequest(function () { - $this->call(GetSpec::create('Testing trace analytics config metric', '/simple')); - }); - - $this->assertFlameGraph( - $traces, - [ - SpanAssertion::build( - 'lumen.request', - 'lumen', - 'web', - 'GET /simple' - ) - ->withExactTags([ - 'lumen.route.name' => 'simple_route', - 'lumen.route.action' => 'App\Http\Controllers\ExampleController@simple', - 'http.method' => 'GET', - 'http.url' => 'http://localhost/simple', - 'http.status_code' => '200', - Tag::SPAN_KIND => 'server', - TAG::COMPONENT => 'lumen', - '_dd.svc_src' => 'lumen', - ]) - ->withExactMetrics([ - '_dd1.sr.eausr' => 0.3, - '_sampling_priority_v1' => 1, - 'process_id' => getmypid(), - ]) - ->withChildren([ - SpanAssertion::build( - 'Laravel\Lumen\Application.handleFoundRoute', - 'lumen', - 'web', - 'simple_route' - )->withExactTags([ - 'lumen.route.action' => 'App\Http\Controllers\ExampleController@simple', - TAG::COMPONENT => 'lumen', - '_dd.svc_src' => 'lumen', - ]), - ]) - ] - ); - } -} diff --git a/tests/Integrations/Lumen/V5_6/TraceSearchConfigTest.php b/tests/Integrations/Lumen/V5_6/TraceSearchConfigTest.php deleted file mode 100644 index 8ed82832ff..0000000000 --- a/tests/Integrations/Lumen/V5_6/TraceSearchConfigTest.php +++ /dev/null @@ -1,73 +0,0 @@ - 'true', - 'DD_LUMEN_ANALYTICS_SAMPLE_RATE' => '0.3', - ]); - } - - /** - * @throws \Exception - */ - public function testScenario() - { - $traces = $this->tracesFromWebRequest(function () { - $this->call(GetSpec::create('Testing trace analytics config metric', '/simple')); - }); - - $this->assertFlameGraph( - $traces, - [ - SpanAssertion::build( - 'lumen.request', - 'lumen', - 'web', - 'GET /simple' - ) - ->withExactTags([ - 'lumen.route.name' => 'simple_route', - 'lumen.route.action' => 'App\Http\Controllers\ExampleController@simple', - 'http.method' => 'GET', - 'http.url' => 'http://localhost/simple', - 'http.status_code' => '200', - Tag::SPAN_KIND => 'server', - Tag::COMPONENT => 'lumen', - '_dd.svc_src' => 'lumen', - ]) - ->withExactMetrics([ - '_dd1.sr.eausr' => 0.3, - '_sampling_priority_v1' => 1, - 'process_id' => getmypid(), - ]) - ->withChildren([ - SpanAssertion::build( - 'Laravel\Lumen\Application.handleFoundRoute', - 'lumen', - 'web', - 'simple_route' - )->withExactTags([ - 'lumen.route.action' => 'App\Http\Controllers\ExampleController@simple', - Tag::COMPONENT => 'lumen', - '_dd.svc_src' => 'lumen', - ]), - ]), - ] - ); - } -} diff --git a/tests/Integrations/Lumen/V5_8/TraceSearchConfigTest.php b/tests/Integrations/Lumen/V5_8/TraceSearchConfigTest.php deleted file mode 100644 index dcefdc8bad..0000000000 --- a/tests/Integrations/Lumen/V5_8/TraceSearchConfigTest.php +++ /dev/null @@ -1,73 +0,0 @@ - 'true', - 'DD_LUMEN_ANALYTICS_SAMPLE_RATE' => '0.3', - ]); - } - - /** - * @throws \Exception - */ - public function testScenario() - { - $traces = $this->tracesFromWebRequest(function () { - $this->call(GetSpec::create('Testing trace analytics config metric', '/simple')); - }); - - $this->assertFlameGraph( - $traces, - [ - SpanAssertion::build( - 'lumen.request', - 'lumen', - 'web', - 'GET /simple' - ) - ->withExactTags([ - 'lumen.route.name' => 'simple_route', - 'lumen.route.action' => 'App\Http\Controllers\ExampleController@simple', - 'http.method' => 'GET', - 'http.url' => 'http://localhost/simple', - 'http.status_code' => '200', - Tag::SPAN_KIND => 'server', - Tag::COMPONENT => 'lumen', - '_dd.svc_src' => 'lumen', - ]) - ->withExactMetrics([ - '_dd1.sr.eausr' => 0.3, - '_sampling_priority_v1' => 1, - 'process_id' => getmypid(), - ]) - ->withChildren([ - SpanAssertion::build( - 'Laravel\Lumen\Application.handleFoundRoute', - 'lumen', - 'web', - 'simple_route' - )->withExactTags([ - 'lumen.route.action' => 'App\Http\Controllers\ExampleController@simple', - Tag::COMPONENT => 'lumen', - '_dd.svc_src' => 'lumen', - ]), - ]), - ] - ); - } -} diff --git a/tests/Integrations/Lumen/V8_1/TraceSearchConfigTest.php b/tests/Integrations/Lumen/V8_1/TraceSearchConfigTest.php deleted file mode 100644 index 5f2f141ed2..0000000000 --- a/tests/Integrations/Lumen/V8_1/TraceSearchConfigTest.php +++ /dev/null @@ -1,73 +0,0 @@ - 'true', - 'DD_LUMEN_ANALYTICS_SAMPLE_RATE' => '0.3', - ]); - } - - /** - * @throws \Exception - */ - public function testScenario() - { - $traces = $this->tracesFromWebRequest(function () { - $this->call(GetSpec::create('Testing trace analytics config metric', '/simple')); - }); - - $this->assertFlameGraph( - $traces, - [ - SpanAssertion::build( - 'lumen.request', - 'lumen', - 'web', - 'GET /simple' - ) - ->withExactTags([ - 'lumen.route.name' => 'simple_route', - 'lumen.route.action' => 'App\Http\Controllers\ExampleController@simple', - 'http.method' => 'GET', - 'http.url' => 'http://localhost/simple', - 'http.status_code' => '200', - Tag::SPAN_KIND => 'server', - Tag::COMPONENT => 'lumen', - '_dd.svc_src' => 'lumen', - ]) - ->withExactMetrics([ - '_dd1.sr.eausr' => 0.3, - '_sampling_priority_v1' => 1, - 'process_id' => getmypid(), - ]) - ->withChildren([ - SpanAssertion::build( - 'Laravel\Lumen\Application.handleFoundRoute', - 'lumen', - 'web', - 'simple_route' - )->withExactTags([ - 'lumen.route.action' => 'App\Http\Controllers\ExampleController@simple', - Tag::COMPONENT => 'lumen', - '_dd.svc_src' => 'lumen', - ]), - ]), - ] - ); - } -} diff --git a/tests/Integrations/Lumen/V9_0/TraceSearchConfigTest.php b/tests/Integrations/Lumen/V9_0/TraceSearchConfigTest.php deleted file mode 100644 index 87675daa15..0000000000 --- a/tests/Integrations/Lumen/V9_0/TraceSearchConfigTest.php +++ /dev/null @@ -1,73 +0,0 @@ - 'true', - 'DD_LUMEN_ANALYTICS_SAMPLE_RATE' => '0.3', - ]); - } - - /** - * @throws \Exception - */ - public function testScenario() - { - $traces = $this->tracesFromWebRequest(function () { - $this->call(GetSpec::create('Testing trace analytics config metric', '/simple')); - }); - - $this->assertFlameGraph( - $traces, - [ - SpanAssertion::build( - 'lumen.request', - 'lumen', - 'web', - 'GET /simple' - ) - ->withExactTags([ - 'lumen.route.name' => 'simple_route', - 'lumen.route.action' => 'App\Http\Controllers\ExampleController@simple', - 'http.method' => 'GET', - 'http.url' => 'http://localhost/simple', - 'http.status_code' => '200', - Tag::SPAN_KIND => 'server', - Tag::COMPONENT => 'lumen', - '_dd.svc_src' => 'lumen', - ]) - ->withExactMetrics([ - '_dd1.sr.eausr' => 0.3, - '_sampling_priority_v1' => 1, - 'process_id' => getmypid(), - ]) - ->withChildren([ - SpanAssertion::build( - 'Laravel\Lumen\Application.handleFoundRoute', - 'lumen', - 'web', - 'simple_route' - )->withExactTags([ - 'lumen.route.action' => 'App\Http\Controllers\ExampleController@simple', - Tag::COMPONENT => 'lumen', - '_dd.svc_src' => 'lumen', - ]), - ]), - ] - ); - } -} diff --git a/tests/Integrations/MongoDB/Latest/MongoDBTest.php b/tests/Integrations/MongoDB/Latest/MongoDBTest.php index d4805c6432..f06ef68287 100644 --- a/tests/Integrations/MongoDB/Latest/MongoDBTest.php +++ b/tests/Integrations/MongoDB/Latest/MongoDBTest.php @@ -396,9 +396,9 @@ public function testQueryNormalization($query, $expected) }); if (null === $expected) { - $this->assertArrayNotHasKey('mongodb.query', $traces[0][0]['meta']); + $this->assertArrayNotHasKey('mongodb.query', $traces[0][0]['attributes']); } else { - $this->assertSame($expected, $traces[0][0]['meta']['mongodb.query']); + $this->assertSame($expected, $traces[0][0]['attributes']['mongodb.query']); } } diff --git a/tests/Integrations/Mysqli/MysqliTest.php b/tests/Integrations/Mysqli/MysqliTest.php index 525a795f62..fc532c77b2 100644 --- a/tests/Integrations/Mysqli/MysqliTest.php +++ b/tests/Integrations/Mysqli/MysqliTest.php @@ -636,7 +636,7 @@ public function testPreparedStatementUsesServiceModeForDBM() // Verify that SERVICE mode is used for the prepare span $this->assertArrayNotHasKey( '_dd.dbm_trace_injected', - $prepareSpan['meta'] ?? [], + $prepareSpan['attributes'] ?? [], 'mysqli.prepare should use SERVICE mode' ); } diff --git a/tests/Integrations/PDO/PDOTest.php b/tests/Integrations/PDO/PDOTest.php index b2abb86e49..ae7e5f68fe 100644 --- a/tests/Integrations/PDO/PDOTest.php +++ b/tests/Integrations/PDO/PDOTest.php @@ -26,14 +26,12 @@ final class PDOTest extends IntegrationTestCase public static function ddSetUpBeforeClass() { - self::putenv('DD_PDO_ANALYTICS_ENABLED=true'); parent::ddSetUpBeforeClass(); } public static function ddTearDownAfterClass() { parent::ddTearDownAfterClass(); - self::putenv('DD_PDO_ANALYTICS_ENABLED'); } protected function ddSetUp() @@ -93,7 +91,6 @@ public function testCustomPDOPrepareWithStringableStatement() ->withExactTags($this->baseTags()) ->withExactMetrics([ Tag::DB_ROW_COUNT => 1.0, - Tag::ANALYTICS_KEY => 1.0, '_dd.agent_psr' => 1.0, '_sampling_priority_v1' => 1.0, ]), @@ -238,7 +235,6 @@ public function testPDOExecOk() ->withExactTags($this->baseTags()) ->withExactMetrics([ Tag::DB_ROW_COUNT => 1.0, - Tag::ANALYTICS_KEY => 1.0, '_dd.agent_psr' => 1.0, '_sampling_priority_v1' => 1.0, ]), @@ -305,7 +301,6 @@ public function testPDOQuery() ->withExactTags($this->baseTags()) ->withExactMetrics([ Tag::DB_ROW_COUNT => 1.0, - Tag::ANALYTICS_KEY => 1.0, '_dd.agent_psr' => 1.0, '_sampling_priority_v1' => 1.0, ]), @@ -328,7 +323,6 @@ public function testPDOQueryPeerServiceEnabled() ->withExactTags($this->baseTags(true)) ->withExactMetrics([ Tag::DB_ROW_COUNT => 1.0, - Tag::ANALYTICS_KEY => 1.0, '_dd.agent_psr' => 1.0, '_sampling_priority_v1' => 1.0, ]), @@ -445,7 +439,6 @@ public function testPDOStatementOk() ->withExactTags($this->baseTags()) ->withExactMetrics([ Tag::DB_ROW_COUNT => 1.0, - Tag::ANALYTICS_KEY => 1.0, '_dd.agent_psr' => 1.0, '_sampling_priority_v1' => 1.0, ]), @@ -484,7 +477,6 @@ public function testPDOStatementOkPeerServiceEnabled() ->withExactTags($this->baseTags(true)) ->withExactMetrics([ Tag::DB_ROW_COUNT => 1.0, - Tag::ANALYTICS_KEY => 1.0, '_dd.agent_psr' => 1.0, '_sampling_priority_v1' => 1.0, ]), @@ -522,7 +514,6 @@ public function testPDOStatementSplitByDomain() ->withExactTags($this->baseTags(false, 'opt.db_client_split_by_instance')) ->withExactMetrics([ Tag::DB_ROW_COUNT => 1.0, - Tag::ANALYTICS_KEY => 1.0, '_dd.agent_psr' => 1.0, '_sampling_priority_v1' => 1.0, ]), @@ -561,7 +552,6 @@ public function testPDOStatementSplitByDomainAndServiceFlattening() ->withExactTags($this->baseTags(false, 'opt.db_client_split_by_instance')) ->withExactMetrics([ Tag::DB_ROW_COUNT => 1.0, - Tag::ANALYTICS_KEY => 1.0, '_dd.agent_psr' => 1.0, '_sampling_priority_v1' => 1.0, ]), @@ -740,7 +730,7 @@ public function testPreparedStatementUsesServiceModeForDBM() // Verify that SERVICE mode is used for the prepare span $this->assertArrayNotHasKey( '_dd.dbm_trace_injected', - $prepareSpan['meta'] ?? [], + $prepareSpan['attributes'] ?? [], 'PDO.prepare should use SERVICE mode' ); } @@ -779,7 +769,6 @@ public function testDirectQueryHasNoParentIssues() ->withExactTags($this->baseTags()) ->withExactMetrics([ Tag::DB_ROW_COUNT => 1.0, - Tag::ANALYTICS_KEY => 1.0, '_dd.agent_psr' => 1.0, '_sampling_priority_v1' => 1.0, ]), @@ -823,7 +812,7 @@ public function testNoFakeServices() SpanAssertion::exists('PDO.__construct'), SpanAssertion::build('PDO.exec', 'configured_service', 'sql', $query) ->withExactTags($this->baseTags(false, null)) - ->withExactMetrics([Tag::DB_ROW_COUNT => 1.0, Tag::ANALYTICS_KEY => 1.0]), + ->withExactMetrics([Tag::DB_ROW_COUNT => 1.0]), SpanAssertion::exists('PDO.commit'), ], false); } diff --git a/tests/Integrations/PHPRedis/V5/PHPRedisTest.php b/tests/Integrations/PHPRedis/V5/PHPRedisTest.php index ea8edf96e2..16008833ce 100644 --- a/tests/Integrations/PHPRedis/V5/PHPRedisTest.php +++ b/tests/Integrations/PHPRedis/V5/PHPRedisTest.php @@ -2486,7 +2486,7 @@ public function testOrphansRemoval() }); $span = $traces[0][0]; - $this->assertEquals(0, $span['metrics']['_sampling_priority_v1']); + $this->assertEquals(0, $span['sampling_priority']); } public function testOrphansRemoval64bit() @@ -2502,6 +2502,6 @@ public function testOrphansRemoval64bit() }); $span = $traces[0][0]; - $this->assertEquals(0, $span['metrics']['_sampling_priority_v1']); + $this->assertEquals(0, $span['sampling_priority']); } } diff --git a/tests/Integrations/Predis/Latest/PredisTest.php b/tests/Integrations/Predis/Latest/PredisTest.php index e7171106a9..64389b726c 100644 --- a/tests/Integrations/Predis/Latest/PredisTest.php +++ b/tests/Integrations/Predis/Latest/PredisTest.php @@ -70,8 +70,8 @@ public function testConnectionAndServiceInfo($firstArgument, $host, $port, $serv } }); $span = $traces[0][0]; - $this->assertSame($host, $span['meta']['out.host']); - $this->assertSame("$port", $span['meta']['out.port']); + $this->assertSame($host, $span['attributes']['out.host']); + $this->assertSame("$port", $span['attributes']['out.port']); $this->assertSame('redis', $span['service']); // With split by domain @@ -84,8 +84,8 @@ public function testConnectionAndServiceInfo($firstArgument, $host, $port, $serv } }); $span = $traces[0][0]; - $this->assertSame($host, $span['meta']['out.host']); - $this->assertSame("$port", $span['meta']['out.port']); + $this->assertSame($host, $span['attributes']['out.host']); + $this->assertSame("$port", $span['attributes']['out.port']); $this->assertSame($service, $span['service']); } @@ -349,7 +349,7 @@ public function testOrphansRemoval() }); $span = $traces[0][0]; - $this->assertEquals(0, $span['metrics']['_sampling_priority_v1']); + $this->assertEquals(0, $span['sampling_priority']); } public function testOrphansRemoval64bit() @@ -364,7 +364,7 @@ public function testOrphansRemoval64bit() }); $span = $traces[0][0]; - $this->assertEquals(0, $span['metrics']['_sampling_priority_v1']); + $this->assertEquals(0, $span['sampling_priority']); } public function testNoFakeServices() diff --git a/tests/Integrations/Ratchet/V0_4/RatchetTest.php b/tests/Integrations/Ratchet/V0_4/RatchetTest.php index cca875d9a1..8fbf9dfb16 100644 --- a/tests/Integrations/Ratchet/V0_4/RatchetTest.php +++ b/tests/Integrations/Ratchet/V0_4/RatchetTest.php @@ -74,7 +74,7 @@ public function onError(ConnectionInterface $conn, \Exception $e) { foreach ($traces[0] as &$span) { $span["resource"] = preg_replace('(:(\d+)$)', ':%d', $span["resource"]); // Our checker has problems with two root spans being identical in primary attributes - if ($span["resource"] === "websocket /" && ($span["metrics"]['websocket.message.length'] ?? "") == '12') { + if ($span["resource"] === "websocket /" && ($span["attributes"]['websocket.message.length'] ?? "") == '12') { $span["resource"] .= 2; } } diff --git a/tests/Integrations/SQLSRV/SQLSRVTest.php b/tests/Integrations/SQLSRV/SQLSRVTest.php index 70b85ff515..cad76a9146 100644 --- a/tests/Integrations/SQLSRV/SQLSRVTest.php +++ b/tests/Integrations/SQLSRV/SQLSRVTest.php @@ -33,7 +33,6 @@ private static function getArchitecture() public static function ddSetUpBeforeClass() { parent::ddSetUpBeforeClass(); - self::putenv('DD_SQLSRV_ANALYTICS_ENABLED=true'); self::waitForSqlServerReady(); } @@ -76,7 +75,6 @@ private static function waitForSqlServerReady() public static function ddTearDownAfterClass() { parent::ddTearDownAfterClass(); - self::putenv('DD_SQLSRV_ANALYTICS_ENABLED'); } protected function ddSetUp() @@ -147,7 +145,6 @@ public function testQueryOk() ->withExactTags(self::baseTags($query)) ->withExactMetrics([ Tag::DB_ROW_COUNT => 1.0, - Tag::ANALYTICS_KEY => 1.0, '_dd.agent_psr' => 1.0, '_sampling_priority_v1' => 1.0, ]) @@ -171,7 +168,6 @@ public function testQueryOkPeerServiceEnabled() ->withExactTags(self::baseTags($query, true)) ->withExactMetrics([ Tag::DB_ROW_COUNT => 1.0, - Tag::ANALYTICS_KEY => 1.0, '_dd.agent_psr' => 1.0, '_sampling_priority_v1' => 1.0, ]) @@ -196,7 +192,6 @@ public function testQueryError() 'SQLSRV error', self::getArchitecture() === 'x86_64' ? SQLSRVTest::ERROR_QUERY_17 : SQLSRVTest::ERROR_QUERY_18 )->withExactMetrics([ - Tag::ANALYTICS_KEY => 1.0, '_dd.agent_psr' => 1.0, '_sampling_priority_v1' => 1.0, ]) @@ -223,7 +218,6 @@ public function testQueryErrorPeerServiceEnabled() 'SQLSRV error', self::getArchitecture() === 'x86_64' ? SQLSRVTest::ERROR_QUERY_17 : SQLSRVTest::ERROR_QUERY_18 )->withExactMetrics([ - Tag::ANALYTICS_KEY => 1.0, '_dd.agent_psr' => 1.0, '_sampling_priority_v1' => 1.0, ]) @@ -248,7 +242,6 @@ public function testCommitOk() ->withExactTags(self::baseTags($query)) ->withExactMetrics([ Tag::DB_ROW_COUNT => 1.0, - Tag::ANALYTICS_KEY => 1.0, '_dd.agent_psr' => 1.0, '_sampling_priority_v1' => 1.0, ]), @@ -275,7 +268,6 @@ public function testPrepareOk() ->withExactTags(self::baseTags($query)) ->withExactMetrics([ Tag::DB_ROW_COUNT => 1.0, - Tag::ANALYTICS_KEY => 1.0, '_dd.agent_psr' => 1.0, '_sampling_priority_v1' => 1.0, ]) @@ -302,7 +294,6 @@ public function testPrepareOkPeerServiceEnabled() ->withExactTags(self::baseTags($query, true)) ->withExactMetrics([ Tag::DB_ROW_COUNT => 1.0, - Tag::ANALYTICS_KEY => 1.0, '_dd.agent_psr' => 1.0, '_sampling_priority_v1' => 1.0, ]) @@ -328,7 +319,6 @@ public function testPrepareError() self::getArchitecture() === 'x86_64' ? SQLSRVTest::ERROR_QUERY_17 : SQLSRVTest::ERROR_QUERY_18 )->withExactTags(self::baseTags($query)) ->withExactMetrics([ - Tag::ANALYTICS_KEY => 1.0, '_dd.agent_psr' => 1.0, '_sampling_priority_v1' => 1.0, ]) @@ -356,7 +346,6 @@ public function testPrepareErrorPeerServiceEnabled() self::getArchitecture() === 'x86_64' ? SQLSRVTest::ERROR_QUERY_17 : SQLSRVTest::ERROR_QUERY_18 )->withExactTags(self::baseTags($query, true)) ->withExactMetrics([ - Tag::ANALYTICS_KEY => 1.0, '_dd.agent_psr' => 1.0, '_sampling_priority_v1' => 1.0, ]) @@ -414,7 +403,7 @@ public function testPreparedStatementUsesServiceModeForDBM() // Verify that SERVICE mode is used for the prepare span $this->assertArrayNotHasKey( '_dd.dbm_trace_injected', - $prepareSpan['meta'] ?? [], + $prepareSpan['attributes'] ?? [], 'sqlsrv_prepare should use SERVICE mode' ); } @@ -503,7 +492,6 @@ public function testConnectPrepareStatement() ->withExactTags(self::baseTags($query)) ->withExactMetrics([ Tag::DB_ROW_COUNT => 1.0, - Tag::ANALYTICS_KEY => 1.0, '_dd.agent_psr' => 1.0, '_sampling_priority_v1' => 1.0, ]) @@ -530,7 +518,6 @@ public function testNoFakeServices() ->withExactTags(self::baseTags($query, false, null)) ->withExactMetrics([ Tag::DB_ROW_COUNT => 1.0, - Tag::ANALYTICS_KEY => 1.0, '_dd.agent_psr' => 1.0, '_sampling_priority_v1' => 1.0, ]) diff --git a/tests/Integrations/Symfony/Latest/TraceSearchConfigTest.php b/tests/Integrations/Symfony/Latest/TraceSearchConfigTest.php deleted file mode 100644 index 9d36b4f577..0000000000 --- a/tests/Integrations/Symfony/Latest/TraceSearchConfigTest.php +++ /dev/null @@ -1,11 +0,0 @@ - 'true', - 'DD_SYMFONY_ANALYTICS_SAMPLE_RATE' => '0.3', - ]); - } - - /** - * @throws \Exception - */ - public function testScenario() - { - $traces = $this->tracesFromWebRequest(function () { - $this->call(GetSpec::create('Testing trace analytics config metric', '/simple')); - }); - - $this->assertFlameGraph( - $traces, - [ - SpanAssertion::build( - 'symfony.request', - 'symfony', - 'web', - 'simple' - )->withExactTags([ - 'symfony.route.action' => 'AppBundle\Controller\CommonScenariosController@simpleAction', - 'symfony.route.name' => 'simple', - 'http.method' => 'GET', - 'http.url' => 'http://localhost/simple', - 'http.status_code' => '200', - Tag::SPAN_KIND => 'server', - Tag::COMPONENT => 'symfony', - '_dd.svc_src' => 'symfony', - ])->withExactMetrics([ - '_dd1.sr.eausr' => 0.3, - '_sampling_priority_v1' => 1, - 'process_id' => getmypid(), - ])->withChildren([ - SpanAssertion::exists('symfony.httpkernel.kernel.handle')->withChildren([ - SpanAssertion::exists('symfony.httpkernel.kernel.boot'), - SpanAssertion::exists('symfony.kernel.handle')->withChildren([ - SpanAssertion::exists('symfony.kernel.request')->withChildren([ - SpanAssertion::exists('symfony.security.authentication.success'), - ]), - SpanAssertion::exists('symfony.kernel.controller'), - SpanAssertion::exists('symfony.kernel.controller'), - SpanAssertion::exists('symfony.kernel.response'), - SpanAssertion::exists('symfony.kernel.finish_request'), - ]), - ]), - SpanAssertion::exists('symfony.kernel.terminate'), - ]), - ] - ); - } -} diff --git a/tests/Integrations/Symfony/V3_3/TraceSearchConfigTest.php b/tests/Integrations/Symfony/V3_3/TraceSearchConfigTest.php deleted file mode 100644 index 5483d95fb4..0000000000 --- a/tests/Integrations/Symfony/V3_3/TraceSearchConfigTest.php +++ /dev/null @@ -1,82 +0,0 @@ - 'true', - 'DD_SYMFONY_ANALYTICS_SAMPLE_RATE' => '0.3', - ]); - } - - /** - * @throws \Exception - */ - public function testScenario() - { - $traces = $this->tracesFromWebRequest(function () { - $this->call(GetSpec::create('Testing trace analytics config metric', '/simple')); - }); - - $this->assertFlameGraph( - $traces, - [ - SpanAssertion::build( - 'symfony.request', - 'symfony', - 'web', - 'simple' - )->withExactTags([ - 'symfony.route.action' => 'AppBundle\Controller\CommonScenariosController@simpleAction', - 'symfony.route.name' => 'simple', - - 'http.method' => 'GET', - 'http.url' => 'http://localhost/simple', - 'http.status_code' => '200', - Tag::SPAN_KIND => 'server', - Tag::COMPONENT => 'symfony', - '_dd.svc_src' => 'symfony', - ])->withExactMetrics([ - '_dd1.sr.eausr' => 0.3, - '_sampling_priority_v1' => 1, - 'process_id' => getmypid(), - ])->withChildren([ - SpanAssertion::exists('symfony.httpkernel.kernel.handle')->withChildren([ - SpanAssertion::exists('symfony.httpkernel.kernel.boot'), - SpanAssertion::exists('symfony.kernel.handle')->withChildren([ - SpanAssertion::exists('symfony.kernel.request')->withChildren([ - SpanAssertion::exists('symfony.security.authentication.success'), - ]), - SpanAssertion::exists('symfony.kernel.controller'), - SpanAssertion::exists('symfony.kernel.controller_arguments'),SpanAssertion::build( - 'symfony.controller', - 'symfony', - 'web', - 'AppBundle\Controller\CommonScenariosController::simpleAction' - )->withExactTags([ - Tag::COMPONENT => 'symfony', - '_dd.svc_src' => 'symfony', - ]), - SpanAssertion::exists('symfony.kernel.response'), - SpanAssertion::exists('symfony.kernel.finish_request'), - ]), - ]), - SpanAssertion::exists('symfony.kernel.terminate'), - ]), - ] - ); - } -} diff --git a/tests/Integrations/Symfony/V3_4/TraceSearchConfigTest.php b/tests/Integrations/Symfony/V3_4/TraceSearchConfigTest.php deleted file mode 100644 index e8691e90ed..0000000000 --- a/tests/Integrations/Symfony/V3_4/TraceSearchConfigTest.php +++ /dev/null @@ -1,84 +0,0 @@ - 'true', - 'DD_SYMFONY_ANALYTICS_SAMPLE_RATE' => '0.3', - ]); - } - - /** - * @throws \Exception - */ - public function testScenario() - { - $traces = $this->tracesFromWebRequest(function () { - $this->call(GetSpec::create('Testing trace analytics config metric', '/simple')); - }); - - $this->assertFlameGraph( - $traces, - [ - SpanAssertion::build( - 'symfony.request', - 'symfony', - 'web', - 'simple' - )->withExactTags([ - 'symfony.route.action' => 'AppBundle\Controller\CommonScenariosController@simpleAction', - 'symfony.route.name' => 'simple', - - 'http.method' => 'GET', - 'http.url' => 'http://localhost/simple', - 'http.status_code' => '200', - Tag::SPAN_KIND => 'server', - Tag::COMPONENT => 'symfony', - '_dd.svc_src' => 'symfony', - ])->withExactMetrics([ - '_dd1.sr.eausr' => 0.3, - '_sampling_priority_v1' => 1, - 'process_id' => getmypid(), - ])->withChildren([ - SpanAssertion::exists('symfony.httpkernel.kernel.handle')->withChildren([ - SpanAssertion::exists('symfony.httpkernel.kernel.boot'), - SpanAssertion::exists('symfony.kernel.handle') - ->withChildren([ - SpanAssertion::exists('symfony.kernel.request')->withChildren([ - SpanAssertion::exists('symfony.security.authentication.success'), - ]), - SpanAssertion::exists('symfony.kernel.controller'), - SpanAssertion::exists('symfony.kernel.controller_arguments'), - SpanAssertion::build( - 'symfony.controller', - 'symfony', - 'web', - 'AppBundle\Controller\CommonScenariosController::simpleAction' - )->withExactTags([ - Tag::COMPONENT => 'symfony', - '_dd.svc_src' => 'symfony', - ]), - SpanAssertion::exists('symfony.kernel.response'), - SpanAssertion::exists('symfony.kernel.finish_request'), - ]), - ]), - SpanAssertion::exists('symfony.kernel.terminate'), - ]), - ] - ); - } -} diff --git a/tests/Integrations/Symfony/V4_0/TraceSearchConfigTest.php b/tests/Integrations/Symfony/V4_0/TraceSearchConfigTest.php deleted file mode 100644 index c92a93e924..0000000000 --- a/tests/Integrations/Symfony/V4_0/TraceSearchConfigTest.php +++ /dev/null @@ -1,83 +0,0 @@ - 'true', - 'DD_SYMFONY_ANALYTICS_SAMPLE_RATE' => '0.3', - ]); - } - - /** - * @throws \Exception - */ - public function testScenario() - { - $traces = $this->tracesFromWebRequest(function () { - $this->call(GetSpec::create('Testing trace analytics config metric', '/simple')); - }); - - $this->assertFlameGraph( - $traces, - [ - SpanAssertion::build( - 'symfony.request', - 'symfony', - 'web', - 'simple' - )->withExactTags([ - 'symfony.route.action' => 'App\Controller\CommonScenariosController@simpleAction', - 'symfony.route.name' => 'simple', - - 'http.method' => 'GET', - 'http.url' => 'http://localhost/simple', - 'http.status_code' => '200', - Tag::SPAN_KIND => 'server', - Tag::COMPONENT => 'symfony', - '_dd.svc_src' => 'symfony', - ])->withExactMetrics([ - '_dd1.sr.eausr' => 0.3, - '_sampling_priority_v1' => 1, - 'process_id' => getmypid(), - ])->withChildren([ - SpanAssertion::exists('symfony.kernel.terminate'), - SpanAssertion::exists('symfony.httpkernel.kernel.handle')->withChildren([ - SpanAssertion::exists('symfony.httpkernel.kernel.boot'), - SpanAssertion::exists('symfony.kernel.handle')->withChildren([ - SpanAssertion::exists('symfony.kernel.request')->withChildren([ - SpanAssertion::exists('symfony.security.authentication.success'), - ]), - SpanAssertion::exists('symfony.kernel.controller'), - SpanAssertion::exists('symfony.kernel.controller_arguments'), - SpanAssertion::build( - 'symfony.controller', - 'symfony', - 'web', - 'App\Controller\CommonScenariosController::simpleAction' - )->withExactTags([ - Tag::COMPONENT => 'symfony', - '_dd.svc_src' => 'symfony', - ]), - SpanAssertion::exists('symfony.kernel.response'), - SpanAssertion::exists('symfony.kernel.finish_request'), - ]), - ]), - ]), - ] - ); - } -} diff --git a/tests/Integrations/Symfony/V4_2/TraceSearchConfigTest.php b/tests/Integrations/Symfony/V4_2/TraceSearchConfigTest.php deleted file mode 100644 index 3e24e5bd01..0000000000 --- a/tests/Integrations/Symfony/V4_2/TraceSearchConfigTest.php +++ /dev/null @@ -1,84 +0,0 @@ - 'true', - 'DD_SYMFONY_ANALYTICS_SAMPLE_RATE' => '0.3', - ]); - } - - /** - * @throws \Exception - */ - public function testScenario() - { - $traces = $this->tracesFromWebRequest(function () { - $this->call(GetSpec::create('Testing trace analytics config metric', '/simple')); - }); - - $this->assertFlameGraph( - $traces, - [ - SpanAssertion::build( - 'symfony.request', - 'symfony', - 'web', - 'simple' - )->withExactTags([ - 'symfony.route.action' => 'App\Controller\CommonScenariosController@simpleAction', - 'symfony.route.name' => 'simple', - - 'http.method' => 'GET', - 'http.url' => 'http://localhost/simple', - 'http.status_code' => '200', - Tag::SPAN_KIND => 'server', - Tag::COMPONENT => 'symfony', - '_dd.svc_src' => 'symfony', - ])->withExactMetrics([ - '_dd1.sr.eausr' => 0.3, - '_sampling_priority_v1' => 1, - 'process_id' => getmypid(), - ]) ->withChildren([ - SpanAssertion::exists('symfony.kernel.terminate'), - SpanAssertion::exists('symfony.httpkernel.kernel.handle')->withChildren([ - SpanAssertion::exists('symfony.httpkernel.kernel.boot'), - SpanAssertion::exists('symfony.kernel.handle') - ->withChildren([ - SpanAssertion::exists('symfony.kernel.request')->withChildren([ - SpanAssertion::exists('symfony.security.authentication.success'), - ]), - SpanAssertion::exists('symfony.kernel.controller'), - SpanAssertion::exists('symfony.kernel.controller_arguments'), - SpanAssertion::build( - 'symfony.controller', - 'symfony', - 'web', - 'App\Controller\CommonScenariosController::simpleAction' - )->withExactTags([ - Tag::COMPONENT => 'symfony', - '_dd.svc_src' => 'symfony', - ]), - SpanAssertion::exists('symfony.kernel.response'), - SpanAssertion::exists('symfony.kernel.finish_request'), - ]), - ]), - ]), - ] - ); - } -} diff --git a/tests/Integrations/Symfony/V4_4/TraceSearchConfigTest.php b/tests/Integrations/Symfony/V4_4/TraceSearchConfigTest.php deleted file mode 100644 index ccf749e2c2..0000000000 --- a/tests/Integrations/Symfony/V4_4/TraceSearchConfigTest.php +++ /dev/null @@ -1,83 +0,0 @@ - 'true', - 'DD_SYMFONY_ANALYTICS_SAMPLE_RATE' => '0.3', - ]); - } - - /** - * @throws \Exception - */ - public function testScenario() - { - $traces = $this->tracesFromWebRequest(function () { - $this->call(GetSpec::create('Testing trace analytics config metric', '/simple')); - }); - - $this->assertFlameGraph( - $traces, - [ - SpanAssertion::build( - 'symfony.request', - 'symfony', - 'web', - 'simple' - )->withExactTags([ - 'symfony.route.action' => 'App\Controller\CommonScenariosController@simpleAction', - 'symfony.route.name' => 'simple', - 'http.route' => '/simple', - 'http.method' => 'GET', - 'http.url' => 'http://localhost/simple', - 'http.status_code' => '200', - Tag::SPAN_KIND => 'server', - Tag::COMPONENT => 'symfony', - '_dd.svc_src' => 'symfony', - ])->withExactMetrics([ - '_dd1.sr.eausr' => 0.3, - '_sampling_priority_v1' => 1, - 'process_id' => getmypid(), - ])->withChildren([ - SpanAssertion::exists('symfony.kernel.terminate'), - SpanAssertion::exists('symfony.httpkernel.kernel.handle')->withChildren([ - SpanAssertion::exists('symfony.httpkernel.kernel.boot'), - SpanAssertion::exists('symfony.kernel.handle')->withChildren([ - SpanAssertion::exists('symfony.kernel.request'), - SpanAssertion::exists('symfony.kernel.controller'), - SpanAssertion::exists('symfony.kernel.controller_arguments'), - SpanAssertion::build( - 'symfony.controller', - 'symfony', - 'web', - 'App\Controller\CommonScenariosController::simpleAction' - )->withExactTags([ - Tag::COMPONENT => 'symfony', - '_dd.svc_src' => 'symfony', - ]), - SpanAssertion::exists('symfony.kernel.response')->withChildren([ - SpanAssertion::exists('symfony.security.authentication.success') - ]), - SpanAssertion::exists('symfony.kernel.finish_request'), - ]), - ]), - ]), - ] - ); - } -} diff --git a/tests/Integrations/Symfony/V5_0/TraceSearchConfigTest.php b/tests/Integrations/Symfony/V5_0/TraceSearchConfigTest.php deleted file mode 100644 index 7c9cbfee07..0000000000 --- a/tests/Integrations/Symfony/V5_0/TraceSearchConfigTest.php +++ /dev/null @@ -1,83 +0,0 @@ - 'true', - 'DD_SYMFONY_ANALYTICS_SAMPLE_RATE' => '0.3', - ]); - } - - /** - * @throws \Exception - */ - public function testScenario() - { - $traces = $this->tracesFromWebRequest(function () { - $this->call(GetSpec::create('Testing trace analytics config metric', '/simple')); - }); - - $this->assertFlameGraph( - $traces, - [ - SpanAssertion::build( - 'symfony.request', - 'symfony', - 'web', - 'simple' - )->withExactTags([ - 'symfony.route.action' => 'App\Controller\CommonScenariosController@simpleAction', - 'symfony.route.name' => 'simple', - 'http.route' => '/simple', - 'http.method' => 'GET', - 'http.url' => 'http://localhost/simple', - 'http.status_code' => '200', - Tag::SPAN_KIND => 'server', - Tag::COMPONENT => 'symfony', - '_dd.svc_src' => 'symfony', - ])->withExactMetrics([ - '_dd1.sr.eausr' => 0.3, - '_sampling_priority_v1' => 1, - 'process_id' => getmypid(), - ])->withChildren([ - SpanAssertion::exists('symfony.kernel.terminate'), - SpanAssertion::exists('symfony.httpkernel.kernel.handle')->withChildren([ - SpanAssertion::exists('symfony.httpkernel.kernel.boot'), - SpanAssertion::exists('symfony.kernel.handle')->withChildren([ - SpanAssertion::exists('symfony.kernel.request'), - SpanAssertion::exists('symfony.kernel.controller'), - SpanAssertion::exists('symfony.kernel.controller_arguments'), - SpanAssertion::build( - 'symfony.controller', - 'symfony', - 'web', - 'App\Controller\CommonScenariosController::simpleAction' - )->withExactTags([ - Tag::COMPONENT => 'symfony', - '_dd.svc_src' => 'symfony', - ]), - SpanAssertion::exists('symfony.kernel.response')->withChildren([ - SpanAssertion::exists('symfony.security.authentication.success') - ]), - SpanAssertion::exists('symfony.kernel.finish_request'), - ]), - ]), - ]), - ] - ); - } -} diff --git a/tests/Integrations/Symfony/V5_1/TraceSearchConfigTest.php b/tests/Integrations/Symfony/V5_1/TraceSearchConfigTest.php deleted file mode 100644 index 5044eafd65..0000000000 --- a/tests/Integrations/Symfony/V5_1/TraceSearchConfigTest.php +++ /dev/null @@ -1,83 +0,0 @@ - 'true', - 'DD_SYMFONY_ANALYTICS_SAMPLE_RATE' => '0.3', - ]); - } - - /** - * @throws \Exception - */ - public function testScenario() - { - $traces = $this->tracesFromWebRequest(function () { - $this->call(GetSpec::create('Testing trace analytics config metric', '/simple')); - }); - - $this->assertFlameGraph( - $traces, - [ - SpanAssertion::build( - 'symfony.request', - 'symfony', - 'web', - 'simple' - )->withExactTags([ - 'symfony.route.action' => 'App\Controller\CommonScenariosController@simpleAction', - 'symfony.route.name' => 'simple', - 'http.route' => '/simple', - 'http.method' => 'GET', - 'http.url' => 'http://localhost/simple', - 'http.status_code' => '200', - Tag::SPAN_KIND => 'server', - Tag::COMPONENT => 'symfony', - '_dd.svc_src' => 'symfony', - ])->withExactMetrics([ - '_dd1.sr.eausr' => 0.3, - '_sampling_priority_v1' => 1, - 'process_id' => getmypid(), - ])->withChildren([ - SpanAssertion::exists('symfony.kernel.terminate'), - SpanAssertion::exists('symfony.httpkernel.kernel.handle')->withChildren([ - SpanAssertion::exists('symfony.httpkernel.kernel.boot'), - SpanAssertion::exists('symfony.kernel.handle')->withChildren([ - SpanAssertion::exists('symfony.kernel.request'), - SpanAssertion::exists('symfony.kernel.controller'), - SpanAssertion::exists('symfony.kernel.controller_arguments'), - SpanAssertion::build( - 'symfony.controller', - 'symfony', - 'web', - 'App\Controller\CommonScenariosController::simpleAction' - )->withExactTags([ - Tag::COMPONENT => 'symfony', - '_dd.svc_src' => 'symfony', - ]), - SpanAssertion::exists('symfony.kernel.response')->withChildren([ - SpanAssertion::exists('symfony.security.authentication.success') - ]), - SpanAssertion::exists('symfony.kernel.finish_request'), - ]), - ]), - ]), - ] - ); - } -} diff --git a/tests/Integrations/Symfony/V5_2/TraceSearchConfigTest.php b/tests/Integrations/Symfony/V5_2/TraceSearchConfigTest.php deleted file mode 100644 index 1a622ae42b..0000000000 --- a/tests/Integrations/Symfony/V5_2/TraceSearchConfigTest.php +++ /dev/null @@ -1,81 +0,0 @@ - 'true', - 'DD_SYMFONY_ANALYTICS_SAMPLE_RATE' => '0.3', - ]); - } - - /** - * @throws \Exception - */ - public function testScenario() - { - $traces = $this->tracesFromWebRequest(function () { - $this->call(GetSpec::create('Testing trace analytics config metric', '/simple')); - }); - - $this->assertFlameGraph( - $traces, - [ - SpanAssertion::build( - 'symfony.request', - 'symfony', - 'web', - 'simple' - )->withExactTags([ - 'symfony.route.action' => 'App\Controller\CommonScenariosController@simpleAction', - 'symfony.route.name' => 'simple', - 'http.route' => '/simple', - 'http.method' => 'GET', - 'http.url' => 'http://localhost/simple', - 'http.status_code' => '200', - Tag::SPAN_KIND => 'server', - Tag::COMPONENT => 'symfony', - '_dd.svc_src' => 'symfony', - ])->withExactMetrics([ - '_dd1.sr.eausr' => 0.3, - '_sampling_priority_v1' => 1, - 'process_id' => getmypid(), - ])->withChildren([ - SpanAssertion::exists('symfony.kernel.terminate'), - SpanAssertion::exists('symfony.httpkernel.kernel.handle')->withChildren([ - SpanAssertion::exists('symfony.httpkernel.kernel.boot'), - SpanAssertion::exists('symfony.kernel.handle')->withChildren([ - SpanAssertion::exists('symfony.kernel.request'), - SpanAssertion::exists('symfony.kernel.controller'), - SpanAssertion::exists('symfony.kernel.controller_arguments'), - SpanAssertion::build( - 'symfony.controller', - 'symfony', - 'web', - 'App\Controller\CommonScenariosController::simpleAction' - )->withExactTags([ - Tag::COMPONENT => 'symfony', - '_dd.svc_src' => 'symfony', - ]), - SpanAssertion::exists('symfony.kernel.response'), - SpanAssertion::exists('symfony.kernel.finish_request'), - ]), - ]), - ]), - ] - ); - } -} diff --git a/tests/Integrations/Symfony/V6_2/TraceSearchConfigTest.php b/tests/Integrations/Symfony/V6_2/TraceSearchConfigTest.php deleted file mode 100644 index aaf2f4acc8..0000000000 --- a/tests/Integrations/Symfony/V6_2/TraceSearchConfigTest.php +++ /dev/null @@ -1,81 +0,0 @@ - 'true', - 'DD_SYMFONY_ANALYTICS_SAMPLE_RATE' => '0.3', - ]); - } - - /** - * @throws \Exception - */ - public function testScenario() - { - $traces = $this->tracesFromWebRequest(function () { - $this->call(GetSpec::create('Testing trace analytics config metric', '/simple')); - }); - - $this->assertFlameGraph( - $traces, - [ - SpanAssertion::build( - 'symfony.request', - 'symfony', - 'web', - 'simple' - )->withExactTags([ - 'symfony.route.action' => 'App\Controller\CommonScenariosController@simpleAction', - 'symfony.route.name' => 'simple', - 'http.route' => '/simple', - 'http.method' => 'GET', - 'http.url' => 'http://localhost/simple', - 'http.status_code' => '200', - Tag::SPAN_KIND => 'server', - Tag::COMPONENT => 'symfony', - '_dd.svc_src' => 'symfony', - ])->withExactMetrics([ - '_dd1.sr.eausr' => 0.3, - '_sampling_priority_v1' => 1, - 'process_id' => getmypid(), - ])->withChildren([ - SpanAssertion::exists('symfony.kernel.terminate'), - SpanAssertion::exists('symfony.httpkernel.kernel.handle')->withChildren([ - SpanAssertion::exists('symfony.httpkernel.kernel.boot'), - SpanAssertion::exists('symfony.kernel.handle')->withChildren([ - SpanAssertion::exists('symfony.kernel.request'), - SpanAssertion::exists('symfony.kernel.controller'), - SpanAssertion::exists('symfony.kernel.controller_arguments'), - SpanAssertion::build( - 'symfony.controller', - 'symfony', - 'web', - 'App\Controller\CommonScenariosController::simpleAction' - )->withExactTags([ - Tag::COMPONENT => 'symfony', - '_dd.svc_src' => 'symfony', - ]), - SpanAssertion::exists('symfony.kernel.response'), - SpanAssertion::exists('symfony.kernel.finish_request'), - ]), - ]), - ]), - ] - ); - } -} diff --git a/tests/Integrations/Symfony/V7_3/TraceSearchConfigTest.php b/tests/Integrations/Symfony/V7_3/TraceSearchConfigTest.php deleted file mode 100644 index 369f46a587..0000000000 --- a/tests/Integrations/Symfony/V7_3/TraceSearchConfigTest.php +++ /dev/null @@ -1,11 +0,0 @@ - 'true', - 'DD_ZENDFRAMEWORK_ANALYTICS_SAMPLE_RATE' => '0.3', - ]); - } - - /** - * @throws \Exception - */ - public function testScenario() - { - $traces = $this->tracesFromWebRequest(function () { - $this->call(GetSpec::create('Testing trace analytics config metric', '/simple')); - }); - - $this->assertExpectedSpans( - $traces, - [ - SpanAssertion::build('zf1.request', 'zf1', 'web', 'simple@index default') - ->withExactTags([ - 'zf1.controller' => 'simple', - 'zf1.action' => 'index', - 'zf1.route_name' => 'default', - 'http.method' => 'GET', - 'http.url' => 'http://localhost/simple', - 'http.status_code' => '200', - Tag::SPAN_KIND => 'server', - Tag::COMPONENT => 'zendframework', - '_dd.svc_src' => 'zf1', - ]) - ->withExactMetrics([ - '_dd1.sr.eausr' => 0.3, - '_sampling_priority_v1' => 1, - 'process_id' => getmypid(), - ]), - ] - ); - } -} diff --git a/tests/Integrations/ZendFramework/V1_21/TraceSearchConfigTest.php b/tests/Integrations/ZendFramework/V1_21/TraceSearchConfigTest.php deleted file mode 100644 index d2dc2c12f0..0000000000 --- a/tests/Integrations/ZendFramework/V1_21/TraceSearchConfigTest.php +++ /dev/null @@ -1,57 +0,0 @@ - 'true', - 'DD_ZENDFRAMEWORK_ANALYTICS_SAMPLE_RATE' => '0.3', - ]); - } - - /** - * @throws \Exception - */ - public function testScenario() - { - $traces = $this->tracesFromWebRequest(function () { - $this->call(GetSpec::create('Testing trace analytics config metric', '/simple')); - }); - - $this->assertExpectedSpans( - $traces, - [ - SpanAssertion::build('zf1.request', 'zf1', 'web', 'simple@index default') - ->withExactTags([ - 'zf1.controller' => 'simple', - 'zf1.action' => 'index', - 'zf1.route_name' => 'default', - 'http.method' => 'GET', - 'http.url' => 'http://localhost/simple', - 'http.status_code' => '200', - Tag::SPAN_KIND => 'server', - Tag::COMPONENT => 'zendframework', - '_dd.svc_src' => 'zf1', - ]) - ->withExactMetrics([ - '_dd1.sr.eausr' => 0.3, - '_sampling_priority_v1' => 1, - 'process_id' => getmypid(), - ]), - ] - ); - } -} diff --git a/tests/OpenTelemetry/Integration/API/BaggageTest.php b/tests/OpenTelemetry/Integration/API/BaggageTest.php index 3ac84f0706..7e1dc5bb87 100644 --- a/tests/OpenTelemetry/Integration/API/BaggageTest.php +++ b/tests/OpenTelemetry/Integration/API/BaggageTest.php @@ -93,10 +93,10 @@ public function testSpansAndBaggage() }); list($parent, $child) = $traces[0]; - $this->assertSame(Tag::SPAN_KIND_VALUE_SERVER, $parent['meta'][Tag::SPAN_KIND]); - $this->assertSame('GET', $parent['meta']['http.method']); - $this->assertSame('/parent', $parent['meta']['http.uri']); - $this->assertSame('1', $child['meta']['user.id']); + $this->assertSame(2, $parent['span_kind']); // span_kind enum: Server=2 + $this->assertSame('GET', $parent['attributes']['http.method']); + $this->assertSame('/parent', $parent['attributes']['http.uri']); + $this->assertSame('1', $child['attributes']['user.id']); $this->assertFlameGraph($traces, [ SpanAssertion::exists('server.request', 'parent', false, (PHP_VERSION_ID < 80100) ? 'datadog/dd-trace-tests' : 'unknown_service:php') diff --git a/tests/OpenTelemetry/Integration/API/TracerTest.php b/tests/OpenTelemetry/Integration/API/TracerTest.php index fcb598201b..b56a7bc76f 100644 --- a/tests/OpenTelemetry/Integration/API/TracerTest.php +++ b/tests/OpenTelemetry/Integration/API/TracerTest.php @@ -65,7 +65,7 @@ public function testOtelSetSpanStatusError() $errorSpan->end(); }); - $this->assertSame('error_desc', $traces[0][0]['meta']['error.message']); + $this->assertSame('error_desc', $traces[0][0]['attributes']['error.message']); } public function testUnorderedOtelSpanActivation() @@ -111,7 +111,7 @@ public function testManuallyCreatedSpanWithNoCustomTags() $this->assertNotEquals(0, $span['duration']); $this->assertSame('internal', $span['name']); $this->assertSame('test.span', $span['resource']); - $this->assertEquals(PrioritySampling::AUTO_KEEP, $span['metrics']["_sampling_priority_v1"]); + $this->assertEquals(PrioritySampling::AUTO_KEEP, $span['sampling_priority']); } public function testManuallyCreatedSpanWithCustomTags() @@ -133,9 +133,9 @@ public function testManuallyCreatedSpanWithCustomTags() $this->assertNotEquals(0, $span['duration']); $this->assertSame('internal', $span['name']); $this->assertSame('test.span', $span['resource']); - $this->assertEquals(PrioritySampling::AUTO_KEEP, $span['metrics']["_sampling_priority_v1"]); - $this->assertSame('bar', $span['meta']['foo']); - $this->assertSame('baz', $span['meta']['bar']); + $this->assertEquals(PrioritySampling::AUTO_KEEP, $span['sampling_priority']); + $this->assertSame('bar', $span['attributes']['foo']); + $this->assertSame('baz', $span['attributes']['bar']); } public function testManuallyCreatedSpanWithNestedAttributes() @@ -157,12 +157,12 @@ public function testManuallyCreatedSpanWithNestedAttributes() $this->assertNotEquals(0, $span['duration']); $this->assertSame('internal', $span['name']); $this->assertSame('test.span', $span['resource']); - $this->assertEquals(PrioritySampling::AUTO_KEEP, $span['metrics']["_sampling_priority_v1"]); - $this->assertSame('bar', $span['meta']['foo']); - $this->assertSame('baz', $span['meta']['bar']); - $this->assertSame('bar', $span['meta']['nested.foo']); - $this->assertSame('baz', $span['meta']['nested.bar']); - $this->assertSame('alone', $span['meta']['nested.0']); + $this->assertEquals(PrioritySampling::AUTO_KEEP, $span['sampling_priority']); + $this->assertSame('bar', $span['attributes']['foo']); + $this->assertSame('baz', $span['attributes']['bar']); + $this->assertSame('bar', $span['attributes']['nested']['foo']); + $this->assertSame('baz', $span['attributes']['nested']['bar']); + $this->assertSame('alone', $span['attributes']['nested'][0]); } public function testManuallyCreatedNestedSpansBasic() @@ -228,7 +228,7 @@ public function testCreateSpanInvalidParent() $this->assertNotEmpty($span['trace_id']); $this->assertSame($span['trace_id'], $span['span_id']); $this->assertArrayNotHasKey('parent_id', $span); - $this->assertEquals(PrioritySampling::AUTO_KEEP, $span['metrics']["_sampling_priority_v1"]); + $this->assertEquals(PrioritySampling::AUTO_KEEP, $span['sampling_priority']); } public function testCreateANewTraceInTheSameProcess() @@ -290,22 +290,21 @@ public function testSpanAttributes() $span->end(); }); - $meta = $traces[0][0]['meta']; - $metrics = $traces[0][0]['metrics']; - $this->assertSame("a", $meta['string']); - $this->assertArrayNotHasKey("null-string", $meta); - $this->assertSame("", $meta['empty_string']); - $this->assertEquals(1, $metrics['number']); - $this->assertSame("true", $meta['boolean']); - $this->assertSame("a", $meta['string-array.0']); - $this->assertSame("b", $meta['string-array.1']); - $this->assertSame("c", $meta['string-array.2']); - $this->assertSame("true", $meta['boolean-array.0']); - $this->assertSame("false", $meta['boolean-array.1']); - $this->assertEquals("1.1", $metrics['float-array.0']); - $this->assertEquals("2.2", $metrics['float-array.1']); - $this->assertEquals("3.3", $metrics['float-array.2']); - $this->assertSame("", $meta['empty-array']); + $attributes = $traces[0][0]['attributes']; + $this->assertSame("a", $attributes['string']); + $this->assertArrayNotHasKey("null-string", $attributes); + $this->assertSame("", $attributes['empty_string']); + $this->assertEquals(1, $attributes['number']); + $this->assertTrue($attributes['boolean']); + $this->assertSame("a", $attributes['string-array'][0]); + $this->assertSame("b", $attributes['string-array'][1]); + $this->assertSame("c", $attributes['string-array'][2]); + $this->assertTrue($attributes['boolean-array'][0]); + $this->assertFalse($attributes['boolean-array'][1]); + $this->assertEquals("1.1", $attributes['float-array'][0]); + $this->assertEquals("2.2", $attributes['float-array'][1]); + $this->assertEquals("3.3", $attributes['float-array'][2]); + $this->assertSame("", $attributes['empty-array']); } /** @@ -322,17 +321,18 @@ public function testSpanKind($otelSpanKind, $tagSpanKind) }); $span = $traces[0][0]; - $this->assertSame($tagSpanKind, $span['meta']['span.kind']); + $this->assertSame($tagSpanKind, $span['span_kind']); } public function providerSpanKind() { + // V1 introspection promotes span.kind to the int enum: Internal=1,Server=2,Client=3,Producer=4,Consumer=5 return [ - [SpanKind::KIND_CLIENT, Tag::SPAN_KIND_VALUE_CLIENT], - [SpanKind::KIND_SERVER, Tag::SPAN_KIND_VALUE_SERVER], - [SpanKind::KIND_PRODUCER, Tag::SPAN_KIND_VALUE_PRODUCER], - [SpanKind::KIND_CONSUMER, Tag::SPAN_KIND_VALUE_CONSUMER], - [SpanKind::KIND_INTERNAL, Tag::SPAN_KIND_VALUE_INTERNAL], + [SpanKind::KIND_CLIENT, 3], + [SpanKind::KIND_SERVER, 2], + [SpanKind::KIND_PRODUCER, 4], + [SpanKind::KIND_CONSUMER, 5], + [SpanKind::KIND_INTERNAL, 1], ]; } @@ -375,10 +375,10 @@ public function testReservedAttributesOverridesAnalyticsEvent($analyticsEventVal $span = $traces[0][0]; if ($expectedMetricValue !== null) { - $actualMetricValue = $span['metrics']['_dd1.sr.eausr']; + $actualMetricValue = $span['attributes']['_dd1.sr.eausr']; $this->assertEquals($expectedMetricValue, $actualMetricValue); } else { - $this->assertArrayNotHasKey('_dd1.sr.eausr', $span['metrics']); + $this->assertArrayNotHasKey('_dd1.sr.eausr', $span['attributes']); } } @@ -394,7 +394,7 @@ public function testSpanErrorStatus() $span = $traces[0][0]; $this->assertSame('internal', $span['name']); $this->assertSame('test.span', $span['resource']); - $this->assertSame('error message', $span['meta']['error.message']); + $this->assertSame('error message', $span['attributes']['error.message']); $this->assertEquals(1, $span['error']); } @@ -416,7 +416,7 @@ public function testSpanStatusTransition() $span = $traces[0][0]; $this->assertArrayNotHasKey("error", $span); - $this->assertArrayNotHasKey("error.message", $span['meta']); + $this->assertArrayNotHasKey("error.message", $span['attributes']); $this->assertSame("internal", $span['name']); $this->assertSame("test.span", $span['resource']); } @@ -433,7 +433,7 @@ public function testRecordException() $span = $traces[0][0]; $this->assertSame('internal', $span['name']); $this->assertSame('test.span', $span['resource']); - $this->assertNotEmpty($span['meta'][Tag::ERROR_STACK]); + $this->assertNotEmpty($span['attributes'][Tag::ERROR_STACK]); } public function testSpanNameUpdate() @@ -469,9 +469,9 @@ public function testSpanUpdateAfterEnd() $span = $traces[0][0]; $this->assertSame('internal', $span['name']); $this->assertSame('test.span', $span['resource']); - $this->assertSame('error message', $span['meta']['error.message']); + $this->assertSame('error message', $span['attributes']['error.message']); $this->assertEquals(1, $span['error']); - $this->assertSame('bar', $span['meta']['foo']); + $this->assertSame('bar', $span['attributes']['foo']); } public function testConcurrentSpans() @@ -522,10 +522,10 @@ public function testConcurrentSpans() $this->assertSame($rootSpan['span_id'], $httpSpan['parent_id']); $this->assertSame("http-$i", $httpSpan['resource']); - $this->assertSame("GET", $httpSpan['meta']['http.method']); - $this->assertSame("example.com/$i", $httpSpan['meta']['http.url']); - $this->assertSame('200', $httpSpan['meta']['http.status_code']); - $this->assertSame('1024', $httpSpan['meta']['http.response_content_length']); + $this->assertSame("GET", $httpSpan['attributes']['http.method']); + $this->assertSame("example.com/$i", $httpSpan['attributes']['http.url']); + $this->assertSame('200', $httpSpan['attributes']['http.status_code']); + $this->assertSame('1024', $httpSpan['attributes']['http.response_content_length']); } } @@ -544,8 +544,8 @@ public function testGetSpanContextWithMultipleTraceStates() }); $span = $traces[0][0]; - $this->assertSame('t61rcWkgMzE', $span['meta']['_dd.p.congo']); - $this->assertSame('tehehe', $span['meta']['_dd.p.some_val']); + $this->assertSame('t61rcWkgMzE', $span['attributes']['_dd.p.congo']); + $this->assertSame('tehehe', $span['attributes']['_dd.p.some_val']); } /** @@ -589,7 +589,7 @@ public function testGetSpanContextWithRemoteParent(int $traceFlags, ?TraceState $span = $traces[0][0]; $this->assertSame($low, $span['trace_id']); - $this->assertSame($high, $span['meta']['_dd.p.tid']); + $this->assertSame($high, $span['trace_id_high']); $this->assertSame($decSpanId, $span['parent_id']); } @@ -834,7 +834,7 @@ public function getDescription(): string $spans = $traces[0]; list($childSpan) = $spans; $this->assertSame("11803532876627986230", $childSpan['trace_id']); - $this->assertSame("4bf92f3577b34da6", $childSpan['meta']['_dd.p.tid']); + $this->assertSame("4bf92f3577b34da6", $childSpan['trace_id_high']); $this->assertSame("67667974448284343", $childSpan['parent_id']); } @@ -874,10 +874,10 @@ public function testAddItemToTracestate() $span = $traces[0]; list($childSpan, $span) = $span; - $this->assertSame('t61rcWkgMzE', $span['meta']['_dd.p.congo']); - $this->assertSame('t61rcWkgMzE', $childSpan['meta']['_dd.p.congo']); - $this->assertSame('-0', $span['meta']['_dd.p.dm']); - $this->assertSame('-0', $childSpan['meta']['_dd.p.dm']); + $this->assertSame('t61rcWkgMzE', $span['attributes']['_dd.p.congo']); + $this->assertSame('t61rcWkgMzE', $childSpan['attributes']['_dd.p.congo']); + $this->assertSame(0, $span['sampling_mechanism']); // _dd.p.dm '-0' promotes to sampling_mechanism=0 + $this->assertSame(0, $childSpan['sampling_mechanism']); $this->assertFlameGraph($traces, [ SpanAssertion::exists('internal', 'test.span') diff --git a/tests/OpenTelemetry/Integration/InteroperabilityTest.php b/tests/OpenTelemetry/Integration/InteroperabilityTest.php index 96d4d6e3ab..58a16797a0 100644 --- a/tests/OpenTelemetry/Integration/InteroperabilityTest.php +++ b/tests/OpenTelemetry/Integration/InteroperabilityTest.php @@ -120,7 +120,7 @@ public function testActivateAnAlreadyActiveDatadogSpan() $span = $traces[0][0]; $this->assertSame('dd.span', $span['name']); - $this->assertArrayNotHasKey('parent_id', $span['meta']); + $this->assertArrayNotHasKey('parent_id', $span['attributes']); } /** @noinspection PhpParamsInspection */ @@ -175,8 +175,8 @@ public function testMixingOpenTelemetrylAndDatadogBasic() $this->assertSame('other.span', $child['resource']); $this->assertSame($parent['span_id'], $child['parent_id']); $this->assertSame($parent['trace_id'], $child['trace_id']); - $this->assertSame('bar', $child['meta']['foo']); - $this->assertArrayNotHasKey('foo', $parent['meta']); + $this->assertSame('bar', $child['attributes']['foo']); + $this->assertArrayNotHasKey('foo', $parent['attributes']); } public function testActivateSpanWithAnotherActiveNonActivatedDatadogSpan() @@ -733,7 +733,7 @@ public function testW3CInteroperability() $this->assertSame('18374692078461386817', $traces[0][0]['parent_id']); $otelRootSpan = $traces[0][0]; - $this->assertSame('ff00000000000517', $otelRootSpan['meta']['_dd.p.tid']); + $this->assertSame('ff00000000000517', $otelRootSpan['trace_id_high']); $this->assertFlameGraph($traces, [ SpanAssertion::exists('internal', 'otel.root.span', false, 'phpunit') @@ -785,7 +785,7 @@ public function testB3SingleInteroperability() $this->assertSame('18374692078461386817', $traces[0][0]['parent_id']); $otelRootSpan = $traces[0][0]; - $this->assertSame('ff00000000000517', $otelRootSpan['meta']['_dd.p.tid']); + $this->assertSame('ff00000000000517', $otelRootSpan['trace_id_high']); $this->assertFlameGraph($traces, [ SpanAssertion::exists('internal', 'otel.root.span', false, 'phpunit') @@ -841,7 +841,7 @@ public function testB3MultiInteroperability() $this->assertSame('18374692078461386817', $traces[0][0]['parent_id']); $otelRootSpan = $traces[0][0]; - $this->assertSame('ff00000000000517', $otelRootSpan['meta']['_dd.p.tid']); + $this->assertSame('ff00000000000517', $otelRootSpan['trace_id_high']); $this->assertFlameGraph($traces, [ SpanAssertion::exists('internal', 'otel.root.span', false, 'phpunit') @@ -882,10 +882,10 @@ public function testBaggageInteroperability() }); list($parent, $child) = $traces[0]; - $this->assertSame(Tag::SPAN_KIND_VALUE_SERVER, $parent['meta'][Tag::SPAN_KIND]); - $this->assertSame('GET', $parent['meta']['http.method']); - $this->assertSame('/parent', $parent['meta']['http.uri']); - $this->assertSame('1', $child['meta']['user.id']); + $this->assertSame(2, $parent['span_kind']); // span_kind enum: Server=2 + $this->assertSame('GET', $parent['attributes']['http.method']); + $this->assertSame('/parent', $parent['attributes']['http.uri']); + $this->assertSame('1', $child['attributes']['user.id']); $this->assertFlameGraph($traces, [ SpanAssertion::exists('server.request', 'parent', false, (PHP_VERSION_ID < 80100) ? 'datadog/dd-trace-tests' : 'unknown_service:php') @@ -920,7 +920,7 @@ public function testSpecialAttributes() $this->assertSame('new.name', $span['resource']); $this->assertSame('new.service.name', $span['service']); $this->assertSame('new.span.type', $span['type']); - $this->assertEquals(1.0, $span['metrics']['_dd1.sr.eausr']); + $this->assertEquals(1.0, $span['attributes']['_dd1.sr.eausr']); } public function testHasEnded() @@ -976,7 +976,7 @@ public function testAttributesInteroperability() $this->assertCount(1, $traces[0]); - $meta = $traces[0][0]['meta']; + $meta = $traces[0][0]['attributes']; $this->assertArrayNotHasKey('arg1', $meta); $this->assertSame('value2', $meta['arg2']); $this->assertSame('value3', $meta['arg3']); @@ -986,8 +986,8 @@ public function testAttributesInteroperability() $this->assertSame('value', $meta['key']); $this->assertArrayNotHasKey('post', $meta); - $this->assertEquals(1, $traces[0][0]['metrics']['m1']); - $this->assertEquals(2, $traces[0][0]['metrics']['m2']); + $this->assertEquals(1, $traces[0][0]['attributes']['m1']); + $this->assertEquals(2, $traces[0][0]['attributes']['m2']); } public function testSpanLinksInteroperabilityFromDatadogSpan() @@ -1024,7 +1024,14 @@ public function testSpanLinksInteroperabilityFromDatadogSpan() }); $this->assertCount(1, $traces[0]); - $this->assertSame("[{\"trace_id\":\"ff0000000000051791e0000000000041\",\"span_id\":\"ff00000000000517\",\"trace_state\":\"dd=t.dm:-0\",\"attributes\":{\"arg1\":\"value1\",\"arg2\":\"value2\"}}]", $traces[0][0]['meta']['_dd.span_links']); + $this->assertSame([[ + 'trace_id' => '10511401530282737729', + 'trace_id_high' => 'ff00000000000517', + 'span_id' => '18374686479671624983', + 'trace_state' => 'dd=t.dm:-0', + 'flags' => 0, + 'attributes' => ['arg1' => 'value1', 'arg2' => 'value2'], + ]], $traces[0][0]['span_links']); } public function testBasicSpanLinksFromDatadog() @@ -1050,7 +1057,12 @@ public function testBasicSpanLinksFromDatadog() }); $this->assertCount(1, $traces[0]); - $this->assertSame("[{\"trace_id\":\"ff0000000000051791e0000000000041\",\"span_id\":\"ff00000000000517\"}]", $traces[0][0]['meta']['_dd.span_links']); + $this->assertSame([[ + 'trace_id' => '10511401530282737729', + 'trace_id_high' => 'ff00000000000517', + 'span_id' => '18374686479671624983', + 'flags' => 0, + ]], $traces[0][0]['span_links']); } public function testSpanLinksInteroperabilityFromOpenTelemetrySpan() @@ -1079,7 +1091,15 @@ public function testSpanLinksInteroperabilityFromOpenTelemetrySpan() }); $this->assertCount(1, $traces[0]); - $this->assertSame("[{\"trace_id\":\"12345678876543211234567887654321\",\"span_id\":\"8765432112345678\",\"trace_state\":\"dd=t.dm:-0\",\"attributes\":{\"arg1\":\"value1\"},\"dropped_attributes_count\":0}]", $traces[0][0]['meta']['_dd.span_links']); + // dropped_attributes_count is not surfaced in the V1 structured span_links (no PHP-side source). + $this->assertSame([[ + 'trace_id' => '1311768467139281697', + 'trace_id_high' => '1234567887654321', + 'span_id' => '9756277977086449272', + 'trace_state' => 'dd=t.dm:-0', + 'flags' => 0, + 'attributes' => ['arg1' => 'value1'], + ]], $traces[0][0]['span_links']); } public function testSpanLinksInteroperabilityBothTypes() @@ -1134,7 +1154,22 @@ public function testSpanLinksInteroperabilityBothTypes() }); $this->assertCount(1, $traces[0]); - $this->assertSame("[{\"trace_id\":\"12345678876543211234567887654321\",\"span_id\":\"8765432112345678\",\"trace_state\":\"dd=t.dm:-0\",\"attributes\":{\"arg1\":\"value1\"},\"dropped_attributes_count\":0},{\"trace_id\":\"ff0000000000051791e0000000000041\",\"span_id\":\"ff00000000000517\"}]", $traces[0][0]['meta']['_dd.span_links']); + $this->assertSame([ + [ + 'trace_id' => '1311768467139281697', + 'trace_id_high' => '1234567887654321', + 'span_id' => '9756277977086449272', + 'trace_state' => 'dd=t.dm:-0', + 'flags' => 0, + 'attributes' => ['arg1' => 'value1'], + ], + [ + 'trace_id' => '10511401530282737729', + 'trace_id_high' => 'ff00000000000517', + 'span_id' => '18374686479671624983', + 'flags' => 0, + ], + ], $traces[0][0]['span_links']); } public function testSpanLinksInteroperabilityRemoval() @@ -1294,7 +1329,15 @@ public function testSpanEventsInteroperabilityFromDatadogSpan() }); $this->assertCount(1, $traces[0]); - $this->assertSame("[{\"name\":\"event-name\",\"time_unix_nano\":1720037568765201300,\"attributes\":{\"arg1\":\"value1\",\"int_array\":[3,4],\"string_array\":[\"5\",\"6\"]}}]", $traces[0][0]['meta']['events']); + $this->assertSame([[ + 'name' => 'event-name', + 'time_unix_nano' => 1720037568765201300, + 'attributes' => [ + 'arg1' => 'value1', + 'int_array' => [3, 4], + 'string_array' => ['5', '6'], + ], + ]], $traces[0][0]['span_events']); } public function testSpanEventsInteroperabilityFromOpenTelemetrySpan() @@ -1326,7 +1369,15 @@ public function testSpanEventsInteroperabilityFromOpenTelemetrySpan() }); $this->assertCount(1, $traces[0]); - $this->assertSame("[{\"name\":\"event-name\",\"time_unix_nano\":1720037568765201300,\"attributes\":{\"arg1\":\"value1\",\"int_array\":[3,4],\"string_array\":[\"5\",\"6\"]}}]", $traces[0][0]['meta']['events']); + $this->assertSame([[ + 'name' => 'event-name', + 'time_unix_nano' => 1720037568765201300, + 'attributes' => [ + 'arg1' => 'value1', + 'int_array' => [3, 4], + 'string_array' => ['5', '6'], + ], + ]], $traces[0][0]['span_events']); } public function testOtelRecordExceptionAttributesSerialization() @@ -1347,7 +1398,7 @@ public function testOtelRecordExceptionAttributesSerialization() $otelSpan->end(); }); - $events = json_decode($traces[0][0]['meta']['events'], true); + $events = $traces[0][0]['span_events']; $this->assertCount(3, $events); $event1 = $events[0]; @@ -1361,10 +1412,10 @@ public function testOtelRecordExceptionAttributesSerialization() $event3 = $events[2]; $this->assertSame('message override', $event3['attributes']['exception.message']); - $this->assertSame(\DDTrace\get_sanitized_exception_trace($lastException), $traces[0][0]['meta']['error.stack']); + $this->assertSame(\DDTrace\get_sanitized_exception_trace($lastException), $traces[0][0]['attributes']['error.stack']); - $this->assertArrayNotHasKey('error.message', $traces[0][0]['meta']); - $this->assertArrayNotHasKey('error.type', $traces[0][0]['meta']); + $this->assertArrayNotHasKey('error.message', $traces[0][0]['attributes']); + $this->assertArrayNotHasKey('error.type', $traces[0][0]['attributes']); $this->assertArrayNotHasKey('error', $traces[0][0]); } @@ -1398,7 +1449,7 @@ public function testExceptionSpanEvents() close_span(); }); - $event = json_decode($traces[0][0]['meta']['events'], true)[0]; + $event = $traces[0][0]['span_events'][0]; $this->assertSame('Test exception message', $event['attributes']['exception.message']); $this->assertSame('Exception', $event['attributes']['exception.type']); diff --git a/tests/OpenTelemetry/Integration/SpanProvenanceTest.php b/tests/OpenTelemetry/Integration/SpanProvenanceTest.php index 3c91add91a..7ed3e6ff13 100644 --- a/tests/OpenTelemetry/Integration/SpanProvenanceTest.php +++ b/tests/OpenTelemetry/Integration/SpanProvenanceTest.php @@ -28,6 +28,6 @@ function testOtelSpanMarked() }); $this->assertEquals($traces[0][0]["resource"], "file_get_contents"); $this->assertEquals($traces[0][0]["name"], "internal"); - $this->assertEquals($traces[0][0]["meta"]["component"], "otel.io"); + $this->assertEquals($traces[0][0]["component"], "otel.io"); } } diff --git a/tests/Unit/ConfigurationTest.php b/tests/Unit/ConfigurationTest.php index f3129e5087..520dddcbf0 100644 --- a/tests/Unit/ConfigurationTest.php +++ b/tests/Unit/ConfigurationTest.php @@ -117,47 +117,6 @@ public function testAllIntegrationsEnabledToggleConfig() self::assertTrue(\ddtrace_config_integration_enabled('foo_invalid')); } - public function testAllIntegrationsAnalyticsEnabledToggleConfig() - { - $integrations = self::getIntegrationsUpper(); - foreach ($integrations as $integration) { - $this->putEnvAndReloadConfig(["DD_TRACE_{$integration}_ANALYTICS_ENABLED=true"]); - - $lower = strtolower($integration); - self::assertTrue( - \DDTrace\Config\integration_analytics_enabled($lower), - "App analytics for '{$lower}' was expected to be enabled." . self::INTEGRATION_ERROR - ); - - // Reset - self::putenv("DD_TRACE_{$integration}_ANALYTICS_ENABLED"); - } - - // Make sure we're not testing the default fallback - self::assertFalse(\DDTrace\Config\integration_analytics_enabled('foo_invalid')); - } - - public function testAllIntegrationsAnalyticsSampleRateConfig() - { - $integrations = self::getIntegrationsUpper(); - foreach ($integrations as $integration) { - $this->putEnvAndReloadConfig(["DD_TRACE_{$integration}_ANALYTICS_SAMPLE_RATE=0.42"]); - - $lower = strtolower($integration); - self::assertSame( - 0.42, - \DDTrace\Config\integration_analytics_sample_rate($lower), - "Invalid app analytics sample rate for '{$lower}'." . self::INTEGRATION_ERROR - ); - - // Reset - self::putenv("DD_TRACE_{$integration}_ANALYTICS_SAMPLE_RATE"); - } - - // Make sure we're not testing the default fallback - self::assertSame(\DDTrace\Config\integration_analytics_sample_rate('foo_invalid'), 1.0); - } - private static function getIntegrationsUpper() { $dirs = glob(__DIR__ . '/../../src/DDTrace/Integrations/*', GLOB_ONLYDIR); diff --git a/tests/Unit/Processing/TraceAnalyticsProcessorTest.php b/tests/Unit/Processing/TraceAnalyticsProcessorTest.php index 1b8fd98cbc..57d6f89850 100644 --- a/tests/Unit/Processing/TraceAnalyticsProcessorTest.php +++ b/tests/Unit/Processing/TraceAnalyticsProcessorTest.php @@ -8,42 +8,35 @@ final class TraceAnalyticsProcessorTest extends BaseTestCase { - public function testTrueIs1() + public function testTrueIsNoOp() { - $metrics = [ - ]; + $metrics = []; TraceAnalyticsProcessor::normalizeAnalyticsValue($metrics, true); - $this->assertSame(1.0, $metrics[Tag::ANALYTICS_KEY]); + $this->assertArrayNotHasKey(Tag::ANALYTICS_KEY, $metrics); } - public function testFalseIsUnset() + public function testFalseIsNoOp() { $metrics = [ Tag::ANALYTICS_KEY => 0.2, ]; TraceAnalyticsProcessor::normalizeAnalyticsValue($metrics, false); - $this->assertArrayNotHasKey(Tag::ANALYTICS_KEY, $metrics); + $this->assertSame(0.2, $metrics[Tag::ANALYTICS_KEY]); } - public function testNumericValueBetweenZeroAndOne() - { - $metrics = [ - ]; - TraceAnalyticsProcessor::normalizeAnalyticsValue($metrics, 0.4); - $this->assertSame(0.4, $metrics[Tag::ANALYTICS_KEY]); - } - - public function testValueLessThan0() + public function testNumericValueIsNoOp() { $metrics = []; - TraceAnalyticsProcessor::normalizeAnalyticsValue($metrics, -0.1); + TraceAnalyticsProcessor::normalizeAnalyticsValue($metrics, 0.4); $this->assertArrayNotHasKey(Tag::ANALYTICS_KEY, $metrics); } - public function testValueGreaterThan1() + public function testDoesNotMutateExistingMetrics() { - $metrics = []; + $metrics = ['foo' => 1.0]; + TraceAnalyticsProcessor::normalizeAnalyticsValue($metrics, true); + TraceAnalyticsProcessor::normalizeAnalyticsValue($metrics, -0.1); TraceAnalyticsProcessor::normalizeAnalyticsValue($metrics, 1.1); - $this->assertArrayNotHasKey(Tag::ANALYTICS_KEY, $metrics); + $this->assertSame(['foo' => 1.0], $metrics); } } diff --git a/tests/Unit/SpanTest.php b/tests/Unit/SpanTest.php index f06e8902e6..d874b5c049 100644 --- a/tests/Unit/SpanTest.php +++ b/tests/Unit/SpanTest.php @@ -273,45 +273,45 @@ public function testMetricsSetGet() $this->assertSame(1.0, $span->getMetrics()['exists']); } - public function testTraceAnalyticsConfigEnabledByTag() + public function testTraceAnalyticsByTagIsDeprecatedNoOp() { $span = $this->createSpan(); $span->setTag(Tag::ANALYTICS_KEY, 0.5); - $this->assertSame(0.5, $span->getMetrics()[Tag::ANALYTICS_KEY]); + $this->assertArrayNotHasKey(Tag::ANALYTICS_KEY, $span->getMetrics()); } - public function testTraceAnalyticsConfigEnabledByMetric() + public function testTraceAnalyticsByMetricIsDeprecatedNoOp() { $span = $this->createSpan(); $span->setMetric(Tag::ANALYTICS_KEY, 0.5); - $this->assertSame(0.5, $span->getMetrics()[Tag::ANALYTICS_KEY]); + $this->assertArrayNotHasKey(Tag::ANALYTICS_KEY, $span->getMetrics()); } - public function testTraceAnalyticsConfigEnabledTrueResultTo1() + public function testTraceAnalyticsTrueIsDeprecatedNoOp() { $span = $this->createSpan(); $span->setMetric(Tag::ANALYTICS_KEY, true); - $this->assertSame(1.0, $span->getMetrics()[Tag::ANALYTICS_KEY]); + $this->assertArrayNotHasKey(Tag::ANALYTICS_KEY, $span->getMetrics()); } - public function testTraceAnalyticsConfigDisabled() + public function testTraceAnalyticsFalseIsDeprecatedNoOp() { $span = $this->createSpan(); $span->setMetric(Tag::ANALYTICS_KEY, true); - $this->assertSame(1.0, $span->getMetrics()[Tag::ANALYTICS_KEY]); - $span->setMetric(Tag::ANALYTICS_KEY, false); + $this->assertArrayNotHasKey(Tag::ANALYTICS_KEY, $span->getMetrics()); } - public function testTraceAnalyticsConfigSpecificRate() + public function testTraceAnalyticsSpecificRateIsDeprecatedNoOp() { $span = $this->createSpan(); $span->setMetric(Tag::ANALYTICS_KEY, 0.3); - $this->assertSame(0.3, $span->getMetrics()[Tag::ANALYTICS_KEY]); + + $this->assertArrayNotHasKey(Tag::ANALYTICS_KEY, $span->getMetrics()); } public function testSpanCreationDoesNotInterfereWithDeterministicRandomness() diff --git a/tests/WebServer.php b/tests/WebServer.php index 5652ad4853..57c0a5c3ac 100644 --- a/tests/WebServer.php +++ b/tests/WebServer.php @@ -118,6 +118,12 @@ public function __construct($indexFile, $host = '0.0.0.0', $port = 80, $ddprofSe $this->ddprofServiceName = $ddprofServiceName; } + // SAPI name of the default web server, which the tracer reports as the root span's default component. + public static function defaultSapiName() + { + return \getenv('DD_TRACE_TEST_SAPI') ?: 'cli-server'; + } + public function setRoadrunner($version) { $this->roadrunnerVersion = $version; diff --git a/tests/ext/active_span.phpt b/tests/ext/active_span.phpt index e08a13ea52..dea587bfc5 100644 --- a/tests/ext/active_span.phpt +++ b/tests/ext/active_span.phpt @@ -28,17 +28,13 @@ var_dump(DDTrace\active_span() == DDTrace\active_span()); Hello, Datadog. greet tracer. bool(true) -object(DDTrace\RootSpanData)#%d (24) { +object(DDTrace\RootSpanData)#%d (30) { ["name"]=> string(15) "active_span.php" ["resource"]=> string(0) "" ["service"]=> string(15) "active_span.php" - ["env"]=> - string(0) "" - ["version"]=> - string(0) "" ["meta_struct"]=> array(0) { } @@ -70,9 +66,9 @@ object(DDTrace\RootSpanData)#%d (24) { ["parent"]=> NULL ["stack"]=> - object(DDTrace\SpanStack)#%d (3) { + object(DDTrace\SpanStack)#%d (4) { ["parent"]=> - object(DDTrace\SpanStack)#%d (3) { + object(DDTrace\SpanStack)#%d (4) { ["parent"]=> NULL ["active"]=> @@ -80,24 +76,49 @@ object(DDTrace\RootSpanData)#%d (24) { ["spanCreationObservers"]=> array(0) { } + ["attributes"]=> + array(0) { + } } ["active"]=> *RECURSION* ["spanCreationObservers"]=> array(0) { } + ["attributes"]=> + array(0) { + } } ["onClose"]=> array(0) { } ["baggage"]=> array(0) { - }%r(\s*\["origin"\]=>\s+uninitialized\(string\))?%r + } + ["env"]=> + string(0) "" + ["version"]=> + string(0) "" + ["component"]=> + string(0) "" + ["spanKind"]=> + int(0) + ["attributes"]=> + array(2) { + ["runtime-id"]=> + string(36) "%s" + ["process_id"]=> + float(%f) + } + ["ignoreError"]=> + bool(false)%r(\s*\["origin"\]=>\s+uninitialized\(string\))?%r ["propagatedTags"]=> array(0) { } ["samplingPriority"]=> - int(1073741824)%r(\s*\["propagatedSamplingPriority"\]=>\s+uninitialized\(int\)\s*\["tracestate"\]=>\s+uninitialized\(string\))?%r + int(1073741824) + ["samplingMechanism"]=> + int(0)%r(\s*\["propagatedSamplingPriority"\]=>\s+uninitialized\(int\)\s*\["tracestate"\]=>\s+uninitialized\(string\))?%r ["tracestateTags"]=> array(0) { }%r(\s*\["parentId"\]=>\s+uninitialized\(string\))?%r @@ -107,5 +128,7 @@ object(DDTrace\RootSpanData)#%d (24) { NULL ["inferredSpan"]=> NULL + ["hostname"]=> + string(0) "" } bool(true) diff --git a/tests/ext/add_global_tag_on_userland_and_internal_spans.phpt b/tests/ext/add_global_tag_on_userland_and_internal_spans.phpt index 9018f175f4..d62abff268 100644 --- a/tests/ext/add_global_tag_on_userland_and_internal_spans.phpt +++ b/tests/ext/add_global_tag_on_userland_and_internal_spans.phpt @@ -30,9 +30,11 @@ var_dump(dd_clean_spans()); HOOK METHOD arg array(2) { [0]=> - array(10) { + array(11) { ["trace_id"]=> string(%d) "%d" + ["trace_id_high"]=> + string(16) "%s" ["span_id"]=> string(%d) "%d" ["parent_id"]=> @@ -49,7 +51,7 @@ array(2) { string(49) "add_global_tag_on_userland_and_internal_spans.php" ["type"]=> string(3) "cli" - ["meta"]=> + ["attributes"]=> array(2) { ["alone"]=> string(2) "no" @@ -77,7 +79,7 @@ array(2) { string(49) "add_global_tag_on_userland_and_internal_spans.php" ["type"]=> string(3) "cli" - ["meta"]=> + ["attributes"]=> array(2) { ["alone"]=> string(2) "no" diff --git a/tests/ext/analytics_event.phpt b/tests/ext/analytics_event.phpt new file mode 100644 index 0000000000..07ddd7720e --- /dev/null +++ b/tests/ext/analytics_event.phpt @@ -0,0 +1,43 @@ +--TEST-- +analytics.event maps to the _dd1.sr.eausr metric, set via $meta or $attributes +--ENV-- +DD_TRACE_GENERATE_ROOT_SPAN=0 +DD_TRACE_AUTO_FLUSH_ENABLED=0 +DD_CODE_ORIGIN_FOR_SPANS_ENABLED=0 +--FILE-- + function ($s) { $s->meta['analytics.event'] = 'true'; }, + 'meta string F' => function ($s) { $s->meta['analytics.event'] = 'F'; }, + 'meta bool true' => function ($s) { $s->meta['analytics.event'] = true; }, + 'attributes bool false' => function ($s) { $s->attributes['analytics.event'] = false; }, + 'attributes float' => function ($s) { $s->attributes['analytics.event'] = 0.5; }, + 'attributes string 1' => function ($s) { $s->attributes['analytics.event'] = '1'; }, + 'invalid string' => function ($s) { $s->meta['analytics.event'] = 'yes'; }, + 'invalid string keeps metric' => function ($s) { $s->meta['analytics.event'] = 'yes'; $s->metrics['_dd1.sr.eausr'] = 0.25; }, + 'valid value wins over metric' => function ($s) { $s->meta['analytics.event'] = 'true'; $s->metrics['_dd1.sr.eausr'] = 0; }, + 'metric only' => function ($s) { $s->metrics['_dd1.sr.eausr'] = 0.75; }, +]; +foreach ($cases as $name => $set) { + $s = \DDTrace\start_span(); + $s->name = $name; + $set($s); + \DDTrace\close_span(); +} +foreach (dd_trace_serialize_closed_spans() as $span) { + $attrs = $span['attributes']; + echo $span['name'], ': eausr=', var_export(isset($attrs['_dd1.sr.eausr']) ? $attrs['_dd1.sr.eausr'] : null, true), + ' analytics.event=', isset($attrs['analytics.event']) ? 'kept' : 'removed', "\n"; +} +?> +--EXPECT-- +metric only: eausr=0.75 analytics.event=removed +valid value wins over metric: eausr=1.0 analytics.event=removed +invalid string keeps metric: eausr=0.25 analytics.event=removed +invalid string: eausr=NULL analytics.event=removed +attributes string 1: eausr=1.0 analytics.event=removed +attributes float: eausr=0.5 analytics.event=removed +attributes bool false: eausr=0.0 analytics.event=removed +meta bool true: eausr=1.0 analytics.event=removed +meta string F: eausr=0.0 analytics.event=removed +meta string true: eausr=1.0 analytics.event=removed diff --git a/tests/ext/autoload-php-files/dd_init_open_basedir.phpt b/tests/ext/autoload-php-files/dd_init_open_basedir.phpt index c05c7d9f54..f999e4d761 100644 --- a/tests/ext/autoload-php-files/dd_init_open_basedir.phpt +++ b/tests/ext/autoload-php-files/dd_init_open_basedir.phpt @@ -18,4 +18,4 @@ echo 'Done.' . PHP_EOL; [ddtrace] [warning] [%d] Error raised in autoloaded file %s_files_tracer.php: %s(): Failed opening '%s_files_tracer.php' for inclusion %s on line %d [ddtrace] [warning] [%d] Error raised in autoloaded file %sDDTrace/OpenBaseDir.php: %s(): Failed opening '%sDDTrace/OpenBaseDir.php' for inclusion %s on line %d Done. -[ddtrace] [info] [%d] Flushing trace of size 1 to send-queue for %s +[ddtrace] [info] [%d] Flushing v1 trace of size 1 to send-queue for %s diff --git a/tests/ext/autoload-php-files/error_get_last_is_unaffected.phpt b/tests/ext/autoload-php-files/error_get_last_is_unaffected.phpt index bf86e43f42..a40262b3fd 100644 --- a/tests/ext/autoload-php-files/error_get_last_is_unaffected.phpt +++ b/tests/ext/autoload-php-files/error_get_last_is_unaffected.phpt @@ -17,4 +17,4 @@ var_dump(error_get_last()); [ddtrace] [warning] [%d] Error raised in autoloaded file %s_files_api.php: %s(): Failed opening '%s_files_api.php' for inclusion %s on line %d [ddtrace] [warning] [%d] Error raised in autoloaded file %sRaisesNotice.php: Notice? in %s on line %d NULL -[ddtrace] [info] [%d] Flushing trace of size 1 to send-queue for %s +[ddtrace] [info] [%d] Flushing v1 trace of size 1 to send-queue for %s diff --git a/tests/ext/autoload-php-files/file_not_found.phpt b/tests/ext/autoload-php-files/file_not_found.phpt index a645461720..94de72c536 100644 --- a/tests/ext/autoload-php-files/file_not_found.phpt +++ b/tests/ext/autoload-php-files/file_not_found.phpt @@ -18,4 +18,4 @@ echo "Request start" . PHP_EOL; [ddtrace] [warning] [%d] Error raised in autoloaded file %s_files_api.php: %s(): Failed opening '%s_files_api.php' for inclusion %s on line %d [ddtrace] [warning] [%d] Error raised in autoloaded file %s_files_tracer.php: %s(): Failed opening '%s_files_tracer.php' for inclusion %s on line %d Request start -[ddtrace] [info] [%d] Flushing trace of size 1 to send-queue for %s +[ddtrace] [info] [%d] Flushing v1 trace of size 1 to send-queue for %s diff --git a/tests/ext/autoload-php-files/ignores_exceptions.phpt b/tests/ext/autoload-php-files/ignores_exceptions.phpt index b77c513da8..e36e7bf971 100644 --- a/tests/ext/autoload-php-files/ignores_exceptions.phpt +++ b/tests/ext/autoload-php-files/ignores_exceptions.phpt @@ -19,4 +19,4 @@ echo "Request start" . PHP_EOL; Throwing an exception... [ddtrace] [warning] [%d] Exception thrown in autoloaded file %sRaisesException.php: Oops! Request start -[ddtrace] [info] [%d] Flushing trace of size 1 to send-queue for %s +[ddtrace] [info] [%d] Flushing v1 trace of size 1 to send-queue for %s diff --git a/tests/ext/autoload-php-files/ignores_fatal_errors.phpt b/tests/ext/autoload-php-files/ignores_fatal_errors.phpt index 1e5f7a8826..905c079ea4 100644 --- a/tests/ext/autoload-php-files/ignores_fatal_errors.phpt +++ b/tests/ext/autoload-php-files/ignores_fatal_errors.phpt @@ -21,4 +21,4 @@ echo "Request start" . PHP_EOL; Calling a function that does not exist... [ddtrace] [warning] [%d] Error raised in autoloaded file %s: Allowed memory size of 20971520 bytes exhausted %s on line %d Request start -[ddtrace] [info] [%d] Flushing trace of size 1 to send-queue for %s +[ddtrace] [info] [%d] Flushing v1 trace of size 1 to send-queue for %s diff --git a/tests/ext/background-sender/agent_headers.phpt b/tests/ext/background-sender/agent_headers.phpt index 75c4120b04..a5c8ca510d 100644 --- a/tests/ext/background-sender/agent_headers.phpt +++ b/tests/ext/background-sender/agent_headers.phpt @@ -1,6 +1,7 @@ --TEST-- HTTP headers are sent to the Agent from the background sender --SKIPIF-- + --ENV-- DD_TRACE_LOG_LEVEL=info,startup=off @@ -10,6 +11,7 @@ DD_TRACE_AGENT_FLUSH_AFTER_N_REQUESTS=1 DD_TRACE_AGENT_FLUSH_INTERVAL=666 DD_TRACE_GENERATE_ROOT_SPAN=0 DD_INSTRUMENTATION_TELEMETRY_ENABLED=0 +DD_TRACE_SIDECAR_TRACE_SENDER=0 --INI-- datadog.trace.agent_test_session_token=background-sender/agent_headers --FILE-- @@ -39,7 +41,7 @@ echo 'Done.' . PHP_EOL; ?> --EXPECTF-- -[ddtrace] [info] [%d] Flushing trace of size 1 to send-queue for http://request-replayer:80 +[ddtrace] [info] [%d] Flushing %d v0.4 trace(s) to send-queue for http://request-replayer:80 content-type: application/msgpack datadog-meta-lang: php diff --git a/tests/ext/background-sender/agent_headers_container_id.phpt b/tests/ext/background-sender/agent_headers_container_id.phpt index 6442f0c7bf..8251c40442 100644 --- a/tests/ext/background-sender/agent_headers_container_id.phpt +++ b/tests/ext/background-sender/agent_headers_container_id.phpt @@ -12,6 +12,7 @@ DD_TRACE_AGENT_FLUSH_AFTER_N_REQUESTS=1 DD_TRACE_AGENT_FLUSH_INTERVAL=666 DD_TRACE_GENERATE_ROOT_SPAN=0 DD_INSTRUMENTATION_TELEMETRY_ENABLED=0 +DD_TRACE_SIDECAR_TRACE_SENDER=0 --INI-- ddtrace.cgroup_file={PWD}/stubs/cgroup.docker datadog.trace.agent_test_session_token=background-sender/agent_headers_container_id @@ -38,7 +39,7 @@ echo 'Done.' . PHP_EOL; ?> --EXPECTF-- -[ddtrace] [info] [%d] Flushing trace of size 1 to send-queue for http://request-replayer:80 +[ddtrace] [info] [%d] Flushing %d v0.4 trace(s) to send-queue for http://request-replayer:80 datadog-container-id:%s9d5b23edb1ba181e8910389a99906598d69ac9a0ead109ee55730cc416d95f7f datadog-meta-lang: php diff --git a/tests/ext/background-sender/agent_headers_container_id_empty.phpt b/tests/ext/background-sender/agent_headers_container_id_empty.phpt index c54653abee..cce106108d 100644 --- a/tests/ext/background-sender/agent_headers_container_id_empty.phpt +++ b/tests/ext/background-sender/agent_headers_container_id_empty.phpt @@ -1,6 +1,7 @@ --TEST-- An empty container ID is not sent via HTTP headers to the Agent --SKIPIF-- + --ENV-- DD_TRACE_LOG_LEVEL=info,startup=off @@ -38,7 +39,7 @@ echo 'Done.' . PHP_EOL; ?> --EXPECTF-- -[ddtrace] [info] [%d] Flushing trace of size 1 to send-queue for http://request-replayer:80 +[ddtrace] [info] [%d] Flushing %d v0.4 trace(s) to send-queue for http://request-replayer:80 datadog-meta-lang: php diff --git a/tests/ext/background-sender/agent_headers_container_id_fargate.phpt b/tests/ext/background-sender/agent_headers_container_id_fargate.phpt index fa4fccffb7..f4dc2817fe 100644 --- a/tests/ext/background-sender/agent_headers_container_id_fargate.phpt +++ b/tests/ext/background-sender/agent_headers_container_id_fargate.phpt @@ -12,6 +12,7 @@ DD_TRACE_AGENT_FLUSH_AFTER_N_REQUESTS=1 DD_TRACE_AGENT_FLUSH_INTERVAL=333 DD_TRACE_GENERATE_ROOT_SPAN=0 DD_INSTRUMENTATION_TELEMETRY_ENABLED=0 +DD_TRACE_SIDECAR_TRACE_SENDER=0 --INI-- ddtrace.cgroup_file={PWD}/stubs/cgroup.fargate.1.4 datadog.trace.agent_test_session_token=background-sender/agent_headers_container_id_fargate @@ -37,7 +38,7 @@ echo 'Done.' . PHP_EOL; ?> --EXPECTF-- -[ddtrace] [info] [%d] Flushing trace of size 1 to send-queue for http://request-replayer:80 +[ddtrace] [info] [%d] Flushing %d v0.4 trace(s) to send-queue for http://request-replayer:80 datadog-container-id:%s34dc0b5e626f2c5c4c5170e34b10e765-1234567890 datadog-meta-lang: php diff --git a/tests/ext/background-sender/agent_headers_ignore_userland.phpt b/tests/ext/background-sender/agent_headers_ignore_userland.phpt deleted file mode 100644 index 224fcd6465..0000000000 --- a/tests/ext/background-sender/agent_headers_ignore_userland.phpt +++ /dev/null @@ -1,49 +0,0 @@ ---TEST-- -HTTP Agent headers are ignored from userland ---SKIPIF-- - ---ENV-- -DD_TRACE_LOG_LEVEL=info,startup=off -DD_AGENT_HOST=request-replayer -DD_TRACE_AGENT_PORT=80 -DD_TRACE_AGENT_FLUSH_AFTER_N_REQUESTS=1 -DD_TRACE_AGENT_FLUSH_INTERVAL=333 -DD_TRACE_GENERATE_ROOT_SPAN=0 -DD_INSTRUMENTATION_TELEMETRY_ENABLED=0 ---INI-- -datadog.trace.agent_test_session_token=background-sender/agent_headers_ignore_userland ---FILE-- -replayHeaders([ - 'datadog-meta-lang', - 'this-should-be', -]); -foreach ($headers as $name => $value) { - echo $name . ': ' . $value . PHP_EOL; -} -echo PHP_EOL; - -echo 'Done.' . PHP_EOL; - -?> ---EXPECTF-- -bool(true) - -datadog-meta-lang: php - -Done. -[ddtrace] [info] [%d] No finished traces to be sent to the agent diff --git a/tests/ext/background-sender/agent_headers_unix_domain_socket.phpt b/tests/ext/background-sender/agent_headers_unix_domain_socket.phpt index 040b4d15b2..816a951678 100644 --- a/tests/ext/background-sender/agent_headers_unix_domain_socket.phpt +++ b/tests/ext/background-sender/agent_headers_unix_domain_socket.phpt @@ -11,6 +11,7 @@ DD_TRACE_AGENT_FLUSH_INTERVAL=333 DD_TRACE_GENERATE_ROOT_SPAN=0 DD_INSTRUMENTATION_TELEMETRY_ENABLED=0 DD_REMOTE_CONFIG_ENABLED=0 +DD_TRACE_SIDECAR_TRACE_SENDER=0 --INI-- datadog.trace.agent_test_session_token=background-sender/agent_headers_unix_domain_socket --FILE-- diff --git a/tests/ext/background-sender/agent_sampling.phpt b/tests/ext/background-sender/agent_sampling.phpt index fe32799f15..d6f9194f75 100644 --- a/tests/ext/background-sender/agent_sampling.phpt +++ b/tests/ext/background-sender/agent_sampling.phpt @@ -2,6 +2,7 @@ The background sender informs about changes to the agent sample rate --SKIPIF-- @@ -59,10 +60,10 @@ echo "Specific sampling: {$get_sampling()}\n"; ?> --EXPECTF-- -[ddtrace] [info] [%d] Flushing trace of size 1 to send-queue for http://request-replayer:80 +[ddtrace] [info] [%d] Flushing 1 v0.4 trace(s) to send-queue for http://request-replayer:80 Initial sampling: 1 -[ddtrace] [info] [%d] Flushing trace of size 1 to send-queue for http://request-replayer:80 +[ddtrace] [info] [%d] Flushing 1 v0.4 trace(s) to send-queue for http://request-replayer:80 Generic sampling: 0 -[ddtrace] [info] [%d] Flushing trace of size 1 to send-queue for http://request-replayer:80 +[ddtrace] [info] [%d] Flushing 1 v0.4 trace(s) to send-queue for http://request-replayer:80 Specific sampling: 1 [ddtrace] [info] [%d] No finished traces to be sent to the agent diff --git a/tests/ext/background-sender/background_sender_restores_capabilities.phpt b/tests/ext/background-sender/background_sender_restores_capabilities.phpt deleted file mode 100644 index 81e76907ce..0000000000 --- a/tests/ext/background-sender/background_sender_restores_capabilities.phpt +++ /dev/null @@ -1,79 +0,0 @@ ---TEST-- -background sender restores effective capabilities from permitted set ---DESCRIPTION-- -The effective set may be cleared, e.g. when prctl(PR_SET_KEEPCAPS), followed by setuid(2) has been used. -Hence we exec() ourselves on top of a process with no effective capabilities. ---SKIPIF-- - - - - - - - ---FILE-- - '-E', -1 => '--'] + $cmdAndArgs); -} - -$ffi = FFI::cdef(<<new("cap_user_header_t"); -$capheader->version = _LINUX_CAPABILITY_VERSION_1; - -$capdata = $ffi->new("cap_user_data_t"); -$capdata->inheritable = 0; -$capdata->effective = 0; -$capdata->permitted = 1 << CAP_SETGID; - -if (!getenv("BACKGROUND_SENDER_RESTORES_CAPABILITIES")) { - $ffi->capset(FFI::addr($capheader), FFI::addr($capdata)); - - putenv("BACKGROUND_SENDER_RESTORES_CAPABILITIES=1"); - $cmdAndArgs = explode("\0", file_get_contents("/proc/" . getmypid() . "/cmdline")); - pcntl_exec(array_shift($cmdAndArgs), $cmdAndArgs); - - die("exec failed?"); -} - -$capdata->effective = $capdata->permitted; -$ffi->capset(FFI::addr($capheader), FFI::addr($capdata)); - -$groups = $ffi->new("uint32_t"); -$groups->cdata = 1; -var_dump($ffi->setgroups(1, FFI::addr($groups))); - -// payload = [[]] -$payload = "\x91\x90"; - -var_dump(dd_trace_send_traces_via_thread(1, [], $payload)); - -echo "Done."; -?> ---EXPECT-- -int(0) -bool(true) -Done. diff --git a/tests/ext/background-sender/background_sender_survives_setuid.phpt b/tests/ext/background-sender/background_sender_survives_setuid.phpt deleted file mode 100644 index 9ebd6e70bb..0000000000 --- a/tests/ext/background-sender/background_sender_survives_setuid.phpt +++ /dev/null @@ -1,77 +0,0 @@ ---TEST-- -background sender survives setuid ---DESCRIPTION-- -setuid() will reset the effective capabilities of the thread to zero when it's run. Ensure that we do not crash afterwards. -To test this we will issue a setgroups() via the libc wrapper (which distributes the setgroups() syscall to all threads of the process). ---SKIPIF-- - - - - - - - ---ENV-- -DD_TRACE_RETAIN_THREAD_CAPABILITIES=1 ---FILE-- - '-E', -1 => '--'] + $cmdAndArgs); -} - -$ffi = FFI::cdef(<<prctl(PR_SET_KEEPCAPS, 1); - -$ffi->setuid(1); // daemon user - -const _LINUX_CAPABILITY_VERSION_1 = 0x19980330; -const CAP_SETGID = 6; - -$capheader = $ffi->new("cap_user_header_t"); -$capheader->version = _LINUX_CAPABILITY_VERSION_1; - -$capdata = $ffi->new("cap_user_data_t"); -$capdata->inheritable = 0; -$capdata->effective = $capdata->permitted = 1 << CAP_SETGID; - -$ffi->capset(FFI::addr($capheader), FFI::addr($capdata)); - -$groups = $ffi->new("uint32_t"); -$groups->cdata = 1; -var_dump($ffi->setgroups(1, FFI::addr($groups))); - -// payload = [[]] -$payload = "\x91\x90"; - -var_dump(dd_trace_send_traces_via_thread(1, [], $payload)); - -echo "Done."; -?> ---EXPECT-- -int(0) -bool(true) -Done. diff --git a/tests/ext/base_service.phpt b/tests/ext/base_service.phpt index a775ec2358..146041e8b8 100644 --- a/tests/ext/base_service.phpt +++ b/tests/ext/base_service.phpt @@ -18,9 +18,11 @@ var_dump(dd_clean_spans()); --EXPECTF-- array(1) { [0]=> - array(10) { + array(11) { ["trace_id"]=> string(%d) "%d" + ["trace_id_high"]=> + string(16) "%s" ["span_id"]=> string(%d) "%d" ["parent_id"]=> @@ -37,12 +39,12 @@ array(1) { string(7) "changed" ["type"]=> string(3) "cli" - ["meta"]=> + ["attributes"]=> array(2) { - ["_dd.base_service"]=> - string(16) "base_service.php" ["_dd.svc_src"]=> string(1) "m" + ["_dd.base_service"]=> + string(16) "base_service.php" } } } diff --git a/tests/ext/client_side_stats_top_level.phpt b/tests/ext/client_side_stats_top_level.phpt index 36f4b38ba6..3f00ce01ed 100644 --- a/tests/ext/client_side_stats_top_level.phpt +++ b/tests/ext/client_side_stats_top_level.phpt @@ -33,7 +33,7 @@ $child_diff->service = "other-service"; $spans = dd_trace_serialize_closed_spans(); foreach ($spans as $span) { - $has_top_level = isset($span["metrics"]["_dd.top_level"]); + $has_top_level = isset($span["attributes"]["_dd.top_level"]); echo $span["name"] . ": _dd.top_level=" . ($has_top_level ? "1" : "not set") . "\n"; } diff --git a/tests/ext/close_spans_until.phpt b/tests/ext/close_spans_until.phpt index f2247f99c5..591cfd918d 100644 --- a/tests/ext/close_spans_until.phpt +++ b/tests/ext/close_spans_until.phpt @@ -48,11 +48,11 @@ int(2) [ddtrace] [span] [%d] Switching to different SpanStack: %d int(1) int(0) -[ddtrace] [span] [%d] Encoding span: Span { service: close_spans_until.php, name: close_spans_until.php, resource: close_spans_until.php, type: cli, trace_id: %d, span_id: %d, parent_id: 0, start: %d, duration: %d, error: 0, meta: %s, metrics: %s, meta_struct: %s, span_links: [], span_events: [] } -[ddtrace] [span] [%d] Encoding span: Span { service: close_spans_until.php, name: traced, resource: traced, type: cli, trace_id: %d, span_id: %d, parent_id: %d, start: %d, duration: %d, error: %d, meta: %s, metrics: %s, meta_struct: %s, span_links: %s, span_events: %s } -[ddtrace] [span] [%d] Encoding span: Span { service: close_spans_until.php, name: , resource: , type: cli, trace_id: %d, span_id: %d, parent_id: %d, start: %d, duration: %d, error: %d, meta: %s, metrics: %s, meta_struct: %s, span_links: %s, span_events: %s } -[ddtrace] [span] [%d] Encoding span: Span { service: close_spans_until.php, name: , resource: , type: cli, trace_id: %d, span_id: %d, parent_id: %d, start: %d, duration: %d, error: %d, meta: %s, metrics: %s, meta_struct: %s, span_links: %s, span_events: %s } -[ddtrace] [span] [%d] Encoding span: Span { service: close_spans_until.php, name: , resource: , type: cli, trace_id: %d, span_id: %d, parent_id: %d, start: %d, duration: %d, error: %d, meta: %s, metrics: %s, meta_struct: %s, span_links: %s, span_events: %s } -[ddtrace] [span] [%d] Encoding span: Span { service: close_spans_until.php, name: , resource: , type: cli, trace_id: %d, span_id: %d, parent_id: %d, start: %d, duration: %d, error: %d, meta: %s, metrics: %s, meta_struct: %s, span_links: %s, span_events: %s } -[ddtrace] [span] [%d] Encoding span: Span { service: close_spans_until.php, name: , resource: , type: cli, trace_id: %d, span_id: %d, parent_id: %d, start: %d, duration: %d, error: %d, meta: %s, metrics: %s, meta_struct: %s, span_links: %s, span_events: %s } -[ddtrace] [info] [%d] Flushing trace of size 7 to send-queue for %s +[ddtrace] [span] [%d] Encoding span: trace_id=%s service="close_spans_until.php" name="close_spans_until.php" resource="close_spans_until.php" type="cli" span_id=%d parent_id=0 start=%d duration=%d error=false kind=%s env="" version="" component="" attributes=%s links=0 events=0 +[ddtrace] [span] [%d] Encoding span: trace_id=%s service="close_spans_until.php" name="traced" resource="traced" type="cli" span_id=%d parent_id=%d start=%d duration=%d error=%s kind=%s env="" version="" component="" attributes=%s links=%d events=%d +[ddtrace] [span] [%d] Encoding span: trace_id=%s service="close_spans_until.php" name="" resource="" type="cli" span_id=%d parent_id=%d start=%d duration=%d error=%s kind=%s env="" version="" component="" attributes=%s links=%d events=%d +[ddtrace] [span] [%d] Encoding span: trace_id=%s service="close_spans_until.php" name="" resource="" type="cli" span_id=%d parent_id=%d start=%d duration=%d error=%s kind=%s env="" version="" component="" attributes=%s links=%d events=%d +[ddtrace] [span] [%d] Encoding span: trace_id=%s service="close_spans_until.php" name="" resource="" type="cli" span_id=%d parent_id=%d start=%d duration=%d error=%s kind=%s env="" version="" component="" attributes=%s links=%d events=%d +[ddtrace] [span] [%d] Encoding span: trace_id=%s service="close_spans_until.php" name="" resource="" type="cli" span_id=%d parent_id=%d start=%d duration=%d error=%s kind=%s env="" version="" component="" attributes=%s links=%d events=%d +[ddtrace] [span] [%d] Encoding span: trace_id=%s service="close_spans_until.php" name="" resource="" type="cli" span_id=%d parent_id=%d start=%d duration=%d error=%s kind=%s env="" version="" component="" attributes=%s links=%d events=%d +[ddtrace] [info] [%d] Flushing v1 trace of size 7 to send-queue for %s diff --git a/tests/ext/dd_trace_send_traces_via_thread_001.phpt b/tests/ext/dd_trace_send_traces_via_thread_001.phpt deleted file mode 100644 index 085096d1c8..0000000000 --- a/tests/ext/dd_trace_send_traces_via_thread_001.phpt +++ /dev/null @@ -1,23 +0,0 @@ ---TEST-- -background sender happy path ---SKIPIF-- - ---ENV-- -DD_TRACE_SIDECAR_TRACE_SENDER=0 ---FILE-- - 'php', -]; - -// payload = [[]] -$payload = "\x91\x90"; - -var_dump(dd_trace_send_traces_via_thread(1, $headers, $payload)); - -echo "Done."; -?> ---EXPECT-- -bool(true) -Done. diff --git a/tests/ext/dd_trace_send_traces_via_thread_002.phpt b/tests/ext/dd_trace_send_traces_via_thread_002.phpt deleted file mode 100644 index 71fe798761..0000000000 --- a/tests/ext/dd_trace_send_traces_via_thread_002.phpt +++ /dev/null @@ -1,21 +0,0 @@ ---TEST-- -background sender should reject msgpack array prefix that does not match expected number of traces ---SKIPIF-- - ---FILE-- - 'php', -]; - -// payload = [] -$payload = "\x90"; - -var_dump(dd_trace_send_traces_via_thread(1, $headers, $payload)); - -echo "Done."; -?> ---EXPECT-- -bool(false) -Done. diff --git a/tests/ext/dd_trace_serialize_header_to_meta.phpt b/tests/ext/dd_trace_serialize_header_to_meta.phpt index f8e548765a..2a83dc5dbb 100644 --- a/tests/ext/dd_trace_serialize_header_to_meta.phpt +++ b/tests/ext/dd_trace_serialize_header_to_meta.phpt @@ -14,10 +14,10 @@ application_key=123 DDTrace\start_span(); DDTrace\close_span(); $spans = dd_trace_serialize_closed_spans(); -var_dump($spans[0]['meta']['http.request.headers.content-type']); -var_dump($spans[0]['meta']['custom-HeaderKey']); -var_dump($spans[0]['meta']['t a g']); -var_dump($spans[0]['meta']['tag']); +var_dump($spans[0]['attributes']['http.request.headers.content-type']); +var_dump($spans[0]['attributes']['custom-HeaderKey']); +var_dump($spans[0]['attributes']['t a g']); +var_dump($spans[0]['attributes']['tag']); ?> --EXPECT-- string(10) "text/plain" diff --git a/tests/ext/dd_trace_serialize_msgpack.phpt b/tests/ext/dd_trace_serialize_msgpack.phpt deleted file mode 100644 index f47738f234..0000000000 --- a/tests/ext/dd_trace_serialize_msgpack.phpt +++ /dev/null @@ -1,40 +0,0 @@ ---TEST-- -Basic functionality of dd_trace_serialize_msgpack() ---DESCRIPTION-- -The "EXPECT" section was generated with the following tool: -https://github.com/ludocode/msgpack-tools -Example command: -$ echo '{"compact": true, "schema": 0}' | json2msgpack | hexdump ---SKIPIF-- - ---FILE-- - "1589331357723252209", - "span_id" => "1589331357723252210", - "name" => "test_name", - "resource" => "test_resource", - "service" => "test_service", - "start" => 1518038421211969000, - "error" => 0, - "meta" => [], - ], -]]; -echo json_encode($traces) . "\n"; - -$encoded = dd_trace_serialize_msgpack($traces); -echo dd_trace_unserialize_trace_hex($encoded) . "\n"; -?> ---EXPECT-- -[[{"trace_id":"1589331357723252209","span_id":"1589331357723252210","name":"test_name","resource":"test_resource","service":"test_service","start":1518038421211969000,"error":0,"meta":[]}]] -91 91 88 a8 74 72 61 63 65 5f 69 64 cf 16 0e 70 72 ff 7b d5 f1 a7 73 70 61 6e 5f 69 64 cf 16 0e 70 72 ff 7b d5 f2 a4 6e 61 6d 65 a9 74 65 73 74 5f 6e 61 6d 65 a8 72 65 73 6f 75 72 63 65 ad 74 65 73 74 5f 72 65 73 6f 75 72 63 65 a7 73 65 72 76 69 63 65 ac 74 65 73 74 5f 73 65 72 76 69 63 65 a5 73 74 61 72 74 cf 15 11 27 e6 b3 bb f5 e8 a5 65 72 72 6f 72 00 a4 6d 65 74 61 90 \ No newline at end of file diff --git a/tests/ext/dd_trace_serialize_msgpack_error.phpt b/tests/ext/dd_trace_serialize_msgpack_error.phpt deleted file mode 100644 index 871f5776d0..0000000000 --- a/tests/ext/dd_trace_serialize_msgpack_error.phpt +++ /dev/null @@ -1,34 +0,0 @@ ---TEST-- -dd_trace_serialize_msgpack() error conditions ---ENV-- -DD_TRACE_AUTO_FLUSH_ENABLED=0 -DD_TRACE_LOG_LEVEL=info,startup=off ---FILE-- - ---EXPECTF-- -[ddtrace] [warning] [%d] Serialize values must be of type array, string, int, float, bool or null -array(1) { - [0]=> - object(stdClass)#%d (0) { - } -} -bool(false) - -[ddtrace] [warning] [%d] Serialize values must be of type array, string, int, float, bool or null -array(2) { - [0]=> - string(3) "bar" - [1]=> - resource(%d) of type (stream-context) -} -bool(false) - -[ddtrace] [info] [%d] Flushing trace of size 1 to send-queue for %s diff --git a/tests/ext/dd_trace_serialize_msgpack_id_in_meta.phpt b/tests/ext/dd_trace_serialize_msgpack_id_in_meta.phpt deleted file mode 100644 index a4aae4b3e8..0000000000 --- a/tests/ext/dd_trace_serialize_msgpack_id_in_meta.phpt +++ /dev/null @@ -1,36 +0,0 @@ ---TEST-- -dd_trace_serialize_msgpack() properly handles span_id, trace_id and parent_id, but only outside of nested arrays ---SKIPIF-- - ---FILE-- - "1589331357723252209", - "parent_id" => "1589331357723252200", - "span_id" => "1589331357723252210", - "meta" => [ - "trace_id" => "1589331357723252209", - "parent_id" => "1589331357723252209", - "span_id" => "1589331357723252210", - "test" => "1234", - ], - ], -]]; -echo json_encode($traces) . "\n"; - -$encoded = dd_trace_serialize_msgpack($traces); -echo dd_trace_unserialize_trace_hex($encoded) . "\n"; -?> ---EXPECT-- -[[{"trace_id":"1589331357723252209","parent_id":"1589331357723252200","span_id":"1589331357723252210","meta":{"trace_id":"1589331357723252209","parent_id":"1589331357723252209","span_id":"1589331357723252210","test":"1234"}}]] -91 91 84 a8 74 72 61 63 65 5f 69 64 cf 16 0e 70 72 ff 7b d5 f1 a9 70 61 72 65 6e 74 5f 69 64 cf 16 0e 70 72 ff 7b d5 e8 a7 73 70 61 6e 5f 69 64 cf 16 0e 70 72 ff 7b d5 f2 a4 6d 65 74 61 84 a8 74 72 61 63 65 5f 69 64 b3 31 35 38 39 33 33 31 33 35 37 37 32 33 32 35 32 32 30 39 a9 70 61 72 65 6e 74 5f 69 64 b3 31 35 38 39 33 33 31 33 35 37 37 32 33 32 35 32 32 30 39 a7 73 70 61 6e 5f 69 64 b3 31 35 38 39 33 33 31 33 35 37 37 32 33 32 35 32 32 31 30 a4 74 65 73 74 a4 31 32 33 34 diff --git a/tests/ext/dd_trace_serialize_msgpack_reference.phpt b/tests/ext/dd_trace_serialize_msgpack_reference.phpt deleted file mode 100644 index 4b1a430696..0000000000 --- a/tests/ext/dd_trace_serialize_msgpack_reference.phpt +++ /dev/null @@ -1,47 +0,0 @@ ---TEST-- -dd_trace_serialize_msgpack() with references ---DESCRIPTION-- -The "EXPECT" section was generated with the following tool: -https://github.com/ludocode/msgpack-tools -Example command: -$ echo '{"compact": true, "schema": 0}' | json2msgpack | hexdump ---SKIPIF-- - ---FILE-- - "1589331357723252209", - "span_id" => "1589331357723252210", - "name" => "test_name", - "resource" => "test_resource", - "service" => "test_service", - "start" => 1518038421211969000, - "error" => 0, - ], -]]; - -$globalTags = ['foo' => 'bar']; -foreach ($traces[0] as &$span) { - foreach ($globalTags as $globalTagName => $globalTagValue) { - $span['meta'][$globalTagName] = $globalTagValue; - } -} - -echo json_encode($traces) . "\n"; - -$encoded = dd_trace_serialize_msgpack($traces); -echo dd_trace_unserialize_trace_hex($encoded) . "\n"; -?> ---EXPECT-- -[[{"trace_id":"1589331357723252209","span_id":"1589331357723252210","name":"test_name","resource":"test_resource","service":"test_service","start":1518038421211969000,"error":0,"meta":{"foo":"bar"}}]] -91 91 88 a8 74 72 61 63 65 5f 69 64 cf 16 0e 70 72 ff 7b d5 f1 a7 73 70 61 6e 5f 69 64 cf 16 0e 70 72 ff 7b d5 f2 a4 6e 61 6d 65 a9 74 65 73 74 5f 6e 61 6d 65 a8 72 65 73 6f 75 72 63 65 ad 74 65 73 74 5f 72 65 73 6f 75 72 63 65 a7 73 65 72 76 69 63 65 ac 74 65 73 74 5f 73 65 72 76 69 63 65 a5 73 74 61 72 74 cf 15 11 27 e6 b3 bb f5 e8 a5 65 72 72 6f 72 00 a4 6d 65 74 61 81 a3 66 6f 6f a3 62 61 72 diff --git a/tests/ext/dd_trace_span_data_get_link.phpt b/tests/ext/dd_trace_span_data_get_link.phpt index de41d8f90e..c577a33217 100644 --- a/tests/ext/dd_trace_span_data_get_link.phpt +++ b/tests/ext/dd_trace_span_data_get_link.phpt @@ -27,6 +27,6 @@ greet('Datadog'); --EXPECTF-- Hello, Datadog. greet tracer. -string(%d) "{"trace_id":"%s","span_id":"%s"}" +string(%d) "{"traceId":"%s","spanId":"%s"}" bool(true) bool(true) diff --git a/tests/ext/dd_trace_span_data_serialization_with_links.phpt b/tests/ext/dd_trace_span_data_serialization_with_links.phpt index 9edbb95974..2740be6927 100644 --- a/tests/ext/dd_trace_span_data_serialization_with_links.phpt +++ b/tests/ext/dd_trace_span_data_serialization_with_links.phpt @@ -16,6 +16,8 @@ DDTrace\trace_function('foo', $span->name = 'foo'; $firstLink = $span->getLink(); + // Drive the link through the real serialization path (produces native span_links). + $span->links = [$firstLink]; } ); @@ -24,6 +26,8 @@ DDTrace\trace_function('bar', $span->name = 'bar'; $secondLink = $span->getLink(); + // Drive the link through the real serialization path (produces native span_links). + $span->links = [$secondLink]; } ); @@ -39,31 +43,20 @@ foo(); bar(); baz(); -var_dump(json_encode($firstLink)); -var_dump($firstLink->jsonSerialize()); -var_dump(json_encode($secondLink)); -var_dump($secondLink->jsonSerialize()); -var_dump(dd_clean_spans()[0]); +$spans = dd_clean_spans(); +// baz carries both links; foo and bar each carry their own self-link. All are asserted through +// the actual span serialization (native top-level span_links), which is the real wire path. +var_dump($spans[0]); +var_dump($spans[1]['name'], $spans[1]['span_links']); +var_dump($spans[2]['name'], $spans[2]['span_links']); ?> --EXPECTF-- -string(76) "{"trace_id":"%sc151df7d6ee5e2d6","span_id":"a3978fb9b92502a8"}" -array(5) { - ["trace_id"]=> - string(32) "%sc151df7d6ee5e2d6" - ["span_id"]=> - string(16) "a3978fb9b92502a8" -} -string(76) "{"trace_id":"%sc151df7d6ee5e2d6","span_id":"c08c967f0e5e7b0a"}" -array(5) { - ["trace_id"]=> - string(32) "%sc151df7d6ee5e2d6" - ["span_id"]=> - string(16) "c08c967f0e5e7b0a" -} -array(10) { +array(11) { ["trace_id"]=> string(20) "13930160852258120406" + ["trace_id_high"]=> + string(16) "%s" ["span_id"]=> string(19) "2513787319205155662" ["parent_id"]=> @@ -80,9 +73,57 @@ array(10) { string(47) "dd_trace_span_data_serialization_with_links.php" ["type"]=> string(3) "cli" - ["meta"]=> - array(1) { - ["_dd.span_links"]=> - string(155) "[{"trace_id":"%sc151df7d6ee5e2d6","span_id":"a3978fb9b92502a8"},{"trace_id":"%sc151df7d6ee5e2d6","span_id":"c08c967f0e5e7b0a"}]" + ["span_links"]=> + array(2) { + [0]=> + array(4) { + ["trace_id"]=> + string(20) "13930160852258120406" + ["trace_id_high"]=> + string(16) "%s" + ["span_id"]=> + string(20) "11788048577503494824" + ["flags"]=> + int(0) + } + [1]=> + array(4) { + ["trace_id"]=> + string(20) "13930160852258120406" + ["trace_id_high"]=> + string(16) "%s" + ["span_id"]=> + string(20) "13874630024467741450" + ["flags"]=> + int(0) + } + } +} +string(3) "bar" +array(1) { + [0]=> + array(4) { + ["trace_id"]=> + string(20) "13930160852258120406" + ["trace_id_high"]=> + string(16) "%s" + ["span_id"]=> + string(20) "13874630024467741450" + ["flags"]=> + int(0) + } +} +string(3) "foo" +array(1) { + [0]=> + array(4) { + ["trace_id"]=> + string(20) "13930160852258120406" + ["trace_id_high"]=> + string(16) "%s" + ["span_id"]=> + string(20) "11788048577503494824" + ["flags"]=> + int(0) } } diff --git a/tests/ext/dd_trace_span_link_event_native_nested_attributes.phpt b/tests/ext/dd_trace_span_link_event_native_nested_attributes.phpt new file mode 100644 index 0000000000..2c6e240947 --- /dev/null +++ b/tests/ext/dd_trace_span_link_event_native_nested_attributes.phpt @@ -0,0 +1,62 @@ +--TEST-- +Span link and event array/object attributes serialize as native nested V1 attributes +--ENV-- +DD_TRACE_DEBUG_PRNG_SEED=42 +--FILE-- +name = 'foo'; + + // A link whose attributes include an array and a nested object/map. Before Phase 3 these were + // json_encode()'d to a string; they must now round-trip as native nested attributes. + $link = new SpanLink(); + $link->traceId = "42"; + $link->spanId = "6"; + $link->attributes = ['nums' => [3, 4], 'nested' => ['k' => 'v']]; + $span->links[] = $link; + + // Same for an event. + $span->events[] = new SpanEvent('evt', ['arr' => [3, 4], 'obj' => ['k' => 'v']], 1); +}); + +foo(); + +$spans = dd_clean_spans(); +$link = $spans[0]['span_links'][0]; +$event = $spans[0]['span_events'][0]; + +// Native nested shape: lists become packed arrays (typed leaves preserved), maps become assoc arrays. +var_dump($link['attributes']['nums']); +var_dump($link['attributes']['nested']); +var_dump($event['attributes']['arr']); +var_dump($event['attributes']['obj']); + +?> +--EXPECT-- +array(2) { + [0]=> + int(3) + [1]=> + int(4) +} +array(1) { + ["k"]=> + string(1) "v" +} +array(2) { + [0]=> + int(3) + [1]=> + int(4) +} +array(1) { + ["k"]=> + string(1) "v" +} diff --git a/tests/ext/distributed_tracing/distributed_trace_asm_standalone_01.phpt b/tests/ext/distributed_tracing/distributed_trace_asm_standalone_01.phpt index db324e84c9..7a55657c35 100644 --- a/tests/ext/distributed_tracing/distributed_trace_asm_standalone_01.phpt +++ b/tests/ext/distributed_tracing/distributed_trace_asm_standalone_01.phpt @@ -28,7 +28,7 @@ var_dump(dd_clean_spans()); --EXPECTF-- array(2) { [0]=> - array(11) { + array(13) { ["trace_id"]=> string(2) "42" ["span_id"]=> @@ -47,39 +47,36 @@ array(2) { string(39) "distributed_trace_asm_standalone_01.php" ["type"]=> string(3) "cli" - ["meta"]=> - array(6) { - ["_dd.origin"]=> - string(7) "datadog" + ["sampling_priority"]=> + int(1) + ["sampling_mechanism"]=> + int(0) + ["origin"]=> + string(7) "datadog" + ["attributes"]=> + array(9) { ["_dd.p.custom_tag"]=> string(9) "inherited" - ["_dd.p.dm"]=> - string(2) "-0" - ["_dd.p.other_tag"]=> - string(4) "also" ["_dd.propagation_error"]=> string(14) "decoding_error" + ["_dd.p.other_tag"]=> + string(4) "also" ["runtime-id"]=> string(36) "%s" - } - ["metrics"]=> - array(6) { + ["process_id"]=> + float(%f) ["_dd.apm.enabled"]=> float(0) - ["_sampling_priority_v1"]=> - float(1) ["php.compilation.total_time_ms"]=> float(%f) - ["php.memory.peak_real_usage_bytes"]=> - float(%f) ["php.memory.peak_usage_bytes"]=> float(%f) - ["process_id"]=> + ["php.memory.peak_real_usage_bytes"]=> float(%f) } } [1]=> - array(11) { + array(10) { ["trace_id"]=> string(2) "42" ["span_id"]=> @@ -98,12 +95,7 @@ array(2) { string(39) "distributed_trace_asm_standalone_01.php" ["type"]=> string(3) "cli" - ["meta"]=> - array(1) { - ["_dd.origin"]=> - string(7) "datadog" - } - ["metrics"]=> + ["attributes"]=> array(1) { ["_dd.apm.enabled"]=> float(0) diff --git a/tests/ext/distributed_tracing/distributed_trace_asm_standalone_02.phpt b/tests/ext/distributed_tracing/distributed_trace_asm_standalone_02.phpt index 98300bf291..4fbf282672 100644 --- a/tests/ext/distributed_tracing/distributed_trace_asm_standalone_02.phpt +++ b/tests/ext/distributed_tracing/distributed_trace_asm_standalone_02.phpt @@ -28,7 +28,7 @@ var_dump(dd_clean_spans()); --EXPECTF-- array(2) { [0]=> - array(11) { + array(13) { ["trace_id"]=> string(2) "42" ["span_id"]=> @@ -47,35 +47,32 @@ array(2) { string(39) "distributed_trace_asm_standalone_02.php" ["type"]=> string(3) "cli" - ["meta"]=> - array(4) { - ["_dd.origin"]=> - string(7) "datadog" - ["_dd.p.dm"]=> - string(2) "-0" + ["sampling_priority"]=> + int(3) + ["sampling_mechanism"]=> + int(0) + ["origin"]=> + string(7) "datadog" + ["attributes"]=> + array(7) { ["_dd.p.ts"]=> string(2) "02" ["runtime-id"]=> string(36) "%s" - } - ["metrics"]=> - array(6) { + ["process_id"]=> + float(%f) ["_dd.apm.enabled"]=> float(0) - ["_sampling_priority_v1"]=> - float(3) ["php.compilation.total_time_ms"]=> float(%f) - ["php.memory.peak_real_usage_bytes"]=> - float(%f) ["php.memory.peak_usage_bytes"]=> float(%f) - ["process_id"]=> + ["php.memory.peak_real_usage_bytes"]=> float(%f) } } [1]=> - array(11) { + array(10) { ["trace_id"]=> string(2) "42" ["span_id"]=> @@ -94,12 +91,7 @@ array(2) { string(39) "distributed_trace_asm_standalone_02.php" ["type"]=> string(3) "cli" - ["meta"]=> - array(1) { - ["_dd.origin"]=> - string(7) "datadog" - } - ["metrics"]=> + ["attributes"]=> array(1) { ["_dd.apm.enabled"]=> float(0) diff --git a/tests/ext/distributed_tracing/distributed_trace_asm_standalone_03.phpt b/tests/ext/distributed_tracing/distributed_trace_asm_standalone_03.phpt index 30ea476e07..df4a71554c 100644 --- a/tests/ext/distributed_tracing/distributed_trace_asm_standalone_03.phpt +++ b/tests/ext/distributed_tracing/distributed_trace_asm_standalone_03.phpt @@ -18,7 +18,7 @@ DDTrace\close_span(); $traces = dd_trace_serialize_closed_spans(); -var_dump($traces[0]['meta']['_dd.p.ts']); +var_dump($traces[0]['attributes']['_dd.p.ts']); ?> --EXPECTF-- diff --git a/tests/ext/distributed_tracing/distributed_trace_asm_standalone_04.phpt b/tests/ext/distributed_tracing/distributed_trace_asm_standalone_04.phpt index 1a589559b3..86700f64ac 100644 --- a/tests/ext/distributed_tracing/distributed_trace_asm_standalone_04.phpt +++ b/tests/ext/distributed_tracing/distributed_trace_asm_standalone_04.phpt @@ -18,7 +18,7 @@ DDTrace\close_span(); $traces = dd_trace_serialize_closed_spans(); -var_dump($traces[0]['meta']['_dd.p.ts']); +var_dump($traces[0]['attributes']['_dd.p.ts']); ?> --EXPECTF-- diff --git a/tests/ext/distributed_tracing/distributed_trace_asm_standalone_05.phpt b/tests/ext/distributed_tracing/distributed_trace_asm_standalone_05.phpt index 70046cb2b2..eb5f2c44de 100644 --- a/tests/ext/distributed_tracing/distributed_trace_asm_standalone_05.phpt +++ b/tests/ext/distributed_tracing/distributed_trace_asm_standalone_05.phpt @@ -18,7 +18,7 @@ DDTrace\close_span(); $traces = dd_trace_serialize_closed_spans(); -var_dump($traces[0]['meta']['_dd.p.ts']); +var_dump($traces[0]['attributes']['_dd.p.ts']); ?> --EXPECTF-- diff --git a/tests/ext/distributed_tracing/distributed_trace_asm_standalone_06.phpt b/tests/ext/distributed_tracing/distributed_trace_asm_standalone_06.phpt index 2b75385f95..cb92e2e792 100644 --- a/tests/ext/distributed_tracing/distributed_trace_asm_standalone_06.phpt +++ b/tests/ext/distributed_tracing/distributed_trace_asm_standalone_06.phpt @@ -26,11 +26,11 @@ DDTrace\close_span(); $traces = dd_trace_serialize_closed_spans(); var_dump($traces[0]['name']); -var_dump(isset($traces[0]['meta']['_dd.p.ts'])); +var_dump(isset($traces[0]['attributes']['_dd.p.ts'])); var_dump($traces[1]['name']); -var_dump($traces[1]['meta']['_dd.p.ts']); +var_dump($traces[1]['attributes']['_dd.p.ts']); var_dump($traces[2]['name']); -var_dump($traces[2]['meta']['_dd.p.ts']); +var_dump($traces[2]['attributes']['_dd.p.ts']); ?> --EXPECTF-- diff --git a/tests/ext/distributed_tracing/distributed_trace_asm_standalone_07.phpt b/tests/ext/distributed_tracing/distributed_trace_asm_standalone_07.phpt index e9285c5548..25a2bd7a14 100644 --- a/tests/ext/distributed_tracing/distributed_trace_asm_standalone_07.phpt +++ b/tests/ext/distributed_tracing/distributed_trace_asm_standalone_07.phpt @@ -22,9 +22,9 @@ DDTrace\close_span(); $traces = dd_trace_serialize_closed_spans(); var_dump($traces[0]['name']); -var_dump($traces[0]['meta']['_dd.p.ts']); +var_dump($traces[0]['attributes']['_dd.p.ts']); var_dump($traces[1]['name']); -var_dump($traces[1]['meta']['_dd.p.ts']); +var_dump($traces[1]['attributes']['_dd.p.ts']); ?> --EXPECTF-- diff --git a/tests/ext/distributed_tracing/distributed_trace_asm_standalone_08.phpt b/tests/ext/distributed_tracing/distributed_trace_asm_standalone_08.phpt index acb15dea0d..96e9fb8ad4 100644 --- a/tests/ext/distributed_tracing/distributed_trace_asm_standalone_08.phpt +++ b/tests/ext/distributed_tracing/distributed_trace_asm_standalone_08.phpt @@ -18,7 +18,7 @@ DDTrace\close_span(); $traces = dd_trace_serialize_closed_spans(); -var_dump($traces[0]['meta']['_dd.p.ts']); +var_dump($traces[0]['attributes']['_dd.p.ts']); ?> --EXPECTF-- diff --git a/tests/ext/distributed_tracing/distributed_trace_asm_standalone_09.phpt b/tests/ext/distributed_tracing/distributed_trace_asm_standalone_09.phpt index e02e2fef6a..9dec29edb7 100644 --- a/tests/ext/distributed_tracing/distributed_trace_asm_standalone_09.phpt +++ b/tests/ext/distributed_tracing/distributed_trace_asm_standalone_09.phpt @@ -17,7 +17,7 @@ DDTrace\close_span(); $traces = dd_trace_serialize_closed_spans(); -var_dump($traces[0]['meta']['_dd.p.ts']); +var_dump($traces[0]['attributes']['_dd.p.ts']); ?> --EXPECTF-- diff --git a/tests/ext/distributed_tracing/distributed_trace_bogus_ids.phpt b/tests/ext/distributed_tracing/distributed_trace_bogus_ids.phpt index b5b61f87fc..b8070bee42 100644 --- a/tests/ext/distributed_tracing/distributed_trace_bogus_ids.phpt +++ b/tests/ext/distributed_tracing/distributed_trace_bogus_ids.phpt @@ -21,9 +21,11 @@ var_dump(dd_clean_spans()); --EXPECTF-- array(1) { [0]=> - array(10) { + array(13) { ["trace_id"]=> string(%d) "%d" + ["trace_id_high"]=> + string(16) "%s" ["span_id"]=> string(%d) "%d" ["start"]=> @@ -38,30 +40,25 @@ array(1) { string(31) "distributed_trace_bogus_ids.php" ["type"]=> string(3) "cli" - ["meta"]=> - array(4) { - ["_dd.origin"]=> - string(7) "datadog" - ["_dd.p.dm"]=> - string(2) "-0" - ["_dd.p.tid"]=> - string(16) "%s" + ["sampling_priority"]=> + int(1) + ["sampling_mechanism"]=> + int(0) + ["origin"]=> + string(7) "datadog" + ["attributes"]=> + array(6) { ["runtime-id"]=> string(36) "%s" - } - ["metrics"]=> - array(6) { + ["process_id"]=> + float(%f) ["_dd.agent_psr"]=> float(1) - ["_sampling_priority_v1"]=> - float(1) ["php.compilation.total_time_ms"]=> float(%f) - ["php.memory.peak_real_usage_bytes"]=> - float(%f) ["php.memory.peak_usage_bytes"]=> float(%f) - ["process_id"]=> + ["php.memory.peak_real_usage_bytes"]=> float(%f) } } diff --git a/tests/ext/distributed_tracing/distributed_trace_inherit.phpt b/tests/ext/distributed_tracing/distributed_trace_inherit.phpt index 433d4c1ef8..dba77a081c 100644 --- a/tests/ext/distributed_tracing/distributed_trace_inherit.phpt +++ b/tests/ext/distributed_tracing/distributed_trace_inherit.phpt @@ -27,7 +27,7 @@ var_dump(dd_clean_spans()); --EXPECTF-- array(2) { [0]=> - array(11) { + array(13) { ["trace_id"]=> string(2) "42" ["span_id"]=> @@ -46,37 +46,34 @@ array(2) { string(29) "distributed_trace_inherit.php" ["type"]=> string(3) "cli" - ["meta"]=> - array(6) { - ["_dd.origin"]=> - string(7) "datadog" + ["sampling_priority"]=> + int(3) + ["sampling_mechanism"]=> + int(0) + ["origin"]=> + string(7) "datadog" + ["attributes"]=> + array(8) { ["_dd.p.custom_tag"]=> string(9) "inherited" - ["_dd.p.dm"]=> - string(2) "-0" - ["_dd.p.other_tag"]=> - string(4) "also" ["_dd.propagation_error"]=> string(14) "decoding_error" + ["_dd.p.other_tag"]=> + string(4) "also" ["runtime-id"]=> string(36) "%s" - } - ["metrics"]=> - array(5) { - ["_sampling_priority_v1"]=> - float(3) - ["php.compilation.total_time_ms"]=> + ["process_id"]=> float(%f) - ["php.memory.peak_real_usage_bytes"]=> + ["php.compilation.total_time_ms"]=> float(%f) ["php.memory.peak_usage_bytes"]=> float(%f) - ["process_id"]=> + ["php.memory.peak_real_usage_bytes"]=> float(%f) } } [1]=> - array(10) { + array(9) { ["trace_id"]=> string(2) "42" ["span_id"]=> @@ -95,10 +92,5 @@ array(2) { string(29) "distributed_trace_inherit.php" ["type"]=> string(3) "cli" - ["meta"]=> - array(1) { - ["_dd.origin"]=> - string(7) "datadog" - } } } diff --git a/tests/ext/distributed_tracing/distributed_trace_overwrite_active_span.phpt b/tests/ext/distributed_tracing/distributed_trace_overwrite_active_span.phpt index 10bc4e9a01..61b4a9eb80 100644 --- a/tests/ext/distributed_tracing/distributed_trace_overwrite_active_span.phpt +++ b/tests/ext/distributed_tracing/distributed_trace_overwrite_active_span.phpt @@ -41,8 +41,23 @@ function largeBaseConvert($numString, $fromBase, $toBase) function dump_spans() { foreach (dd_trace_serialize_closed_spans() as $span) { - unset($span["meta"]["process_id"], $span["meta"]["runtime-id"], $span["meta"]["_dd.p.dm"], $span["meta"]["_dd.tags.process"], $span["meta"]["_dd.sdk.otlp_export"]); - echo "parent: ", $span["parent_id"] ?? 0, ", trace: {$span["trace_id"]}, meta: " . json_encode($span["meta"] ?? []) . "\n"; + $meta = $span["attributes"] ?? []; + unset( + $meta["process_id"], $meta["runtime-id"], $meta["_dd.p.dm"], $meta["_dd.tags.process"], $meta["_dd.sdk.otlp_export"], + $meta["_dd.agent_psr"], $meta["php.compilation.total_time_ms"], + $meta["php.memory.peak_usage_bytes"], $meta["php.memory.peak_real_usage_bytes"] + ); + // origin and the 128-bit trace id high bits are promoted to dedicated top-level + // fields in the v1 shape rather than living in attributes. + $promoted = []; + if (isset($span["origin"])) { + $promoted["_dd.origin"] = $span["origin"]; + } + if (isset($span["trace_id_high"])) { + $promoted["_dd.p.tid"] = $span["trace_id_high"]; + } + $meta = array_merge($promoted, $meta); + echo "parent: ", $span["parent_id"] ?? 0, ", trace: {$span["trace_id"]}, meta: " . json_encode($meta) . "\n"; } return $span; } @@ -98,7 +113,7 @@ array(7) { } bool(true) parent: 321, trace: 123, meta: {"_dd.origin":"foo","a":"b"} -parent: %d, trace: 123, meta: {"_dd.origin":"foo"} +parent: %d, trace: 123, meta: [] bool(true) array(5) { ["trace_id"]=> diff --git a/tests/ext/do_not_check_if_class_or_function_exists_by_default.phpt b/tests/ext/do_not_check_if_class_or_function_exists_by_default.phpt index f094385b51..fe26a0e685 100644 --- a/tests/ext/do_not_check_if_class_or_function_exists_by_default.phpt +++ b/tests/ext/do_not_check_if_class_or_function_exists_by_default.phpt @@ -1,7 +1,5 @@ --TEST-- Do not throw exceptions when veryfying if class/method and function exists. ---ENV-- -DD_TRACE_WARN_LEGACY_DD_TRACE=0 --FILE-- name = "http.request"; +$s->service = "web"; +\DDTrace\close_span(); + +$spans = dd_trace_serialize_closed_spans(); +$root = $spans[0]; +// env/version promoted from the DD_TAGS-sourced meta fallback; deleted from the unified +// attributes map once promoted to the dedicated top-level fields. +echo "env=" . var_export($root["env"] ?? null, true) . "\n"; +echo "version=" . var_export($root["version"] ?? null, true) . "\n"; +echo "attributes.env=" . var_export($root["attributes"]["env"] ?? null, true) . "\n"; +echo "attributes.version=" . var_export($root["attributes"]["version"] ?? null, true) . "\n"; +?> +--EXPECT-- +env='staging' +version='1.2.3' +attributes.env=NULL +attributes.version=NULL diff --git a/tests/ext/extract_ip_private_01.phpt b/tests/ext/extract_ip_private_01.phpt index 4362f7ecae..435145953d 100644 --- a/tests/ext/extract_ip_private_01.phpt +++ b/tests/ext/extract_ip_private_01.phpt @@ -11,7 +11,7 @@ DD_TRACE_CLIENT_IP_ENABLED=true DDTrace\start_span(); DDTrace\close_span(0); $span = dd_trace_serialize_closed_spans(); -var_dump($span[0]["meta"]["http.client_ip"]); +var_dump($span[0]["attributes"]["http.client_ip"]); ?> --EXPECTF-- string(7) "7.7.7.7" diff --git a/tests/ext/extract_server_values.phpt b/tests/ext/extract_server_values.phpt index 69d8ad24e0..f503b5beb5 100644 --- a/tests/ext/extract_server_values.phpt +++ b/tests/ext/extract_server_values.phpt @@ -27,21 +27,8 @@ if (!isset($_SERVER[0])) { DDTrace\start_span(); DDTrace\close_span(); -var_dump(dd_trace_serialize_closed_spans()[0]["meta"]); +var_dump(dd_trace_serialize_closed_spans()[0]["attributes"]["http.request.headers.0"]); ?> ---EXPECTF-- -array(6) { - ["_dd.p.dm"]=> - string(2) "-0" - ["_dd.p.tid"]=> - string(16) "%s" - ["_dd.sdk.otlp_export"]=> - string(5) "false" - ["_dd.tags.process"]=> - string(%d) "%s" - ["http.request.headers.0"]=> - string(16) "http_zero_header" - ["runtime-id"]=> - string(36) "%s" -} +--EXPECT-- +string(16) "http_zero_header" diff --git a/tests/ext/fibers/fiber_observer_bailout.phpt b/tests/ext/fibers/fiber_observer_bailout.phpt index 277de4a684..244566b792 100644 --- a/tests/ext/fibers/fiber_observer_bailout.phpt +++ b/tests/ext/fibers/fiber_observer_bailout.phpt @@ -46,22 +46,20 @@ Fatal error: Allowed memory size of %d bytes exhausted %s in %s on line %d inFiber posthook spans(\DDTrace\SpanData) (1) { fiber_observer_bailout.php (fiber_observer_bailout.php, fiber_observer_bailout.php, cli) (error: Allowed memory size of %d bytes exhausted %s) - _dd.p.dm => -0 - _dd.p.tid => %s + error.type => E_ERROR error.message => Allowed memory size of %d bytes exhausted %s error.stack => #0 %s(%d): str_repeat() #1 [internal function]: inFiber() #2 %s(%d): Fiber->resume() #3 %s(%d): outer() #4 {main} - error.type => E_ERROR inFiber (fiber_observer_bailout.php, inFiber, cli) (error: Allowed memory size of %d bytes exhausted %s) + error.type => E_ERROR error.message => Allowed memory size of %d bytes exhausted %s error.stack => #0 %s(%d): str_repeat() #1 [internal function]: inFiber() #2 %s(%d): Fiber->resume() #3 %s(%d): outer() #4 {main} - error.type => E_ERROR outer (fiber_observer_bailout.php, outer, cli) } diff --git a/tests/ext/fibers/fiber_stack_switch.phpt b/tests/ext/fibers/fiber_stack_switch.phpt index 5c2118ecce..189e9a1d11 100644 --- a/tests/ext/fibers/fiber_stack_switch.phpt +++ b/tests/ext/fibers/fiber_stack_switch.phpt @@ -79,23 +79,21 @@ Hook: Fiber->resume Caught ex spans(\DDTrace\SpanData) (1) { fiber_stack_switch.php (fiber_stack_switch.php, fiber_stack_switch.php, cli) - _dd.p.dm => -0 - _dd.p.tid => %s Fiber.start (fiber_stack_switch.php, Fiber.start, cli) inFiber (fiber_stack_switch.php, inFiber, cli) otherFiber (fiber_stack_switch.php, otherFiber, cli) (error: Thrown Exception: ex in %s:%d) error.message => Thrown Exception: ex in %s:%d + error.type => Exception error.stack => #0 [internal function]: otherFiber() #1 %s(%d): Fiber->resume() #2 {main} - error.type => Exception Fiber.suspend (fiber_stack_switch.php, Fiber.suspend, cli) Fiber.suspend (fiber_stack_switch.php, Fiber.suspend, cli) Fiber.resume (fiber_stack_switch.php, Fiber.resume, cli) Fiber.resume (fiber_stack_switch.php, Fiber.resume, cli) (error: Thrown Exception: ex in %s:%d) error.message => Thrown Exception: ex in %s:%d + error.type => Exception error.stack => #0 [internal function]: otherFiber() #1 %s(%d): Fiber->resume() #2 {main} - error.type => Exception } \ No newline at end of file diff --git a/tests/ext/flush-autofinish.phpt b/tests/ext/flush-autofinish.phpt index e890e93647..a7595aa10a 100644 --- a/tests/ext/flush-autofinish.phpt +++ b/tests/ext/flush-autofinish.phpt @@ -17,7 +17,7 @@ var_dump(DDTrace\active_span() != null); ?> --EXPECTF-- -[ddtrace] [info] [%d] Flushing trace of size 2 to send-queue for %s +[ddtrace] [info] [%d] Flushing v1 trace of size 2 to send-queue for %s bool(true) bool(true) -[ddtrace] [info] [%d] Flushing trace of size 1 to send-queue for %s +[ddtrace] [info] [%d] Flushing v1 trace of size 1 to send-queue for %s diff --git a/tests/ext/force_flush_traces.phpt b/tests/ext/force_flush_traces.phpt index 252758568b..e3b5d8bd43 100644 --- a/tests/ext/force_flush_traces.phpt +++ b/tests/ext/force_flush_traces.phpt @@ -44,5 +44,5 @@ var_dump(dd_trace_serialize_closed_spans()); // Spans should be flushed, so this --EXPECTF-- tracing process process -[ddtrace] [info] [%d] Flushing trace of size %r2.*\n.*1|3%r to send-queue for %s +[ddtrace] [info] [%d] Flushing v1 trace of size %r2.*\n.*1|3%r to send-queue for %s kill%r\n*(Killed\n*)?(Termsig=9)?%r diff --git a/tests/ext/generate_128_bit_trace_id.phpt b/tests/ext/generate_128_bit_trace_id.phpt index ccad1e18a0..f0246e5adf 100644 --- a/tests/ext/generate_128_bit_trace_id.phpt +++ b/tests/ext/generate_128_bit_trace_id.phpt @@ -26,8 +26,8 @@ var_dump(\DDTrace\trace_id() < 2 ** 64); DDTrace\close_span(); $spans = dd_trace_serialize_closed_spans(); -var_dump(!isset($spans[0]["meta"]["_dd.p.tid"])); -var_dump(hexdec($spans[1]["meta"]["_dd.p.tid"]) == floor($spans[1]["start"] / 1000000000) * (1 << 32)); +var_dump(!isset($spans[0]["trace_id_high"])); +var_dump(hexdec($spans[1]["trace_id_high"]) == floor($spans[1]["start"] / 1000000000) * (1 << 32)); ?> --EXPECT-- diff --git a/tests/ext/http_endpoint_resource_renaming_always_simplified.phpt b/tests/ext/http_endpoint_resource_renaming_always_simplified.phpt index 475f420dd3..b4e38dc14f 100644 --- a/tests/ext/http_endpoint_resource_renaming_always_simplified.phpt +++ b/tests/ext/http_endpoint_resource_renaming_always_simplified.phpt @@ -30,13 +30,13 @@ function test_endpoint_with_route($path, $route) { } else { echo "Path: ", $path, ", No Route\n"; } - if (isset($span_data['meta']['http.endpoint'])) { - echo "Endpoint: ", $span_data['meta']['http.endpoint'], "\n"; + if (isset($span_data['attributes']['http.endpoint'])) { + echo "Endpoint: ", $span_data['attributes']['http.endpoint'], "\n"; } else { echo "Endpoint: (not set)\n"; } - if (isset($span_data['meta']['http.route'])) { - echo "Route: ", $span_data['meta']['http.route'], "\n"; + if (isset($span_data['attributes']['http.route'])) { + echo "Route: ", $span_data['attributes']['http.route'], "\n"; } else { echo "Route: (not set)\n"; } diff --git a/tests/ext/http_endpoint_resource_renaming_basic.phpt b/tests/ext/http_endpoint_resource_renaming_basic.phpt index 745924ce7e..90632a5089 100644 --- a/tests/ext/http_endpoint_resource_renaming_basic.phpt +++ b/tests/ext/http_endpoint_resource_renaming_basic.phpt @@ -23,8 +23,8 @@ function test_endpoint($path) { if (count($spans) > 0) { $span_data = $spans[0]; echo "Path: $path\n"; - if (isset($span_data['meta']['http.endpoint'])) { - echo "Endpoint: " . $span_data['meta']['http.endpoint'] . "\n"; + if (isset($span_data['attributes']['http.endpoint'])) { + echo "Endpoint: " . $span_data['attributes']['http.endpoint'] . "\n"; } else { echo "Endpoint: (not set)\n"; } @@ -32,7 +32,6 @@ function test_endpoint($path) { } else { echo "Path: $path - No spans\n\n"; } - dd_trace_reset(); } // Test invalid inputs and root @@ -95,8 +94,8 @@ function test_endpoint_with_route($path, $route) { if (count($spans) > 0) { $span_data = $spans[0]; echo "Path: $path, Route: $route\n"; - if (isset($span_data['meta']['http.endpoint'])) { - echo "Endpoint: " . $span_data['meta']['http.endpoint'] . "\n"; + if (isset($span_data['attributes']['http.endpoint'])) { + echo "Endpoint: " . $span_data['attributes']['http.endpoint'] . "\n"; } else { echo "Endpoint: (not set)\n"; } diff --git a/tests/ext/includes/fake_tracer.inc b/tests/ext/includes/fake_tracer.inc index e9a98bf25b..a3f080ee95 100644 --- a/tests/ext/includes/fake_tracer.inc +++ b/tests/ext/includes/fake_tracer.inc @@ -26,8 +26,8 @@ class Tracer if (!empty($values)) { $valuesString .= ' (' . implode(', ', $values) . ')'; } - if (isset($span['meta']['error.message'])) { - $valuesString .= ' (error: ' . $span['meta']['error.message'] . ')'; + if (isset($span['attributes']['error.message'])) { + $valuesString .= ' (error: ' . $span['attributes']['error.message'] . ')'; } $valuesString .= PHP_EOL; if (strlen($valuesString) > 0) { diff --git a/tests/ext/inferred_proxy/alter_service.phpt b/tests/ext/inferred_proxy/alter_service.phpt index 419335cf09..710e509a4c 100644 --- a/tests/ext/inferred_proxy/alter_service.phpt +++ b/tests/ext/inferred_proxy/alter_service.phpt @@ -51,24 +51,24 @@ echo json_encode(dd_clean_spans(), JSON_PRETTY_PRINT); "resource": "GET \/foo", "service": "aws-server", "type": "web", - "meta": { - "env": "local-prod", + "env": "local-prod", + "version": "1.0", + "component": "cgi-fcgi", + "span_kind": 2, + "attributes": { + "runtime-id": "%s", + "http.url": "http:\/\/localhost:8888\/foo", "http.method": "GET", + "process_id": %d, "http.status_code": "200", - "http.url": "http:\/\/localhost:8888\/foo", - "runtime-id": "%s", - "span.kind": "server", - "version": "1.0" - }, - "metrics": { "php.compilation.total_time_ms": %f, - "php.memory.peak_real_usage_bytes": %d, "php.memory.peak_usage_bytes": %d, - "process_id": %d + "php.memory.peak_real_usage_bytes": %d } }, { "trace_id": "13930160852258120406", + "trace_id_high": "%s", "span_id": "11788048577503494824", "start": 100000000, "duration": %d, @@ -76,21 +76,18 @@ echo json_encode(dd_clean_spans(), JSON_PRETTY_PRINT); "resource": "GET \/test", "service": "example.com", "type": "web", - "meta": { - "_dd.p.dm": "-0", - "_dd.p.tid": "%s", - "component": "aws-apigateway", - "env": "local-prod", + "env": "local-prod", + "version": "1.0", + "component": "aws-apigateway", + "sampling_priority": 1, + "sampling_mechanism": 0, + "attributes": { "http.method": "GET", - "http.status_code": "200", "http.url": "example.com\/test", "stage": "aws-prod", - "version": "1.0" - }, - "metrics": { - "_dd.agent_psr": 1, "_dd.inferred_span": 1, - "_sampling_priority_v1": 1 + "http.status_code": "200", + "_dd.agent_psr": 1 } }, { @@ -103,9 +100,7 @@ echo json_encode(dd_clean_spans(), JSON_PRETTY_PRINT); "resource": "child", "service": "aws-server", "type": "web", - "meta": { - "env": "local-prod", - "version": "1.0" - } + "env": "local-prod", + "version": "1.0" } -] \ No newline at end of file +] diff --git a/tests/ext/inferred_proxy/basic_test.phpt b/tests/ext/inferred_proxy/basic_test.phpt index b8fc62939f..331851110d 100644 --- a/tests/ext/inferred_proxy/basic_test.phpt +++ b/tests/ext/inferred_proxy/basic_test.phpt @@ -68,25 +68,25 @@ if ($percentageDifference > 0.01) { // 0.01% difference for the sake of the test "resource": "GET \/foo", "service": "aws-server", "type": "web", - "meta": { - "env": "local-prod", - "foo": "bar", + "env": "local-prod", + "version": "1.0", + "component": "cgi-fcgi", + "span_kind": 2, + "attributes": { + "runtime-id": "%s", + "http.url": "http:\/\/localhost:8888\/foo", "http.method": "GET", + "process_id": %d, + "foo": "bar", "http.status_code": "200", - "http.url": "http:\/\/localhost:8888\/foo", - "runtime-id": "%s", - "span.kind": "server", - "version": "1.0" - }, - "metrics": { "php.compilation.total_time_ms": %f, - "php.memory.peak_real_usage_bytes": %d, "php.memory.peak_usage_bytes": %d, - "process_id": %d + "php.memory.peak_real_usage_bytes": %d } }, { "trace_id": "13930160852258120406", + "trace_id_high": "%s", "span_id": "11788048577503494824", "start": 1742285908783000000, "duration": %d, @@ -94,21 +94,18 @@ if ($percentageDifference > 0.01) { // 0.01% difference for the sake of the test "resource": "GET \/test", "service": "example.com", "type": "web", - "meta": { - "_dd.p.dm": "-0", - "_dd.p.tid": "%s", - "component": "aws-apigateway", - "env": "local-prod", + "env": "local-prod", + "version": "1.0", + "component": "aws-apigateway", + "sampling_priority": 1, + "sampling_mechanism": 0, + "attributes": { "http.method": "GET", - "http.status_code": "200", "http.url": "example.com\/test", "stage": "aws-prod", - "version": "1.0" - }, - "metrics": { - "_dd.agent_psr": 1, "_dd.inferred_span": 1, - "_sampling_priority_v1": 1 + "http.status_code": "200", + "_dd.agent_psr": 1 } }, { @@ -121,9 +118,7 @@ if ($percentageDifference > 0.01) { // 0.01% difference for the sake of the test "resource": "child", "service": "aws-server", "type": "web", - "meta": { - "env": "local-prod", - "version": "1.0" - } + "env": "local-prod", + "version": "1.0" } -]Duration is within 0.01% of expected duration \ No newline at end of file +]Duration is within 0.01% of expected duration diff --git a/tests/ext/inferred_proxy/consume_distributed_tracing_headers.phpt b/tests/ext/inferred_proxy/consume_distributed_tracing_headers.phpt index 4023bf9f6b..f6da750f55 100644 --- a/tests/ext/inferred_proxy/consume_distributed_tracing_headers.phpt +++ b/tests/ext/inferred_proxy/consume_distributed_tracing_headers.phpt @@ -56,21 +56,20 @@ echo json_encode(dd_clean_spans(), JSON_PRETTY_PRINT); "resource": "consume_distributed_tracing_headers.php", "service": "aws-server", "type": "cli", - "meta": { - "env": "local-prod", - "http.url": "http:\/\/localhost:8888\/foo", + "env": "local-prod", + "version": "1.0", + "attributes": { "runtime-id": "%s", - "version": "1.0" - }, - "metrics": { + "http.url": "http:\/\/localhost:8888\/foo", + "process_id": %d, "php.compilation.total_time_ms": %f, - "php.memory.peak_real_usage_bytes": %d, "php.memory.peak_usage_bytes": %d, - "process_id": %d + "php.memory.peak_real_usage_bytes": %d } }, { "trace_id": "13930160852258120406", + "trace_id_high": "%s", "span_id": "11788048577503494824", "start": %d, "duration": %d, @@ -78,20 +77,17 @@ echo json_encode(dd_clean_spans(), JSON_PRETTY_PRINT); "resource": "GET \/test", "service": "example.com", "type": "web", - "meta": { - "_dd.p.dm": "-0", - "_dd.p.tid": "%s", - "component": "aws-apigateway", - "env": "local-prod", + "env": "local-prod", + "version": "1.0", + "component": "aws-apigateway", + "sampling_priority": 1, + "sampling_mechanism": 0, + "attributes": { "http.method": "GET", "http.url": "example.com\/test", "stage": "aws-prod", - "version": "1.0" - }, - "metrics": { - "_dd.agent_psr": 1, "_dd.inferred_span": 1, - "_sampling_priority_v1": 1 + "_dd.agent_psr": 1 } }, { @@ -104,9 +100,7 @@ echo json_encode(dd_clean_spans(), JSON_PRETTY_PRINT); "resource": "child", "service": "aws-server", "type": "cli", - "meta": { - "env": "local-prod", - "version": "1.0" - } + "env": "local-prod", + "version": "1.0" } -] \ No newline at end of file +] diff --git a/tests/ext/inferred_proxy/distributed_tracing.phpt b/tests/ext/inferred_proxy/distributed_tracing.phpt index be481d60c1..eb29334b90 100644 --- a/tests/ext/inferred_proxy/distributed_tracing.phpt +++ b/tests/ext/inferred_proxy/distributed_tracing.phpt @@ -58,22 +58,20 @@ echo json_encode(dd_clean_spans(), JSON_PRETTY_PRINT); "resource": "GET \/foo", "service": "aws-server", "type": "web", - "meta": { - "_dd.origin": "rum", - "env": "local-prod", - "foo": "bar", + "env": "local-prod", + "version": "1.0", + "component": "cgi-fcgi", + "span_kind": 2, + "attributes": { + "runtime-id": "%s", + "http.url": "http:\/\/localhost:8888\/foo", "http.method": "GET", + "process_id": %d, + "foo": "bar", "http.status_code": "200", - "http.url": "http:\/\/localhost:8888\/foo", - "runtime-id": "%s", - "span.kind": "server", - "version": "1.0" - }, - "metrics": { "php.compilation.total_time_ms": %f, - "php.memory.peak_real_usage_bytes": %d, "php.memory.peak_usage_bytes": %d, - "process_id": %d + "php.memory.peak_real_usage_bytes": %d } }, { @@ -86,21 +84,18 @@ echo json_encode(dd_clean_spans(), JSON_PRETTY_PRINT); "resource": "GET \/test", "service": "example.com", "type": "web", - "meta": { - "_dd.origin": "rum", - "_dd.p.dm": "-0", - "_dd.p.tid": "0", - "component": "aws-apigateway", - "env": "local-prod", + "env": "local-prod", + "version": "1.0", + "component": "aws-apigateway", + "sampling_priority": 2, + "sampling_mechanism": 0, + "origin": "rum", + "attributes": { "http.method": "GET", - "http.status_code": "200", "http.url": "example.com\/test", "stage": "aws-prod", - "version": "1.0" - }, - "metrics": { "_dd.inferred_span": 1, - "_sampling_priority_v1": 2 + "http.status_code": "200" } }, { @@ -113,10 +108,7 @@ echo json_encode(dd_clean_spans(), JSON_PRETTY_PRINT); "resource": "child", "service": "aws-server", "type": "web", - "meta": { - "_dd.origin": "rum", - "env": "local-prod", - "version": "1.0" - } + "env": "local-prod", + "version": "1.0" } -] \ No newline at end of file +] diff --git a/tests/ext/inferred_proxy/error_propagated.phpt b/tests/ext/inferred_proxy/error_propagated.phpt index 7d7c98d39b..59c066fbad 100644 --- a/tests/ext/inferred_proxy/error_propagated.phpt +++ b/tests/ext/inferred_proxy/error_propagated.phpt @@ -61,27 +61,27 @@ echo json_encode(dd_clean_spans(), JSON_PRETTY_PRINT); "service": "aws-server", "type": "web", "error": 1, - "meta": { - "env": "local-prod", - "error.message": "Uncaught Exception (500): An exception occurred in %serror_propagated.php:%d", - "error.stack": "#0 %serror_propagated.php(%d): oops()\n#1 {main}", - "error.type": "Exception", + "env": "local-prod", + "version": "1.0", + "component": "cgi-fcgi", + "span_kind": 2, + "attributes": { + "runtime-id": "%s", + "http.url": "http:\/\/localhost:8888\/foo", "http.method": "GET", + "process_id": %d, "http.status_code": "500", - "http.url": "http:\/\/localhost:8888\/foo", - "runtime-id": "%s", - "span.kind": "server", - "version": "1.0" - }, - "metrics": { + "error.type": "Exception", + "error.message": "Uncaught Exception (500): An exception occurred in %serror_propagated.php:%d", + "error.stack": "#0 %serror_propagated.php(%d): oops()\n#1 {main}", "php.compilation.total_time_ms": %f, - "php.memory.peak_real_usage_bytes": %d, "php.memory.peak_usage_bytes": %d, - "process_id": %d + "php.memory.peak_real_usage_bytes": %d } }, { "trace_id": "13930160852258120406", + "trace_id_high": "%s", "span_id": "11788048577503494824", "start": 100000000, "duration": %d, @@ -90,24 +90,21 @@ echo json_encode(dd_clean_spans(), JSON_PRETTY_PRINT); "service": "example.com", "type": "web", "error": 1, - "meta": { - "_dd.p.dm": "-0", - "_dd.p.tid": "%s", - "component": "aws-apigateway", - "env": "local-prod", - "error.message": "Uncaught Exception (500): An exception occurred in %serror_propagated.php:%d", - "error.stack": "#0 %serror_propagated.php(%d): oops()\n#1 {main}", - "error.type": "Exception", + "env": "local-prod", + "version": "1.0", + "component": "aws-apigateway", + "sampling_priority": 1, + "sampling_mechanism": 0, + "attributes": { "http.method": "GET", - "http.status_code": "500", "http.url": "example.com\/test", "stage": "aws-prod", - "version": "1.0" - }, - "metrics": { - "_dd.agent_psr": 1, "_dd.inferred_span": 1, - "_sampling_priority_v1": 1 + "http.status_code": "500", + "error.type": "Exception", + "_dd.agent_psr": 1, + "error.message": "Uncaught Exception (500): An exception occurred in %serror_propagated.php:%d", + "error.stack": "#0 %serror_propagated.php(%d): oops()\n#1 {main}" } } -] \ No newline at end of file +] diff --git a/tests/ext/inferred_proxy/fallback_service_name.phpt b/tests/ext/inferred_proxy/fallback_service_name.phpt index 8b9cfe1d24..970b47ce63 100644 --- a/tests/ext/inferred_proxy/fallback_service_name.phpt +++ b/tests/ext/inferred_proxy/fallback_service_name.phpt @@ -52,25 +52,25 @@ echo json_encode(dd_clean_spans(), JSON_PRETTY_PRINT); "resource": "GET \/foo", "service": "aws-server", "type": "web", - "meta": { - "env": "local-prod", - "foo": "bar", + "env": "local-prod", + "version": "1.0", + "component": "cgi-fcgi", + "span_kind": 2, + "attributes": { + "runtime-id": "%s", + "http.url": "http:\/\/localhost:8888\/foo", "http.method": "GET", + "process_id": %d, + "foo": "bar", "http.status_code": "200", - "http.url": "http:\/\/localhost:8888\/foo", - "runtime-id": "%s", - "span.kind": "server", - "version": "1.0" - }, - "metrics": { "php.compilation.total_time_ms": %f, - "php.memory.peak_real_usage_bytes": %d, "php.memory.peak_usage_bytes": %d, - "process_id": %d + "php.memory.peak_real_usage_bytes": %d } }, { "trace_id": "13930160852258120406", + "trace_id_high": "%s", "span_id": "11788048577503494824", "start": 100000000, "duration": %d, @@ -78,20 +78,17 @@ echo json_encode(dd_clean_spans(), JSON_PRETTY_PRINT); "resource": "GET \/test", "service": "aws-server", "type": "web", - "meta": { - "_dd.p.dm": "-0", - "_dd.p.tid": "%s", - "component": "aws-apigateway", - "env": "local-prod", + "env": "local-prod", + "version": "1.0", + "component": "aws-apigateway", + "sampling_priority": 1, + "sampling_mechanism": 0, + "attributes": { "http.method": "GET", - "http.status_code": "200", "stage": "aws-prod", - "version": "1.0" - }, - "metrics": { - "_dd.agent_psr": 1, "_dd.inferred_span": 1, - "_sampling_priority_v1": 1 + "http.status_code": "200", + "_dd.agent_psr": 1 } }, { @@ -104,9 +101,7 @@ echo json_encode(dd_clean_spans(), JSON_PRETTY_PRINT); "resource": "child", "service": "aws-server", "type": "web", - "meta": { - "env": "local-prod", - "version": "1.0" - } + "env": "local-prod", + "version": "1.0" } -] \ No newline at end of file +] diff --git a/tests/ext/inferred_proxy/incomplete_headers.phpt b/tests/ext/inferred_proxy/incomplete_headers.phpt index 2ca50170b2..900be82425 100644 --- a/tests/ext/inferred_proxy/incomplete_headers.phpt +++ b/tests/ext/inferred_proxy/incomplete_headers.phpt @@ -37,6 +37,7 @@ echo json_encode(dd_clean_spans(), JSON_PRETTY_PRINT); [ { "trace_id": "13930160852258120406", + "trace_id_high": "%s", "span_id": "13930160852258120406", "start": 120000000, "duration": %d, @@ -44,27 +45,25 @@ echo json_encode(dd_clean_spans(), JSON_PRETTY_PRINT); "resource": "GET \/foo", "service": "aws-server", "type": "web", - "meta": { + "env": "local-prod", + "version": "1.0", + "component": "cgi-fcgi", + "span_kind": 2, + "sampling_priority": 1, + "sampling_mechanism": 0, + "attributes": { + "runtime-id": "%s", + "http.url": "http:\/\/localhost:8888\/foo", + "http.method": "GET", + "process_id": %d, + "_dd.code_origin.type": "entry", "_dd.code_origin.frames.0.file": "%sincomplete_headers.php", "_dd.code_origin.frames.0.line": "1", - "_dd.code_origin.type": "entry", - "_dd.p.dm": "-0", - "_dd.p.tid": "%s", - "env": "local-prod", - "http.method": "GET", - "http.status_code": "200", - "http.url": "http:\/\/localhost:8888\/foo", - "runtime-id": "%s", - "span.kind": "server", - "version": "1.0" - }, - "metrics": { "_dd.agent_psr": 1, - "_sampling_priority_v1": 1, + "http.status_code": "200", "php.compilation.total_time_ms": %f, - "php.memory.peak_real_usage_bytes": %d, "php.memory.peak_usage_bytes": %d, - "process_id": %d + "php.memory.peak_real_usage_bytes": %d } }, { @@ -77,9 +76,7 @@ echo json_encode(dd_clean_spans(), JSON_PRETTY_PRINT); "resource": "child", "service": "aws-server", "type": "web", - "meta": { - "env": "local-prod", - "version": "1.0" - } + "env": "local-prod", + "version": "1.0" } -] \ No newline at end of file +] diff --git a/tests/ext/inferred_proxy/multiple_traces.phpt b/tests/ext/inferred_proxy/multiple_traces.phpt index 8038c2de48..85f9bb7828 100644 --- a/tests/ext/inferred_proxy/multiple_traces.phpt +++ b/tests/ext/inferred_proxy/multiple_traces.phpt @@ -47,6 +47,7 @@ echo json_encode(dd_clean_spans(), JSON_PRETTY_PRINT); [ { "trace_id": "2513787319205155662", + "trace_id_high": "%s", "span_id": "2513787319205155662", "start": %d, "duration": %d, @@ -54,24 +55,22 @@ echo json_encode(dd_clean_spans(), JSON_PRETTY_PRINT); "resource": "GET \/foo", "service": "aws-server", "type": "web", - "meta": { - "_dd.p.dm": "-0", - "_dd.p.tid": "%s", - "env": "local-prod", - "http.method": "GET", - "http.status_code": "200", - "http.url": "http:\/\/localhost:8888\/foo", + "env": "local-prod", + "version": "1.0", + "component": "cgi-fcgi", + "span_kind": 2, + "sampling_priority": 1, + "sampling_mechanism": 0, + "attributes": { "runtime-id": "%s", - "span.kind": "server", - "version": "1.0" - }, - "metrics": { + "http.url": "http:\/\/localhost:8888\/foo", + "http.method": "GET", + "process_id": %d, "_dd.agent_psr": 1, - "_sampling_priority_v1": 1, + "http.status_code": "200", "php.compilation.total_time_ms": %f, - "php.memory.peak_real_usage_bytes": %d, "php.memory.peak_usage_bytes": %d, - "process_id": %d + "php.memory.peak_real_usage_bytes": %d } }, { @@ -84,24 +83,24 @@ echo json_encode(dd_clean_spans(), JSON_PRETTY_PRINT); "resource": "GET \/foo", "service": "aws-server", "type": "web", - "meta": { - "env": "local-prod", + "env": "local-prod", + "version": "1.0", + "component": "cgi-fcgi", + "span_kind": 2, + "attributes": { + "runtime-id": "%s", + "http.url": "http:\/\/localhost:8888\/foo", "http.method": "GET", + "process_id": %d, "http.status_code": "200", - "http.url": "http:\/\/localhost:8888\/foo", - "runtime-id": "%s", - "span.kind": "server", - "version": "1.0" - }, - "metrics": { "php.compilation.total_time_ms": %f, - "php.memory.peak_real_usage_bytes": %d, "php.memory.peak_usage_bytes": %d, - "process_id": %d + "php.memory.peak_real_usage_bytes": %d } }, { "trace_id": "13930160852258120406", + "trace_id_high": "%s", "span_id": "11788048577503494824", "start": 100000000, "duration": %d, @@ -109,21 +108,18 @@ echo json_encode(dd_clean_spans(), JSON_PRETTY_PRINT); "resource": "GET \/test", "service": "example.com", "type": "web", - "meta": { - "_dd.p.dm": "-0", - "_dd.p.tid": "%s", - "component": "aws-apigateway", - "env": "local-prod", + "env": "local-prod", + "version": "1.0", + "component": "aws-apigateway", + "sampling_priority": 1, + "sampling_mechanism": 0, + "attributes": { "http.method": "GET", - "http.status_code": "200", "http.url": "example.com\/test", "stage": "aws-prod", - "version": "1.0" - }, - "metrics": { - "_dd.agent_psr": 1, "_dd.inferred_span": 1, - "_sampling_priority_v1": 1 + "http.status_code": "200", + "_dd.agent_psr": 1 } }, { @@ -136,9 +132,7 @@ echo json_encode(dd_clean_spans(), JSON_PRETTY_PRINT); "resource": "child", "service": "aws-server", "type": "web", - "meta": { - "env": "local-prod", - "version": "1.0" - } + "env": "local-prod", + "version": "1.0" } -] \ No newline at end of file +] diff --git a/tests/ext/inferred_proxy/propagated_tags_after_span_start.phpt b/tests/ext/inferred_proxy/propagated_tags_after_span_start.phpt index 60bca93566..c9ddbba259 100644 --- a/tests/ext/inferred_proxy/propagated_tags_after_span_start.phpt +++ b/tests/ext/inferred_proxy/propagated_tags_after_span_start.phpt @@ -55,23 +55,21 @@ echo json_encode(dd_clean_spans(), JSON_PRETTY_PRINT); "resource": "GET \/foo", "service": "aws-server", "type": "web", - "meta": { - "_dd.origin": "rum", - "_dd.p.usr.id": "12345", - "_dd.parent_id": "00000000000000bb", - "env": "local-prod", + "env": "local-prod", + "version": "1.0", + "component": "cgi-fcgi", + "span_kind": 2, + "attributes": { + "runtime-id": "%s", + "http.url": "http:\/\/localhost:8888\/foo", "http.method": "GET", + "process_id": %d, + "_dd.parent_id": "00000000000000bb", + "_dd.p.usr.id": "12345", "http.status_code": "200", - "http.url": "http:\/\/localhost:8888\/foo", - "runtime-id": "%s", - "span.kind": "server", - "version": "1.0" - }, - "metrics": { "php.compilation.total_time_ms": %f, - "php.memory.peak_real_usage_bytes": %d, "php.memory.peak_usage_bytes": %d, - "process_id": %d + "php.memory.peak_real_usage_bytes": %d } }, { @@ -84,23 +82,20 @@ echo json_encode(dd_clean_spans(), JSON_PRETTY_PRINT); "resource": "GET \/test", "service": "example.com", "type": "web", - "meta": { - "_dd.origin": "rum", - "_dd.p.dm": "-4", - "_dd.p.tid": "0", - "_dd.p.usr.id": "12345", - "_dd.parent_id": "00000000000000bb", - "component": "aws-apigateway", - "env": "local-prod", + "env": "local-prod", + "version": "1.0", + "component": "aws-apigateway", + "sampling_priority": 1, + "sampling_mechanism": 4, + "origin": "rum", + "attributes": { "http.method": "GET", - "http.status_code": "200", "http.url": "example.com\/test", "stage": "aws-prod", - "version": "1.0" - }, - "metrics": { "_dd.inferred_span": 1, - "_sampling_priority_v1": 1 + "_dd.parent_id": "00000000000000bb", + "_dd.p.usr.id": "12345", + "http.status_code": "200" } } -] \ No newline at end of file +] diff --git a/tests/ext/inferred_proxy/propagated_tags_before_span_start.phpt b/tests/ext/inferred_proxy/propagated_tags_before_span_start.phpt index 4ec56b8f43..598989147f 100644 --- a/tests/ext/inferred_proxy/propagated_tags_before_span_start.phpt +++ b/tests/ext/inferred_proxy/propagated_tags_before_span_start.phpt @@ -54,23 +54,21 @@ echo json_encode(dd_clean_spans(), JSON_PRETTY_PRINT); "resource": "GET \/foo", "service": "aws-server", "type": "web", - "meta": { - "_dd.origin": "rum", - "_dd.p.usr.id": "12345", + "env": "local-prod", + "version": "1.0", + "component": "cgi-fcgi", + "span_kind": 2, + "attributes": { "_dd.parent_id": "00000000000000bb", - "env": "local-prod", + "_dd.p.usr.id": "12345", + "runtime-id": "%s", + "http.url": "http:\/\/localhost:8888\/foo", "http.method": "GET", + "process_id": %d, "http.status_code": "200", - "http.url": "http:\/\/localhost:8888\/foo", - "runtime-id": "%s", - "span.kind": "server", - "version": "1.0" - }, - "metrics": { "php.compilation.total_time_ms": %f, - "php.memory.peak_real_usage_bytes": %d, "php.memory.peak_usage_bytes": %d, - "process_id": %d + "php.memory.peak_real_usage_bytes": %d } }, { @@ -83,23 +81,20 @@ echo json_encode(dd_clean_spans(), JSON_PRETTY_PRINT); "resource": "GET \/test", "service": "example.com", "type": "web", - "meta": { - "_dd.origin": "rum", - "_dd.p.dm": "-4", - "_dd.p.tid": "0", - "_dd.p.usr.id": "12345", + "env": "local-prod", + "version": "1.0", + "component": "aws-apigateway", + "sampling_priority": 1, + "sampling_mechanism": 4, + "origin": "rum", + "attributes": { "_dd.parent_id": "00000000000000bb", - "component": "aws-apigateway", - "env": "local-prod", + "_dd.p.usr.id": "12345", "http.method": "GET", - "http.status_code": "200", "http.url": "example.com\/test", "stage": "aws-prod", - "version": "1.0" - }, - "metrics": { "_dd.inferred_span": 1, - "_sampling_priority_v1": 1 + "http.status_code": "200" } } -] \ No newline at end of file +] diff --git a/tests/ext/inferred_proxy/sampling_rules.phpt b/tests/ext/inferred_proxy/sampling_rules.phpt index ec95d80ce1..90be2db799 100644 --- a/tests/ext/inferred_proxy/sampling_rules.phpt +++ b/tests/ext/inferred_proxy/sampling_rules.phpt @@ -48,23 +48,23 @@ echo json_encode(dd_clean_spans(), JSON_PRETTY_PRINT); "resource": "GET \/foo", "service": "foo", "type": "web", - "meta": { - "_dd.p.ksr": "0.3", + "component": "cgi-fcgi", + "span_kind": 2, + "attributes": { + "runtime-id": "%s", + "http.url": "http:\/\/localhost:8888\/foo", "http.method": "GET", + "process_id": %d, + "_dd.p.ksr": "0.3", "http.status_code": "200", - "http.url": "http:\/\/localhost:8888\/foo", - "runtime-id": "%s", - "span.kind": "server" - }, - "metrics": { "php.compilation.total_time_ms": %f, - "php.memory.peak_real_usage_bytes": %d, "php.memory.peak_usage_bytes": %d, - "process_id": %d + "php.memory.peak_real_usage_bytes": %d } }, { "trace_id": "13930160852258120406", + "trace_id_high": "%s", "span_id": "11788048577503494824", "start": 100000000, "duration": %d, @@ -72,20 +72,17 @@ echo json_encode(dd_clean_spans(), JSON_PRETTY_PRINT); "resource": "GET \/test", "service": "example.com", "type": "web", - "meta": { - "_dd.p.dm": "-3", - "_dd.p.ksr": "0.3", - "_dd.p.tid": "%s", - "component": "aws-apigateway", + "component": "aws-apigateway", + "sampling_priority": 2, + "sampling_mechanism": 3, + "attributes": { "http.method": "GET", - "http.status_code": "200", "http.url": "example.com\/test", - "stage": "aws-prod" - }, - "metrics": { + "stage": "aws-prod", "_dd.inferred_span": 1, + "http.status_code": "200", "_dd.rule_psr": 0.3, - "_sampling_priority_v1": 2 + "_dd.p.ksr": "0.3" } } -] \ No newline at end of file +] diff --git a/tests/ext/inferred_proxy/security_headers_forwarded.phpt b/tests/ext/inferred_proxy/security_headers_forwarded.phpt index bb96033629..e901d01e4c 100644 --- a/tests/ext/inferred_proxy/security_headers_forwarded.phpt +++ b/tests/ext/inferred_proxy/security_headers_forwarded.phpt @@ -37,11 +37,11 @@ foreach ($spans as $span) { } // Tags must be present on the PHP service-entry span -var_dump($rootSpan['meta']['http.request.headers.x-datadog-endpoint-scan'] ?? 'NOT SET'); -var_dump($rootSpan['meta']['http.request.headers.x-datadog-security-test'] ?? 'NOT SET'); +var_dump($rootSpan['attributes']['http.request.headers.x-datadog-endpoint-scan'] ?? 'NOT SET'); +var_dump($rootSpan['attributes']['http.request.headers.x-datadog-security-test'] ?? 'NOT SET'); // And forwarded to the inferred proxy span -var_dump($inferredSpan['meta']['http.request.headers.x-datadog-endpoint-scan'] ?? 'NOT SET'); -var_dump($inferredSpan['meta']['http.request.headers.x-datadog-security-test'] ?? 'NOT SET'); +var_dump($inferredSpan['attributes']['http.request.headers.x-datadog-endpoint-scan'] ?? 'NOT SET'); +var_dump($inferredSpan['attributes']['http.request.headers.x-datadog-security-test'] ?? 'NOT SET'); ?> --EXPECT-- string(18) "endpoint-scan-uuid" diff --git a/tests/ext/inferred_proxy/serialization-sampling-chunk.phpt b/tests/ext/inferred_proxy/serialization-sampling-chunk.phpt index 23d7753090..e8e1de6e0a 100644 --- a/tests/ext/inferred_proxy/serialization-sampling-chunk.phpt +++ b/tests/ext/inferred_proxy/serialization-sampling-chunk.phpt @@ -25,16 +25,16 @@ class ChangeSamplingDuringSerialization { $root = DDTrace\start_span(); $root->name = 'keep.root'; -$root->metrics['http.status_code'] = new ChangeSamplingDuringSerialization(); +$root->attributes['http.status_code'] = new ChangeSamplingDuringSerialization(); DDTrace\close_span(); foreach (dd_trace_serialize_closed_spans() as $span) { echo $span['name'], "\n"; - if (isset($span['metrics']['_dd.span_sampling.mechanism'])) { - echo 'single span: ', $span['metrics']['_dd.span_sampling.mechanism'], "\n"; + if (isset($span['attributes']['_dd.span_sampling.mechanism'])) { + echo 'single span: ', $span['attributes']['_dd.span_sampling.mechanism'], "\n"; } - if (isset($span['metrics']['_sampling_priority_v1'])) { - echo 'trace priority: ', $span['metrics']['_sampling_priority_v1'], "\n"; + if (isset($span['sampling_priority'])) { + echo 'trace priority: ', $span['sampling_priority'], "\n"; } } diff --git a/tests/ext/inherit_meta_from_parent.phpt b/tests/ext/inherit_meta_from_parent.phpt index 46db2d7ef0..d49fd52fe9 100644 --- a/tests/ext/inherit_meta_from_parent.phpt +++ b/tests/ext/inherit_meta_from_parent.phpt @@ -18,10 +18,11 @@ $span->meta["env"] = "goodenv"; \DDTrace\close_span(); -var_dump(array_intersect_key(dd_trace_serialize_closed_spans()[1]["meta"], [ - "env" => 1, - "version" => 1, -])); +$span = dd_trace_serialize_closed_spans()[1]; +var_dump([ + "env" => $span["env"], + "version" => $span["version"], +]); ?> --EXPECT-- diff --git a/tests/ext/integrations/curl/distributed_tracing_curl.phpt b/tests/ext/integrations/curl/distributed_tracing_curl.phpt index 3484ebedcf..bc2ae49254 100644 --- a/tests/ext/integrations/curl/distributed_tracing_curl.phpt +++ b/tests/ext/integrations/curl/distributed_tracing_curl.phpt @@ -47,7 +47,7 @@ var_dump($headers['x-datadog-parent-id'] === (string) $spans[0]['span_id']); var_dump(abs(hexdec($headers['x-b3-spanid']) - $spans[0]['span_id']) < (1 << 13)); var_dump(abs(hexdec($headers['x-b3-traceid']) - $headers['x-datadog-trace-id']) < (1 << 13)); var_dump($headers['b3'] == "{$headers['x-b3-traceid']}-{$headers['x-b3-spanid']}-1"); -var_dump($spans[0]["meta"]["_dd.propagation_error"]); +var_dump($spans[0]["attributes"]["_dd.propagation_error"]); echo 'Done.' . PHP_EOL; diff --git a/tests/ext/integrations/curl/distributed_tracing_curl_copy_handle.phpt b/tests/ext/integrations/curl/distributed_tracing_curl_copy_handle.phpt index 8214b7c9f6..85f876fcee 100644 --- a/tests/ext/integrations/curl/distributed_tracing_curl_copy_handle.phpt +++ b/tests/ext/integrations/curl/distributed_tracing_curl_copy_handle.phpt @@ -95,4 +95,4 @@ x-datadog-trace-id: %d x-foo: after-the-copy Done. -[ddtrace] [info] [%d] Flushing trace of size 5 to send-queue for %s +[ddtrace] [info] [%d] Flushing v1 trace of size 5 to send-queue for %s diff --git a/tests/ext/integrations/curl/distributed_tracing_curl_drop_dm.phpt b/tests/ext/integrations/curl/distributed_tracing_curl_drop_dm.phpt index f3e19fc36e..10cc6280b8 100644 --- a/tests/ext/integrations/curl/distributed_tracing_curl_drop_dm.phpt +++ b/tests/ext/integrations/curl/distributed_tracing_curl_drop_dm.phpt @@ -35,7 +35,7 @@ dt_dump_headers_from_httpbin($headers, [ ]); $spans = dd_trace_serialize_closed_spans(); -var_dump(isset($spans[0]["meta"]["_dd.propagation_error"])); +var_dump(isset($spans[0]["attributes"]["_dd.propagation_error"])); echo 'Done.' . PHP_EOL; diff --git a/tests/ext/integrations/curl/distributed_tracing_curl_existing_headers_001.phpt b/tests/ext/integrations/curl/distributed_tracing_curl_existing_headers_001.phpt index e39edbc762..4adb416e77 100644 --- a/tests/ext/integrations/curl/distributed_tracing_curl_existing_headers_001.phpt +++ b/tests/ext/integrations/curl/distributed_tracing_curl_existing_headers_001.phpt @@ -65,4 +65,4 @@ x-mas: tree x-my-custom-header: foo Done. -[ddtrace] [info] [%d] Flushing trace of size 3 to send-queue for %s +[ddtrace] [info] [%d] Flushing v1 trace of size 3 to send-queue for %s diff --git a/tests/ext/integrations/curl/distributed_tracing_curl_existing_headers_002.phpt b/tests/ext/integrations/curl/distributed_tracing_curl_existing_headers_002.phpt index 2f7b20fb70..508bd9faa9 100644 --- a/tests/ext/integrations/curl/distributed_tracing_curl_existing_headers_002.phpt +++ b/tests/ext/integrations/curl/distributed_tracing_curl_existing_headers_002.phpt @@ -65,4 +65,4 @@ x-mas: tree x-my-custom-header: foo Done. -[ddtrace] [info] [%d] Flushing trace of size 3 to send-queue for %s +[ddtrace] [info] [%d] Flushing v1 trace of size 3 to send-queue for %s diff --git a/tests/ext/integrations/curl/distributed_tracing_curl_existing_headers_003.phpt b/tests/ext/integrations/curl/distributed_tracing_curl_existing_headers_003.phpt index 2509206ca4..b8927bf9d0 100644 --- a/tests/ext/integrations/curl/distributed_tracing_curl_existing_headers_003.phpt +++ b/tests/ext/integrations/curl/distributed_tracing_curl_existing_headers_003.phpt @@ -82,4 +82,4 @@ x-datadog-parent-id: %d x-orig-header: foo Done. -[ddtrace] [info] [%d] Flushing trace of size 3 to send-queue for %s +[ddtrace] [info] [%d] Flushing v1 trace of size 3 to send-queue for %s diff --git a/tests/ext/integrations/curl/distributed_tracing_curl_invalid_tags.phpt b/tests/ext/integrations/curl/distributed_tracing_curl_invalid_tags.phpt index 134d2b895b..cd5f6f99a2 100644 --- a/tests/ext/integrations/curl/distributed_tracing_curl_invalid_tags.phpt +++ b/tests/ext/integrations/curl/distributed_tracing_curl_invalid_tags.phpt @@ -35,7 +35,7 @@ dt_dump_headers_from_httpbin($headers, [ ]); $spans = dd_trace_serialize_closed_spans(); -var_dump(isset($spans[0]["meta"]["_dd.propagation_error"])); +var_dump(isset($spans[0]["attributes"]["_dd.propagation_error"])); echo 'Done.' . PHP_EOL; diff --git a/tests/ext/integrations/curl/distributed_tracing_curl_multi_exec_001.phpt b/tests/ext/integrations/curl/distributed_tracing_curl_multi_exec_001.phpt index 5d6ac75c12..011dab40ec 100644 --- a/tests/ext/integrations/curl/distributed_tracing_curl_multi_exec_001.phpt +++ b/tests/ext/integrations/curl/distributed_tracing_curl_multi_exec_001.phpt @@ -72,4 +72,4 @@ x-datadog-parent-id: %d x-datadog-origin: phpt-test x-datadog-parent-id: %d Done. -[ddtrace] [info] [%d] Flushing trace of size 2 to send-queue for %s +[ddtrace] [info] [%d] Flushing v1 trace of size 2 to send-queue for %s diff --git a/tests/ext/integrations/curl/distributed_tracing_curl_multi_exec_002.phpt b/tests/ext/integrations/curl/distributed_tracing_curl_multi_exec_002.phpt index 79b4472761..b153400722 100644 --- a/tests/ext/integrations/curl/distributed_tracing_curl_multi_exec_002.phpt +++ b/tests/ext/integrations/curl/distributed_tracing_curl_multi_exec_002.phpt @@ -73,4 +73,4 @@ x-datadog-parent-id: %d x-datadog-origin: phpt-test x-datadog-parent-id: %d Done. -[ddtrace] [info] [%d] Flushing trace of size 2 to send-queue for %s +[ddtrace] [info] [%d] Flushing v1 trace of size 2 to send-queue for %s diff --git a/tests/ext/integrations/curl/distributed_tracing_curl_multi_exec_003.phpt b/tests/ext/integrations/curl/distributed_tracing_curl_multi_exec_003.phpt index 253fb22770..63f0c6bad5 100644 --- a/tests/ext/integrations/curl/distributed_tracing_curl_multi_exec_003.phpt +++ b/tests/ext/integrations/curl/distributed_tracing_curl_multi_exec_003.phpt @@ -74,4 +74,4 @@ x-datadog-parent-id: %d x-datadog-origin: phpt-test x-datadog-parent-id: %d Done. -[ddtrace] [info] [%d] Flushing trace of size 2 to send-queue for %s +[ddtrace] [info] [%d] Flushing v1 trace of size 2 to send-queue for %s diff --git a/tests/ext/integrations/curl/distributed_tracing_curl_multi_exec_copy_handle.phpt b/tests/ext/integrations/curl/distributed_tracing_curl_multi_exec_copy_handle.phpt index 8331212387..da8389ef5b 100644 --- a/tests/ext/integrations/curl/distributed_tracing_curl_multi_exec_copy_handle.phpt +++ b/tests/ext/integrations/curl/distributed_tracing_curl_multi_exec_copy_handle.phpt @@ -91,4 +91,4 @@ x-datadog-origin: phpt-test x-datadog-parent-id: %d x-foo: not copied Done. -[ddtrace] [info] [%d] Flushing trace of size 2 to send-queue for %s +[ddtrace] [info] [%d] Flushing v1 trace of size 2 to send-queue for %s diff --git a/tests/ext/integrations/curl/distributed_tracing_curl_multi_exec_existing_headers_001.phpt b/tests/ext/integrations/curl/distributed_tracing_curl_multi_exec_existing_headers_001.phpt index c8597de99b..8e1c77dc6c 100644 --- a/tests/ext/integrations/curl/distributed_tracing_curl_multi_exec_existing_headers_001.phpt +++ b/tests/ext/integrations/curl/distributed_tracing_curl_multi_exec_existing_headers_001.phpt @@ -88,4 +88,4 @@ x-ch-2-foo: foo x-datadog-origin: phpt-test x-datadog-parent-id: %d Done. -[ddtrace] [info] [%d] Flushing trace of size 2 to send-queue for %s +[ddtrace] [info] [%d] Flushing v1 trace of size 2 to send-queue for %s diff --git a/tests/ext/integrations/curl/distributed_tracing_curl_multi_exec_existing_headers_002.phpt b/tests/ext/integrations/curl/distributed_tracing_curl_multi_exec_existing_headers_002.phpt index da71329a71..1e185300c9 100644 --- a/tests/ext/integrations/curl/distributed_tracing_curl_multi_exec_existing_headers_002.phpt +++ b/tests/ext/integrations/curl/distributed_tracing_curl_multi_exec_existing_headers_002.phpt @@ -92,4 +92,4 @@ x-ch-2-foo: foo x-datadog-origin: phpt-test x-datadog-parent-id: %d Done. -[ddtrace] [info] [%d] Flushing trace of size 2 to send-queue for %s +[ddtrace] [info] [%d] Flushing v1 trace of size 2 to send-queue for %s diff --git a/tests/ext/integrations/curl/distributed_tracing_curl_tracestate.phpt b/tests/ext/integrations/curl/distributed_tracing_curl_tracestate.phpt index 3fdf84c386..9c58e95ee6 100644 --- a/tests/ext/integrations/curl/distributed_tracing_curl_tracestate.phpt +++ b/tests/ext/integrations/curl/distributed_tracing_curl_tracestate.phpt @@ -35,7 +35,7 @@ dt_dump_headers_from_httpbin($headers, [ ]); $spans = dd_trace_serialize_closed_spans(); -var_dump(isset($spans[0]["meta"]["_dd.propagation_error"])); +var_dump(isset($spans[0]["attributes"]["_dd.propagation_error"])); echo 'Done.' . PHP_EOL; diff --git a/tests/ext/integrations/drupal/drupal_integration.inc b/tests/ext/integrations/drupal/drupal_integration.inc index e065e05166..55e48eb018 100644 --- a/tests/ext/integrations/drupal/drupal_integration.inc +++ b/tests/ext/integrations/drupal/drupal_integration.inc @@ -38,10 +38,10 @@ function dd_drupal_render_report(array $spans, array $probeTargets) if ($span['name'] !== 'drupal.theme.render') { continue; } - $file = isset($span['meta']['drupal.template.file']) ? $span['meta']['drupal.template.file'] : ''; + $file = isset($span['attributes']['drupal.template.file']) ? $span['attributes']['drupal.template.file'] : ''; $tags[$file] = (isset($tags[$file]) ? $tags[$file] : 0) + 1; // Also reported so that a begin hook exception swallowed by the sandbox cannot pass silently. - $engine = isset($span['meta']['drupal.render.engine']) ? $span['meta']['drupal.render.engine'] : ''; + $engine = isset($span['attributes']['drupal.render.engine']) ? $span['attributes']['drupal.render.engine'] : ''; $engines[$engine] = (isset($engines[$engine]) ? $engines[$engine] : 0) + 1; } ksort($tags); diff --git a/tests/ext/integrations/drupal/theme_engine_service_dropped_nested_span.phpt b/tests/ext/integrations/drupal/theme_engine_service_dropped_nested_span.phpt index f4024575b6..001c4a758f 100644 --- a/tests/ext/integrations/drupal/theme_engine_service_dropped_nested_span.phpt +++ b/tests/ext/integrations/drupal/theme_engine_service_dropped_nested_span.phpt @@ -114,7 +114,7 @@ namespace continue; } echo "surviving render span template.file = ", - isset($span['meta']['drupal.template.file']) ? $span['meta']['drupal.template.file'] : '', + isset($span['attributes']['drupal.template.file']) ? $span['attributes']['drupal.template.file'] : '', "\n"; } dd_drupal_render_report($spans, ['Drupal\Core\Template\TwigThemeEngine::renderTemplate']); diff --git a/tests/ext/integrations/drupal/theme_render_dropped_nested_span.phpt b/tests/ext/integrations/drupal/theme_render_dropped_nested_span.phpt index 21323d191d..8676b38017 100644 --- a/tests/ext/integrations/drupal/theme_render_dropped_nested_span.phpt +++ b/tests/ext/integrations/drupal/theme_render_dropped_nested_span.phpt @@ -86,7 +86,7 @@ namespace continue; } echo "surviving render span template.file = ", - isset($span['meta']['drupal.template.file']) ? $span['meta']['drupal.template.file'] : '', + isset($span['attributes']['drupal.template.file']) ? $span['attributes']['drupal.template.file'] : '', "\n"; } dd_drupal_render_report($spans, ['twig_render_template']); diff --git a/tests/ext/integrations/http_streams/distributed_tracing_http_streams.phpt b/tests/ext/integrations/http_streams/distributed_tracing_http_streams.phpt index cfa41ac630..c8267cd2e9 100644 --- a/tests/ext/integrations/http_streams/distributed_tracing_http_streams.phpt +++ b/tests/ext/integrations/http_streams/distributed_tracing_http_streams.phpt @@ -50,8 +50,12 @@ echo "resource: " . $span['resource'] . "\n"; echo "type: " . $span['type'] . "\n"; echo "service: " . $span['service'] . "\n"; echo "meta:\n"; -ksort($span['meta']); -foreach ($span['meta'] as $k => $v) { +// The v1 introspection shape merges meta+metrics into a single attributes map and +// promotes component/span.kind to top-level fields; keep the string tags to preserve +// this test's historical meta view. +$attrs = array_filter($span['attributes'], 'is_string'); +ksort($attrs); +foreach ($attrs as $k => $v) { echo " $k: $v\n"; } @@ -72,10 +76,8 @@ resource: %s type: cli service: %s meta: - component: php.stream http.method: GET http.url: http://%s:%d/headers network.destination.name: %s - span.kind: client Done. [ddtrace] [info] [%d] No finished traces to be sent to the agent diff --git a/tests/ext/integrations/http_streams/distributed_tracing_http_streams_with_headers_array.phpt b/tests/ext/integrations/http_streams/distributed_tracing_http_streams_with_headers_array.phpt index 98cb4604ab..7da44b660c 100644 --- a/tests/ext/integrations/http_streams/distributed_tracing_http_streams_with_headers_array.phpt +++ b/tests/ext/integrations/http_streams/distributed_tracing_http_streams_with_headers_array.phpt @@ -93,4 +93,4 @@ x-datadog-trace-id: %d x-foo: two Done. -[ddtrace] [info] [%d] Flushing trace of size 5 to send-queue for %s +[ddtrace] [info] [%d] Flushing v1 trace of size 5 to send-queue for %s diff --git a/tests/ext/integrations/http_streams/distributed_tracing_http_streams_with_headers_string.phpt b/tests/ext/integrations/http_streams/distributed_tracing_http_streams_with_headers_string.phpt index a2acac25e6..2f485057ed 100644 --- a/tests/ext/integrations/http_streams/distributed_tracing_http_streams_with_headers_string.phpt +++ b/tests/ext/integrations/http_streams/distributed_tracing_http_streams_with_headers_string.phpt @@ -85,4 +85,4 @@ x-datadog-trace-id: %d x-foo: two Done. -[ddtrace] [info] [%d] Flushing trace of size 5 to send-queue for %s +[ddtrace] [info] [%d] Flushing v1 trace of size 5 to send-queue for %s diff --git a/tests/ext/integrations/source_code/001/git_metadata_injection_from_valid_files.phpt b/tests/ext/integrations/source_code/001/git_metadata_injection_from_valid_files.phpt index 7bfdb7b9f2..01943f8d28 100644 --- a/tests/ext/integrations/source_code/001/git_metadata_injection_from_valid_files.phpt +++ b/tests/ext/integrations/source_code/001/git_metadata_injection_from_valid_files.phpt @@ -27,7 +27,7 @@ function makeRequest() { $closedSpans = dd_trace_serialize_closed_spans(); - $rootMeta = $closedSpans[0]['meta']; + $rootMeta = $closedSpans[0]['attributes']; echo $rootMeta['_dd.git.repository_url'] . PHP_EOL; echo $rootMeta['_dd.git.commit.sha'] . PHP_EOL; @@ -35,7 +35,7 @@ function makeRequest() { \DDTrace\close_span(); $closedRoot = dd_trace_serialize_closed_spans(); - $rootMeta2 = $closedRoot[0]['meta']; + $rootMeta2 = $closedRoot[0]['attributes']; echo $rootMeta2['_dd.git.repository_url'] . PHP_EOL; echo $rootMeta2['_dd.git.commit.sha'] . PHP_EOL; diff --git a/tests/ext/integrations/source_code/002/git_metadata_injection_from_invalid_files.phpt b/tests/ext/integrations/source_code/002/git_metadata_injection_from_invalid_files.phpt index de22c60be6..3a41aa29f6 100644 --- a/tests/ext/integrations/source_code/002/git_metadata_injection_from_invalid_files.phpt +++ b/tests/ext/integrations/source_code/002/git_metadata_injection_from_invalid_files.phpt @@ -28,14 +28,14 @@ function makeRequest() { \DDTrace\close_span(); $closedSpans = dd_clean_spans(); - $rootMeta = $closedSpans[0]['meta']; + $rootMeta = $closedSpans[0]['attributes']; var_dump($rootMeta); \DDTrace\start_span(); \DDTrace\close_span(); $closedRoot = dd_clean_spans(); - $rootMeta2 = $closedRoot[0]['meta']; + $rootMeta2 = $closedRoot[0]['attributes']; var_dump($rootMeta2); } @@ -55,43 +55,67 @@ function rm_rf($dir) { rm_rf(__DIR__ . '/.git'); ?> --EXPECTF-- -array(4) { - ["_dd.git.repository_url"]=> - string(32) "https://github.com/user/repo_new" - ["_dd.p.dm"]=> - string(2) "-0" - ["_dd.p.tid"]=> - string(16) "%s" +array(7) { ["runtime-id"]=> string(%d) "%s" -} -array(4) { + ["process_id"]=> + float(%f) + ["_dd.agent_psr"]=> + float(1) ["_dd.git.repository_url"]=> string(32) "https://github.com/user/repo_new" - ["_dd.p.dm"]=> - string(2) "-0" - ["_dd.p.tid"]=> - string(16) "%s" + ["php.compilation.total_time_ms"]=> + float(%f) + ["php.memory.peak_usage_bytes"]=> + float(%f) + ["php.memory.peak_real_usage_bytes"]=> + float(%f) +} +array(7) { ["runtime-id"]=> string(%d) "%s" -} -array(4) { + ["process_id"]=> + float(%f) + ["_dd.agent_psr"]=> + float(1) ["_dd.git.repository_url"]=> string(32) "https://github.com/user/repo_new" - ["_dd.p.dm"]=> - string(2) "-0" - ["_dd.p.tid"]=> - string(16) "%s" + ["php.compilation.total_time_ms"]=> + float(%f) + ["php.memory.peak_usage_bytes"]=> + float(%f) + ["php.memory.peak_real_usage_bytes"]=> + float(%f) +} +array(7) { ["runtime-id"]=> string(%d) "%s" -} -array(4) { + ["process_id"]=> + float(%f) + ["_dd.agent_psr"]=> + float(1) ["_dd.git.repository_url"]=> string(32) "https://github.com/user/repo_new" - ["_dd.p.dm"]=> - string(2) "-0" - ["_dd.p.tid"]=> - string(16) "%s" + ["php.compilation.total_time_ms"]=> + float(%f) + ["php.memory.peak_usage_bytes"]=> + float(%f) + ["php.memory.peak_real_usage_bytes"]=> + float(%f) +} +array(7) { ["runtime-id"]=> string(%d) "%s" + ["process_id"]=> + float(%f) + ["_dd.agent_psr"]=> + float(1) + ["_dd.git.repository_url"]=> + string(32) "https://github.com/user/repo_new" + ["php.compilation.total_time_ms"]=> + float(%f) + ["php.memory.peak_usage_bytes"]=> + float(%f) + ["php.memory.peak_real_usage_bytes"]=> + float(%f) } diff --git a/tests/ext/integrations/source_code/commit_sha_env_var.phpt b/tests/ext/integrations/source_code/commit_sha_env_var.phpt index 907bf033af..5b8534a25c 100644 --- a/tests/ext/integrations/source_code/commit_sha_env_var.phpt +++ b/tests/ext/integrations/source_code/commit_sha_env_var.phpt @@ -23,9 +23,11 @@ var_dump(dd_clean_spans()); --EXPECTF-- array(2) { [0]=> - array(10) { + array(12) { ["trace_id"]=> string(%d) "%d" + ["trace_id_high"]=> + string(16) "%s" ["span_id"]=> string(%d) "%d" ["start"]=> @@ -40,30 +42,25 @@ array(2) { string(22) "commit_sha_env_var.php" ["type"]=> string(3) "cli" - ["meta"]=> - array(4) { - ["_dd.git.commit.sha"]=> - string(6) "123456" - ["_dd.p.dm"]=> - string(2) "-0" - ["_dd.p.tid"]=> - string(16) "%s" + ["sampling_priority"]=> + int(1) + ["sampling_mechanism"]=> + int(0) + ["attributes"]=> + array(7) { ["runtime-id"]=> string(%d) "%s" - } - ["metrics"]=> - array(6) { + ["process_id"]=> + float(%f) ["_dd.agent_psr"]=> float(1) - ["_sampling_priority_v1"]=> - float(1) + ["_dd.git.commit.sha"]=> + string(6) "123456" ["php.compilation.total_time_ms"]=> float(%f) - ["php.memory.peak_real_usage_bytes"]=> - float(%f) ["php.memory.peak_usage_bytes"]=> float(%f) - ["process_id"]=> + ["php.memory.peak_real_usage_bytes"]=> float(%f) } } diff --git a/tests/ext/integrations/source_code/git_metadata_injection_from_env.phpt b/tests/ext/integrations/source_code/git_metadata_injection_from_env.phpt index d420f7f4b7..ea9e02e4c0 100644 --- a/tests/ext/integrations/source_code/git_metadata_injection_from_env.phpt +++ b/tests/ext/integrations/source_code/git_metadata_injection_from_env.phpt @@ -24,9 +24,11 @@ var_dump(dd_clean_spans()); --EXPECTF-- array(2) { [0]=> - array(10) { + array(12) { ["trace_id"]=> string(%d) "%d" + ["trace_id_high"]=> + string(16) "%s" ["span_id"]=> string(%d) "%d" ["start"]=> @@ -41,33 +43,28 @@ array(2) { string(35) "git_metadata_injection_from_env.php" ["type"]=> string(3) "cli" - ["meta"]=> - array(5) { + ["sampling_priority"]=> + int(1) + ["sampling_mechanism"]=> + int(0) + ["attributes"]=> + array(8) { + ["runtime-id"]=> + string(%d) "%s" + ["process_id"]=> + float(%f) + ["_dd.agent_psr"]=> + float(1) ["_dd.git.commit.sha"]=> string(6) "123456" ["_dd.git.repository_url"]=> string(24) "github.com/user/env_repo" - ["_dd.p.dm"]=> - string(2) "-0" - ["_dd.p.tid"]=> - string(16) "%s" - ["runtime-id"]=> - string(36) "%s" - } - ["metrics"]=> - array(6) { - ["_dd.agent_psr"]=> - float(1) - ["_sampling_priority_v1"]=> - float(1) ["php.compilation.total_time_ms"]=> float(%f) - ["php.memory.peak_real_usage_bytes"]=> - float(%f) ["php.memory.peak_usage_bytes"]=> float(%f) - ["process_id"]=> - float(%d) + ["php.memory.peak_real_usage_bytes"]=> + float(%f) } } [1]=> @@ -91,4 +88,4 @@ array(2) { ["type"]=> string(3) "cli" } -} \ No newline at end of file +} diff --git a/tests/ext/integrations/source_code/git_metadata_injection_from_global_tags.phpt b/tests/ext/integrations/source_code/git_metadata_injection_from_global_tags.phpt index f7a0669b12..d5057ea544 100644 --- a/tests/ext/integrations/source_code/git_metadata_injection_from_global_tags.phpt +++ b/tests/ext/integrations/source_code/git_metadata_injection_from_global_tags.phpt @@ -23,9 +23,11 @@ var_dump(dd_clean_spans()); --EXPECTF-- array(2) { [0]=> - array(10) { + array(12) { ["trace_id"]=> string(%d) "%d" + ["trace_id_high"]=> + string(16) "%s" ["span_id"]=> string(%d) "%d" ["start"]=> @@ -40,37 +42,32 @@ array(2) { string(43) "git_metadata_injection_from_global_tags.php" ["type"]=> string(3) "cli" - ["meta"]=> - array(7) { - ["_dd.git.commit.sha"]=> - string(6) "123456" - ["_dd.git.repository_url"]=> - string(24) "github.com/user/env_repo" - ["_dd.p.dm"]=> - string(2) "-0" - ["_dd.p.tid"]=> - string(16) "%s" + ["sampling_priority"]=> + int(1) + ["sampling_mechanism"]=> + int(0) + ["attributes"]=> + array(10) { + ["runtime-id"]=> + string(%d) "%s" + ["process_id"]=> + float(%f) ["git.commit.sha"]=> string(6) "123456" ["git.repository_url"]=> string(24) "github.com/user/env_repo" - ["runtime-id"]=> - string(36) "%s" - } - ["metrics"]=> - array(6) { ["_dd.agent_psr"]=> float(1) - ["_sampling_priority_v1"]=> - float(1) + ["_dd.git.commit.sha"]=> + string(6) "123456" + ["_dd.git.repository_url"]=> + string(24) "github.com/user/env_repo" ["php.compilation.total_time_ms"]=> float(%f) - ["php.memory.peak_real_usage_bytes"]=> - float(%f) ["php.memory.peak_usage_bytes"]=> float(%f) - ["process_id"]=> - float(%d) + ["php.memory.peak_real_usage_bytes"]=> + float(%f) } } [1]=> @@ -93,7 +90,7 @@ array(2) { string(43) "git_metadata_injection_from_global_tags.php" ["type"]=> string(3) "cli" - ["meta"]=> + ["attributes"]=> array(2) { ["git.commit.sha"]=> string(6) "123456" diff --git a/tests/ext/integrations/source_code/git_metadata_injection_remove_credentials_from_env.phpt b/tests/ext/integrations/source_code/git_metadata_injection_remove_credentials_from_env.phpt index 6e735807c4..7357f811ff 100644 --- a/tests/ext/integrations/source_code/git_metadata_injection_remove_credentials_from_env.phpt +++ b/tests/ext/integrations/source_code/git_metadata_injection_remove_credentials_from_env.phpt @@ -24,9 +24,11 @@ var_dump(dd_clean_spans()); --EXPECTF-- array(2) { [0]=> - array(10) { + array(12) { ["trace_id"]=> string(%d) "%d" + ["trace_id_high"]=> + string(16) "%s" ["span_id"]=> string(%d) "%d" ["start"]=> @@ -41,33 +43,28 @@ array(2) { string(54) "git_metadata_injection_remove_credentials_from_env.php" ["type"]=> string(3) "cli" - ["meta"]=> - array(5) { + ["sampling_priority"]=> + int(1) + ["sampling_mechanism"]=> + int(0) + ["attributes"]=> + array(8) { + ["runtime-id"]=> + string(%d) "%s" + ["process_id"]=> + float(%f) + ["_dd.agent_psr"]=> + float(1) ["_dd.git.commit.sha"]=> string(6) "123456" ["_dd.git.repository_url"]=> string(32) "https://github.com/user/repo_new" - ["_dd.p.dm"]=> - string(2) "-0" - ["_dd.p.tid"]=> - string(16) "%s" - ["runtime-id"]=> - string(36) "%s" - } - ["metrics"]=> - array(6) { - ["_dd.agent_psr"]=> - float(1) - ["_sampling_priority_v1"]=> - float(1) ["php.compilation.total_time_ms"]=> float(%f) - ["php.memory.peak_real_usage_bytes"]=> - float(%f) ["php.memory.peak_usage_bytes"]=> float(%f) - ["process_id"]=> - float(%d) + ["php.memory.peak_real_usage_bytes"]=> + float(%f) } } [1]=> diff --git a/tests/ext/integrations/source_code/repository_url_env_var.phpt b/tests/ext/integrations/source_code/repository_url_env_var.phpt index b7f4fa9108..638bcf947a 100644 --- a/tests/ext/integrations/source_code/repository_url_env_var.phpt +++ b/tests/ext/integrations/source_code/repository_url_env_var.phpt @@ -23,9 +23,11 @@ var_dump(dd_clean_spans()); --EXPECTF-- array(2) { [0]=> - array(10) { + array(12) { ["trace_id"]=> string(%d) "%d" + ["trace_id_high"]=> + string(16) "%s" ["span_id"]=> string(%d) "%d" ["start"]=> @@ -40,31 +42,26 @@ array(2) { string(26) "repository_url_env_var.php" ["type"]=> string(3) "cli" - ["meta"]=> - array(4) { - ["_dd.git.repository_url"]=> - string(24) "github.com/user/env_repo" - ["_dd.p.dm"]=> - string(2) "-0" - ["_dd.p.tid"]=> - string(16) "%s" + ["sampling_priority"]=> + int(1) + ["sampling_mechanism"]=> + int(0) + ["attributes"]=> + array(7) { ["runtime-id"]=> string(%d) "%s" - } - ["metrics"]=> - array(6) { + ["process_id"]=> + float(%f) ["_dd.agent_psr"]=> float(1) - ["_sampling_priority_v1"]=> - float(1) + ["_dd.git.repository_url"]=> + string(24) "github.com/user/env_repo" ["php.compilation.total_time_ms"]=> float(%f) - ["php.memory.peak_real_usage_bytes"]=> - float(%f) ["php.memory.peak_usage_bytes"]=> float(%f) - ["process_id"]=> - float(%d) + ["php.memory.peak_real_usage_bytes"]=> + float(%f) } } [1]=> diff --git a/tests/ext/ip_collection_01.phpt b/tests/ext/ip_collection_01.phpt index a92a5d91e8..80efa5465c 100644 --- a/tests/ext/ip_collection_01.phpt +++ b/tests/ext/ip_collection_01.phpt @@ -8,7 +8,7 @@ REMOTE_ADDR=127.0.0.1 DDTrace\start_span(); DDTrace\close_span(0); $span = dd_trace_serialize_closed_spans(); -var_dump(isset($span[0]["meta"]["http.client_ip"])); +var_dump(isset($span[0]["attributes"]["http.client_ip"])); ?> --EXPECTF-- bool(false) diff --git a/tests/ext/ip_collection_02.phpt b/tests/ext/ip_collection_02.phpt index b73dca0798..0ad7dea225 100644 --- a/tests/ext/ip_collection_02.phpt +++ b/tests/ext/ip_collection_02.phpt @@ -8,7 +8,7 @@ REMOTE_ADDR=127.0.0.1 DDTrace\start_span(); DDTrace\close_span(0); $span = dd_trace_serialize_closed_spans(); -var_dump(isset($span[0]["meta"]["http.client_ip"])); +var_dump(isset($span[0]["attributes"]["http.client_ip"])); ?> --EXPECTF-- bool(false) diff --git a/tests/ext/ip_collection_03.phpt b/tests/ext/ip_collection_03.phpt index 3c55dc4be1..22462f9fd4 100644 --- a/tests/ext/ip_collection_03.phpt +++ b/tests/ext/ip_collection_03.phpt @@ -10,7 +10,7 @@ DD_TRACE_CLIENT_IP_ENABLED=true DDTrace\start_span(); DDTrace\close_span(0); $span = dd_trace_serialize_closed_spans(); -var_dump($span[0]["meta"]["http.client_ip"]); +var_dump($span[0]["attributes"]["http.client_ip"]); ?> --EXPECTF-- string(9) "127.0.0.1" diff --git a/tests/ext/ip_collection_04.phpt b/tests/ext/ip_collection_04.phpt index 33d734344a..699d0bd462 100644 --- a/tests/ext/ip_collection_04.phpt +++ b/tests/ext/ip_collection_04.phpt @@ -10,7 +10,7 @@ datadog.trace.client_ip_header_disabled=true DDTrace\start_span(); DDTrace\close_span(0); $span = dd_trace_serialize_closed_spans(); -var_dump(isset($span[0]["meta"]["http.client_ip"])); +var_dump(isset($span[0]["attributes"]["http.client_ip"])); ?> --EXPECTF-- bool(false) diff --git a/tests/ext/ip_collection_05.phpt b/tests/ext/ip_collection_05.phpt index 33d734344a..699d0bd462 100644 --- a/tests/ext/ip_collection_05.phpt +++ b/tests/ext/ip_collection_05.phpt @@ -10,7 +10,7 @@ datadog.trace.client_ip_header_disabled=true DDTrace\start_span(); DDTrace\close_span(0); $span = dd_trace_serialize_closed_spans(); -var_dump(isset($span[0]["meta"]["http.client_ip"])); +var_dump(isset($span[0]["attributes"]["http.client_ip"])); ?> --EXPECTF-- bool(false) diff --git a/tests/ext/limiter/002-limiter-reached.phpt b/tests/ext/limiter/002-limiter-reached.phpt index b26685d403..aa95978352 100644 --- a/tests/ext/limiter/002-limiter-reached.phpt +++ b/tests/ext/limiter/002-limiter-reached.phpt @@ -21,7 +21,7 @@ while (true) { $sampled = 0; foreach ($spans as $span) { - if (isset($span["metrics"]["_sampling_priority_v1"])) { + if (isset($span["sampling_priority"])) { $sampled++; } } @@ -38,7 +38,7 @@ while (true) { $end = $spans[\count($spans)-1]; -if (\round($end["metrics"]["_dd.limit_psr"], 1) != 0.5) { +if (\round($end["attributes"]["_dd.limit_psr"], 1) != 0.5) { echo "Fail\n"; var_dump($spans); exit; diff --git a/tests/ext/limiter/003-limiter-with-asm-standalone.phpt b/tests/ext/limiter/003-limiter-with-asm-standalone.phpt index 95997cccb5..5923e9b741 100644 --- a/tests/ext/limiter/003-limiter-with-asm-standalone.phpt +++ b/tests/ext/limiter/003-limiter-with-asm-standalone.phpt @@ -22,7 +22,7 @@ while (true) { $sampled = 0; foreach ($spans as $span) { - if (isset($span["metrics"]["_sampling_priority_v1"])) { + if (isset($span["sampling_priority"])) { $sampled++; } } diff --git a/tests/ext/live-debugger/debugger_span_decoration_probe.phpt b/tests/ext/live-debugger/debugger_span_decoration_probe.phpt index f5278b29a5..6055175ee1 100644 --- a/tests/ext/live-debugger/debugger_span_decoration_probe.phpt +++ b/tests/ext/live-debugger/debugger_span_decoration_probe.phpt @@ -18,14 +18,14 @@ require __DIR__ . "/live_debugger.inc"; reset_request_replayer(); function &foo($arg) { - $meta = &\DDTrace\active_span()->meta; + $meta = &\DDTrace\active_span()->attributes; unset($meta["runtime-id"]); return $meta; } function &root($arg) { - $meta = &\DDTrace\root_span()->meta; - unset($meta["runtime-id"]); + $meta = &\DDTrace\root_span()->attributes; + unset($meta["runtime-id"], $meta["process_id"]); return $arg; } @@ -48,13 +48,13 @@ await_probe_installation(function() { \DDTrace\start_span(); var_dump(foo(["foo" => (object)["var" => 1, "val" => "test"], "val" => 123])); -\DDTrace\active_span()->meta = []; +\DDTrace\active_span()->attributes = []; $meta = foo(["foo" => (object)["var" => 2]]); ksort($meta); var_dump($meta); root(1); -var_dump(\DDTrace\root_span()->meta); +var_dump(\DDTrace\root_span()->attributes); $dlr = new DebuggerLogReplayer; $log = $dlr->waitForDebuggerDataAndReplay(); diff --git a/tests/ext/nested_exceptions.phpt b/tests/ext/nested_exceptions.phpt index cf79fb27e8..e8d11dcdda 100644 --- a/tests/ext/nested_exceptions.phpt +++ b/tests/ext/nested_exceptions.phpt @@ -18,9 +18,11 @@ var_dump(dd_clean_spans()); --EXPECTF-- array(1) { [0]=> - array(11) { + array(12) { ["trace_id"]=> string(%d) "%d" + ["trace_id_high"]=> + string(16) "%s" ["span_id"]=> string(%d) "%d" ["parent_id"]=> @@ -39,10 +41,12 @@ array(1) { string(3) "cli" ["error"]=> int(1) - ["meta"]=> + ["attributes"]=> array(3) { ["error.message"]=> string(%d) "Thrown RuntimeException: Some kind of message in %s:%d" + ["error.type"]=> + string(16) "RuntimeException" ["error.stack"]=> string(%d) "#0 {main} @@ -53,8 +57,6 @@ Stack trace: Next Exception: This is a generic exception message in %s:%d Stack trace: #0 {main}" - ["error.type"]=> - string(16) "RuntimeException" } } } diff --git a/tests/ext/otel_http_response_status_code_remapping.phpt b/tests/ext/otel_http_response_status_code_remapping.phpt index 88b2d3cb5a..f571b7c990 100644 --- a/tests/ext/otel_http_response_status_code_remapping.phpt +++ b/tests/ext/otel_http_response_status_code_remapping.phpt @@ -14,9 +14,11 @@ var_dump(dd_clean_spans()); --EXPECTF-- array(1) { [0]=> - array(10) { + array(11) { ["trace_id"]=> string(%d) "%d" + ["trace_id_high"]=> + string(16) "%s" ["span_id"]=> string(%d) "%d" ["parent_id"]=> @@ -33,7 +35,7 @@ array(1) { string(44) "otel_http_response_status_code_remapping.php" ["type"]=> string(3) "cli" - ["meta"]=> + ["attributes"]=> array(1) { ["http.status_code"]=> string(3) "300" diff --git a/tests/ext/otel_http_response_status_code_remapping_precedence.phpt b/tests/ext/otel_http_response_status_code_remapping_precedence.phpt index 386ef0492e..b8f5f8f3e2 100644 --- a/tests/ext/otel_http_response_status_code_remapping_precedence.phpt +++ b/tests/ext/otel_http_response_status_code_remapping_precedence.phpt @@ -15,9 +15,11 @@ var_dump(dd_clean_spans()); --EXPECTF-- array(1) { [0]=> - array(10) { + array(11) { ["trace_id"]=> string(%d) "%d" + ["trace_id_high"]=> + string(16) "%s" ["span_id"]=> string(%d) "%d" ["parent_id"]=> @@ -34,7 +36,7 @@ array(1) { string(55) "otel_http_response_status_code_remapping_precedence.php" ["type"]=> string(3) "cli" - ["meta"]=> + ["attributes"]=> array(1) { ["http.status_code"]=> string(3) "300" diff --git a/tests/ext/otel_http_status_code_remapping.phpt b/tests/ext/otel_http_status_code_remapping.phpt index 4b3886711e..b6646d4695 100644 --- a/tests/ext/otel_http_status_code_remapping.phpt +++ b/tests/ext/otel_http_status_code_remapping.phpt @@ -14,9 +14,11 @@ var_dump(dd_clean_spans()); --EXPECTF-- array(1) { [0]=> - array(10) { + array(11) { ["trace_id"]=> string(%d) "%d" + ["trace_id_high"]=> + string(16) "%s" ["span_id"]=> string(%d) "%d" ["parent_id"]=> @@ -33,7 +35,7 @@ array(1) { string(35) "otel_http_status_code_remapping.php" ["type"]=> string(3) "cli" - ["meta"]=> + ["attributes"]=> array(1) { ["http.status_code"]=> string(3) "200" diff --git a/tests/ext/pcntl/pcntl_fork_long_running_autoflush.phpt b/tests/ext/pcntl/pcntl_fork_long_running_autoflush.phpt index 2431d43fa1..2650487d0b 100644 --- a/tests/ext/pcntl/pcntl_fork_long_running_autoflush.phpt +++ b/tests/ext/pcntl/pcntl_fork_long_running_autoflush.phpt @@ -53,13 +53,13 @@ function long_running_entry_point() --EXPECTF-- [ddtrace] [warning] [%d] Error loading deferred integration DDTrace\Integrations\Pcntl\PcntlIntegration: Class not loaded and not autoloadable child is enabled -[ddtrace] [info] [%d] Flushing trace of size 1 to send-queue for %s +[ddtrace] [info] [%d] Flushing v1 trace of size 1 to send-queue for %s [ddtrace] [info] [%d] No finished traces to be sent to the agent parent is enabled -[ddtrace] [info] [%d] Flushing trace of size 3 to send-queue for %s +[ddtrace] [info] [%d] Flushing v1 trace of size 3 to send-queue for %s child is enabled -[ddtrace] [info] [%d] Flushing trace of size 1 to send-queue for %s +[ddtrace] [info] [%d] Flushing v1 trace of size 1 to send-queue for %s [ddtrace] [info] [%d] No finished traces to be sent to the agent parent is enabled -[ddtrace] [info] [%d] Flushing trace of size 3 to send-queue for %s +[ddtrace] [info] [%d] Flushing v1 trace of size 3 to send-queue for %s [ddtrace] [info] [%d] No finished traces to be sent to the agent diff --git a/tests/ext/peer_service_disabled_default.phpt b/tests/ext/peer_service_disabled_default.phpt index c425257494..8bab4d8311 100644 --- a/tests/ext/peer_service_disabled_default.phpt +++ b/tests/ext/peer_service_disabled_default.phpt @@ -23,9 +23,11 @@ var_dump(dd_clean_spans()); --EXPECTF-- array(1) { [0]=> - array(10) { + array(11) { ["trace_id"]=> string(%d) "%d" + ["trace_id_high"]=> + string(16) "%s" ["span_id"]=> string(%d) "%d" ["parent_id"]=> @@ -42,14 +44,14 @@ array(1) { string(33) "peer_service_disabled_default.php" ["type"]=> string(3) "cli" - ["meta"]=> + ["attributes"]=> array(3) { ["db.instance"]=> string(3) "db1" - ["foo"]=> - string(3) "bar" ["net.peer.name"]=> string(3) "xyz" + ["foo"]=> + string(3) "bar" } } -} \ No newline at end of file +} diff --git a/tests/ext/peer_service_honor_user_value.phpt b/tests/ext/peer_service_honor_user_value.phpt index 9551bda918..f1ef0d7601 100644 --- a/tests/ext/peer_service_honor_user_value.phpt +++ b/tests/ext/peer_service_honor_user_value.phpt @@ -29,9 +29,11 @@ var_dump(dd_clean_spans()); --EXPECTF-- array(2) { [0]=> - array(10) { + array(11) { ["trace_id"]=> string(%d) "%d" + ["trace_id_high"]=> + string(16) "%s" ["span_id"]=> string(%d) "%d" ["parent_id"]=> @@ -48,14 +50,14 @@ array(2) { string(33) "peer_service_honor_user_value.php" ["type"]=> string(3) "cli" - ["meta"]=> + ["attributes"]=> array(3) { - ["_dd.peer.service.source"]=> - string(12) "peer.service" ["db.instance"]=> string(3) "db1" ["peer.service"]=> string(3) "xyz" + ["_dd.peer.service.source"]=> + string(12) "peer.service" } } [1]=> @@ -78,14 +80,14 @@ array(2) { string(33) "peer_service_honor_user_value.php" ["type"]=> string(3) "cli" - ["meta"]=> + ["attributes"]=> array(3) { - ["_dd.peer.service.source"]=> - string(12) "peer.service" ["db.instance"]=> string(3) "db1" ["peer.service"]=> string(3) "xyz" + ["_dd.peer.service.source"]=> + string(12) "peer.service" } } -} \ No newline at end of file +} diff --git a/tests/ext/peer_service_remapping.phpt b/tests/ext/peer_service_remapping.phpt index ab7e0e6b5a..9d7483846c 100644 --- a/tests/ext/peer_service_remapping.phpt +++ b/tests/ext/peer_service_remapping.phpt @@ -34,9 +34,11 @@ var_dump(dd_clean_spans()); --EXPECTF-- array(2) { [0]=> - array(10) { + array(11) { ["trace_id"]=> string(%d) "%d" + ["trace_id_high"]=> + string(16) "%s" ["span_id"]=> string(%d) "%d" ["parent_id"]=> @@ -53,18 +55,18 @@ array(2) { string(26) "peer_service_remapping.php" ["type"]=> string(3) "cli" - ["meta"]=> + ["attributes"]=> array(6) { - ["_dd.peer.service.source"]=> - string(12) "peer.service" ["db.instance"]=> string(3) "db1" - ["foo"]=> - string(3) "bar" ["net.peer.name"]=> string(3) "xyz" + ["foo"]=> + string(3) "bar" ["peer.service"]=> string(3) "net" + ["_dd.peer.service.source"]=> + string(12) "peer.service" ["peer.service.remapped_from"]=> string(13) "net.peer.name" } @@ -89,20 +91,20 @@ array(2) { string(26) "peer_service_remapping.php" ["type"]=> string(3) "cli" - ["meta"]=> + ["attributes"]=> array(6) { - ["_dd.peer.service.source"]=> - string(11) "db.instance" ["db.instance"]=> string(3) "db1" - ["foo"]=> - string(3) "bar" ["net.peer.name"]=> string(3) "xyz" - ["peer.service"]=> - string(8) "database" + ["foo"]=> + string(3) "bar" + ["_dd.peer.service.source"]=> + string(11) "db.instance" ["peer.service.remapped_from"]=> string(3) "db1" + ["peer.service"]=> + string(8) "database" } } -} \ No newline at end of file +} diff --git a/tests/ext/peer_service_sources_not_serialized_when_set.phpt b/tests/ext/peer_service_sources_not_serialized_when_set.phpt index aa21c183cf..08fb6c0837 100644 --- a/tests/ext/peer_service_sources_not_serialized_when_set.phpt +++ b/tests/ext/peer_service_sources_not_serialized_when_set.phpt @@ -24,9 +24,11 @@ var_dump(dd_clean_spans()); HOOK METHOD arg array(1) { [0]=> - array(9) { + array(10) { ["trace_id"]=> string(%d) "%d" + ["trace_id_high"]=> + string(16) "%s" ["span_id"]=> string(%d) "%d" ["parent_id"]=> diff --git a/tests/ext/peer_service_sources_not_serialized_when_unset.phpt b/tests/ext/peer_service_sources_not_serialized_when_unset.phpt index c9b3ea26d3..4024a2bc69 100644 --- a/tests/ext/peer_service_sources_not_serialized_when_unset.phpt +++ b/tests/ext/peer_service_sources_not_serialized_when_unset.phpt @@ -23,9 +23,11 @@ var_dump(dd_clean_spans()); HOOK METHOD arg array(1) { [0]=> - array(9) { + array(10) { ["trace_id"]=> string(%d) "%d" + ["trace_id_high"]=> + string(16) "%s" ["span_id"]=> string(%d) "%d" ["parent_id"]=> diff --git a/tests/ext/peer_service_use_first_available_tag.phpt b/tests/ext/peer_service_use_first_available_tag.phpt index 06999a9cc8..def02e5d2e 100644 --- a/tests/ext/peer_service_use_first_available_tag.phpt +++ b/tests/ext/peer_service_use_first_available_tag.phpt @@ -36,9 +36,11 @@ var_dump(dd_clean_spans()); --EXPECTF-- array(3) { [0]=> - array(10) { + array(11) { ["trace_id"]=> string(%d) "%d" + ["trace_id_high"]=> + string(16) "%s" ["span_id"]=> string(%d) "%d" ["parent_id"]=> @@ -55,12 +57,12 @@ array(3) { string(40) "peer_service_use_first_available_tag.php" ["type"]=> string(3) "cli" - ["meta"]=> + ["attributes"]=> array(3) { - ["_dd.peer.service.source"]=> - string(13) "net.peer.name" ["net.peer.name"]=> string(15) "db1.example.com" + ["_dd.peer.service.source"]=> + string(13) "net.peer.name" ["peer.service"]=> string(15) "db1.example.com" } @@ -85,14 +87,14 @@ array(3) { string(40) "peer_service_use_first_available_tag.php" ["type"]=> string(3) "cli" - ["meta"]=> + ["attributes"]=> array(4) { - ["_dd.peer.service.source"]=> - string(11) "db.instance" ["db.instance"]=> string(3) "db1" ["net.peer.name"]=> string(15) "db1.example.com" + ["_dd.peer.service.source"]=> + string(11) "db.instance" ["peer.service"]=> string(3) "db1" } @@ -117,14 +119,14 @@ array(3) { string(40) "peer_service_use_first_available_tag.php" ["type"]=> string(3) "cli" - ["meta"]=> + ["attributes"]=> array(3) { - ["_dd.peer.service.source"]=> - string(11) "db.instance" ["db.instance"]=> string(3) "db1" + ["_dd.peer.service.source"]=> + string(11) "db.instance" ["peer.service"]=> string(3) "db1" } } -} \ No newline at end of file +} diff --git a/tests/ext/peer_service_wrong_values.phpt b/tests/ext/peer_service_wrong_values.phpt index fda0ae4ec8..840373fd8e 100644 --- a/tests/ext/peer_service_wrong_values.phpt +++ b/tests/ext/peer_service_wrong_values.phpt @@ -29,9 +29,11 @@ var_dump(dd_clean_spans()); --EXPECTF-- array(2) { [0]=> - array(10) { + array(11) { ["trace_id"]=> string(%d) "%d" + ["trace_id_high"]=> + string(16) "%s" ["span_id"]=> string(%d) "%d" ["parent_id"]=> @@ -48,12 +50,12 @@ array(2) { string(29) "peer_service_wrong_values.php" ["type"]=> string(3) "cli" - ["meta"]=> + ["attributes"]=> array(3) { - ["_dd.peer.service.source"]=> - string(11) "db.instance" ["db.instance"]=> string(8) "only_tag" + ["_dd.peer.service.source"]=> + string(11) "db.instance" ["peer.service"]=> string(8) "only_tag" } @@ -78,14 +80,14 @@ array(2) { string(29) "peer_service_wrong_values.php" ["type"]=> string(3) "cli" - ["meta"]=> + ["attributes"]=> array(3) { - ["_dd.peer.service.source"]=> - string(11) "db.instance" ["db.instance"]=> string(3) "foo" + ["_dd.peer.service.source"]=> + string(11) "db.instance" ["peer.service"]=> string(3) "foo" } } -} \ No newline at end of file +} diff --git a/tests/ext/priority_sampling/021-rule-name-as-glob-with-question-mark.phpt b/tests/ext/priority_sampling/021-rule-name-as-glob-with-question-mark.phpt index 4614f26881..f098415b9f 100644 --- a/tests/ext/priority_sampling/021-rule-name-as-glob-with-question-mark.phpt +++ b/tests/ext/priority_sampling/021-rule-name-as-glob-with-question-mark.phpt @@ -91,7 +91,8 @@ foreach ($tests as list($pattern, $name, $matches)) { ini_set("datadog.trace.sampling_rules", '[{"tags":{"foo":"' . $pattern . '"},"sample_rate":0.7},{"sample_rate": 0.3}]'); $root = \DDTrace\root_span(); - $root->meta["foo"] = $name; + // Typed, so the numeric/null rules apply ($meta stores strings). + $root->attributes["foo"] = $name; \DDTrace\get_priority_sampling(); diff --git a/tests/ext/priority_sampling/serialization-chunk.phpt b/tests/ext/priority_sampling/serialization-chunk.phpt index 11192c4223..6778267391 100644 --- a/tests/ext/priority_sampling/serialization-chunk.phpt +++ b/tests/ext/priority_sampling/serialization-chunk.phpt @@ -17,8 +17,8 @@ class ChangeSamplingDuringSerialization { $root = DDTrace\start_span(); $root->name = 'root'; -// Serialization converts this metric to a string tag and releases the old value. -$root->metrics['http.status_code'] = new ChangeSamplingDuringSerialization(); +// Serialization converts this attribute to a string tag and releases the old value. +$root->attributes['http.status_code'] = new ChangeSamplingDuringSerialization(); DDTrace\start_span()->name = 'keep.child'; DDTrace\close_span(); @@ -31,15 +31,15 @@ DDTrace\close_span(); DDTrace\close_span(); foreach (dd_trace_serialize_closed_spans() as $span) { - echo $span['name'], ': ', isset($span['metrics']['_dd.span_sampling.mechanism']) ? 'single span' : 'trace', "\n"; + echo $span['name'], ': ', isset($span['attributes']['_dd.span_sampling.mechanism']) ? 'single span' : 'trace', "\n"; } // Subsequent chunks must observe the new configuration. DDTrace\start_span()->name = 'keep.next'; DDTrace\close_span(); $span = dd_trace_serialize_closed_spans()[0]; -echo $span['name'], ': ', isset($span['metrics']['_dd.span_sampling.mechanism']) ? 'single span' : 'trace', "\n"; -var_dump($span['metrics']['_sampling_priority_v1']); +echo $span['name'], ': ', isset($span['attributes']['_dd.span_sampling.mechanism']) ? 'single span' : 'trace', "\n"; +var_dump($span['sampling_priority']); var_dump(dd_trace_serialize_closed_spans()); ?> @@ -49,6 +49,6 @@ unmatched: trace keep.child: single span keep.attached: single span keep.next: trace -float(2) +int(2) array(0) { } diff --git a/tests/ext/process_tags.phpt b/tests/ext/process_tags.phpt index 7e532482c0..23be23085a 100644 --- a/tests/ext/process_tags.phpt +++ b/tests/ext/process_tags.phpt @@ -20,8 +20,8 @@ $child_span->service = 'test_service'; $spans = dd_trace_serialize_closed_spans(); // Check if process tags are present -if (isset($spans[0]['meta']['_dd.tags.process'])) { - $processTags = $spans[0]['meta']['_dd.tags.process']; +if (isset($spans[0]['attributes']['_dd.tags.process'])) { + $processTags = $spans[0]['attributes']['_dd.tags.process']; echo "Process tags present in root span: YES\n"; echo "Process tags: $processTags\n"; @@ -39,7 +39,7 @@ if (isset($spans[0]['meta']['_dd.tags.process'])) { echo "Process tags present in root span: NO\n"; } -if (isset($spans[1]['meta']['_dd.process_tags'])) { +if (isset($spans[1]['attributes']['_dd.process_tags'])) { echo "Process tags present in child span: YES\n"; } else { echo "Process tags present in child span: NO\n"; diff --git a/tests/ext/referrer_extraction_01.phpt b/tests/ext/referrer_extraction_01.phpt index 6d41422406..ab6c26a1c5 100644 --- a/tests/ext/referrer_extraction_01.phpt +++ b/tests/ext/referrer_extraction_01.phpt @@ -15,26 +15,7 @@ foo=bar DDTrace\start_span(); DDTrace\close_span(); $spans = dd_trace_serialize_closed_spans(); -var_dump($spans[0]['meta']); +var_dump($spans[0]['attributes']['http.referrer_hostname'] ?? 'NOT SET'); ?> ---EXPECTF-- -array(9) { - ["_dd.p.dm"]=> - string(2) "-0" - ["_dd.p.tid"]=> - string(16) "%s" - ["_dd.sdk.otlp_export"]=> - string(5) "false" - ["_dd.tags.process"]=> - string(%d) "%s" - ["http.method"]=> - string(3) "GET" - ["http.status_code"]=> - string(3) "200" - ["http.url"]=> - string(25) "http://localhost:8888/foo" - ["runtime-id"]=> - string(36) "%s" - ["span.kind"]=> - string(6) "server" -} \ No newline at end of file +--EXPECT-- +string(7) "NOT SET" diff --git a/tests/ext/referrer_extraction_02.phpt b/tests/ext/referrer_extraction_02.phpt index ce4817172a..eb70044f44 100644 --- a/tests/ext/referrer_extraction_02.phpt +++ b/tests/ext/referrer_extraction_02.phpt @@ -15,28 +15,7 @@ foo=bar DDTrace\start_span(); DDTrace\close_span(); $spans = dd_trace_serialize_closed_spans(); -var_dump($spans[0]['meta']); +var_dump($spans[0]['attributes']['http.referrer_hostname'] ?? 'NOT SET'); ?> ---EXPECTF-- -array(10) { - ["_dd.p.dm"]=> - string(2) "-0" - ["_dd.p.tid"]=> - string(16) "%s" - ["_dd.sdk.otlp_export"]=> - string(5) "false" - ["_dd.tags.process"]=> - string(%d) "%s" - ["http.method"]=> - string(3) "GET" - ["http.referrer_hostname"]=> - string(11) "example.com" - ["http.status_code"]=> - string(3) "200" - ["http.url"]=> - string(25) "http://localhost:8888/foo" - ["runtime-id"]=> - string(36) "%s" - ["span.kind"]=> - string(6) "server" -} \ No newline at end of file +--EXPECT-- +string(11) "example.com" diff --git a/tests/ext/referrer_extraction_03.phpt b/tests/ext/referrer_extraction_03.phpt index 2a0f673213..a7cbf5c5c1 100644 --- a/tests/ext/referrer_extraction_03.phpt +++ b/tests/ext/referrer_extraction_03.phpt @@ -15,26 +15,7 @@ foo=bar DDTrace\start_span(); DDTrace\close_span(); $spans = dd_trace_serialize_closed_spans(); -var_dump($spans[0]['meta']); +var_dump($spans[0]['attributes']['http.referrer_hostname'] ?? 'NOT SET'); ?> ---EXPECTF-- -array(9) { - ["_dd.p.dm"]=> - string(2) "-0" - ["_dd.p.tid"]=> - string(16) "%s" - ["_dd.sdk.otlp_export"]=> - string(5) "false" - ["_dd.tags.process"]=> - string(%d) "%s" - ["http.method"]=> - string(3) "GET" - ["http.status_code"]=> - string(3) "200" - ["http.url"]=> - string(25) "http://localhost:8888/foo" - ["runtime-id"]=> - string(36) "%s" - ["span.kind"]=> - string(6) "server" -} \ No newline at end of file +--EXPECT-- +string(7) "NOT SET" diff --git a/tests/ext/referrer_extraction_04.phpt b/tests/ext/referrer_extraction_04.phpt index 181a768491..f14c33a500 100644 --- a/tests/ext/referrer_extraction_04.phpt +++ b/tests/ext/referrer_extraction_04.phpt @@ -15,26 +15,7 @@ foo=bar DDTrace\start_span(); DDTrace\close_span(); $spans = dd_trace_serialize_closed_spans(); -var_dump($spans[0]['meta']); +var_dump($spans[0]['attributes']['http.referrer_hostname'] ?? 'NOT SET'); ?> ---EXPECTF-- -array(9) { - ["_dd.p.dm"]=> - string(2) "-0" - ["_dd.p.tid"]=> - string(16) "%s" - ["_dd.sdk.otlp_export"]=> - string(5) "false" - ["_dd.tags.process"]=> - string(%d) "%s" - ["http.method"]=> - string(3) "GET" - ["http.status_code"]=> - string(3) "200" - ["http.url"]=> - string(25) "http://localhost:8888/foo" - ["runtime-id"]=> - string(36) "%s" - ["span.kind"]=> - string(6) "server" -} \ No newline at end of file +--EXPECT-- +string(7) "NOT SET" diff --git a/tests/ext/referrer_extraction_05.phpt b/tests/ext/referrer_extraction_05.phpt index edb0b56b5b..e2569f33b5 100644 --- a/tests/ext/referrer_extraction_05.phpt +++ b/tests/ext/referrer_extraction_05.phpt @@ -15,28 +15,7 @@ foo=bar DDTrace\start_span(); DDTrace\close_span(); $spans = dd_trace_serialize_closed_spans(); -var_dump($spans[0]['meta']); +var_dump($spans[0]['attributes']['http.referrer_hostname'] ?? 'NOT SET'); ?> ---EXPECTF-- -array(10) { - ["_dd.p.dm"]=> - string(2) "-0" - ["_dd.p.tid"]=> - string(16) "%s" - ["_dd.sdk.otlp_export"]=> - string(5) "false" - ["_dd.tags.process"]=> - string(%d) "%s" - ["http.method"]=> - string(3) "GET" - ["http.referrer_hostname"]=> - string(13) "[2001:db8::1]" - ["http.status_code"]=> - string(3) "200" - ["http.url"]=> - string(25) "http://localhost:8888/foo" - ["runtime-id"]=> - string(36) "%s" - ["span.kind"]=> - string(6) "server" -} \ No newline at end of file +--EXPECT-- +string(13) "[2001:db8::1]" diff --git a/tests/ext/request-replayer/analytics_event_v04.phpt b/tests/ext/request-replayer/analytics_event_v04.phpt new file mode 100644 index 0000000000..9196d71fdb --- /dev/null +++ b/tests/ext/request-replayer/analytics_event_v04.phpt @@ -0,0 +1,57 @@ +--TEST-- +analytics.event maps to the _dd1.sr.eausr metric on the v0.4 wire +--SKIPIF-- + [ + 'method' => 'PUT', + 'header' => ["Content-Type: application/json", "X-Datadog-Test-Session-Token: analytics_event_v04"], + 'content' => json_encode(["endpoints" => ["/v0.4/traces", "/v0.6/stats", "/v0.7/config"], "client_drop_p0s" => false, "version" => "7.66.0"]), +]]); +if (@file_get_contents("http://request-replayer/set-agent-info", false, $ctx) === false) { + die("skip: request-replayer not reachable"); +} +?> +--ENV-- +DD_TRACE_LOG_LEVEL=error,startup=off +DD_AGENT_HOST=request-replayer +DD_TRACE_AGENT_PORT=80 +DD_TRACE_AGENT_FLUSH_INTERVAL=333 +DD_TRACE_GENERATE_ROOT_SPAN=0 +DD_INSTRUMENTATION_TELEMETRY_ENABLED=0 +DD_TRACE_SIDECAR_TRACE_SENDER=0 +--INI-- +datadog.trace.agent_test_session_token=analytics_event_v04 +--FILE-- +clearDumpedData(); + +dd_trace_internal_fn('await_agent_info'); + +$s = \DDTrace\start_span(); +$s->name = "root"; +$s->meta["analytics.event"] = "true"; +$c = \DDTrace\start_span(); +$c->name = "child"; +$c->attributes["analytics.event"] = 0; +\DDTrace\close_span(); +\DDTrace\close_span(); +dd_trace_internal_fn("synchronous_flush"); + +$req = $rr->waitForRequest(function ($r) { return strpos($r["uri"], "traces") !== false; }); +echo "uri=" . $req["uri"] . "\n"; +$spans = json_decode($req["body"], true)[0]; +usort($spans, function ($a, $b) { return strcmp($a["name"], $b["name"]); }); +foreach ($spans as $span) { + echo $span["name"], ": eausr=", var_export($span["metrics"]["_dd1.sr.eausr"] ?? null, true), + " analytics.event=", isset($span["meta"]["analytics.event"]) || isset($span["metrics"]["analytics.event"]) ? "kept" : "removed", "\n"; +} +?> +--EXPECT-- +uri=/v0.4/traces +child: eausr=0 analytics.event=removed +root: eausr=1 analytics.event=removed diff --git a/tests/ext/request-replayer/client_side_stats_dd_tags_env.phpt b/tests/ext/request-replayer/client_side_stats_dd_tags_env.phpt new file mode 100644 index 0000000000..98b0ac8d73 --- /dev/null +++ b/tests/ext/request-replayer/client_side_stats_dd_tags_env.phpt @@ -0,0 +1,63 @@ +--TEST-- +Client-side span stats bucket by DD_TAGS env/version when DD_ENV/DD_VERSION are unset +--SKIPIF-- + += 80100) { + echo "nocache\n"; +} +$ctx = stream_context_create([ + 'http' => [ + 'method' => 'PUT', + 'header' => [ + 'Content-Type: application/json', + 'X-Datadog-Test-Session-Token: client_side_stats_dd_tags', + ], + 'content' => json_encode(['version' => '7.65.0', 'client_drop_p0s' => true]), + ] +]); +file_get_contents('http://request-replayer/set-agent-info', false, $ctx); +?> +--ENV-- +DD_AGENT_HOST=request-replayer +DD_TRACE_AGENT_PORT=80 +DD_TRACE_AGENT_FLUSH_INTERVAL=333 +DD_TRACE_GENERATE_ROOT_SPAN=0 +DD_INSTRUMENTATION_TELEMETRY_ENABLED=0 +DD_TRACE_SIDECAR_TRACE_SENDER=1 +DD_TRACE_STATS_COMPUTATION_ENABLED=1 +DD_TAGS=env:staging,version:9.9.9-tags +--INI-- +datadog.trace.agent_test_session_token=client_side_stats_dd_tags +--FILE-- +name = "web.request"; +$root->resource = "GET /test"; +$root->service = "stats-test-service"; +\DDTrace\close_span(); + +dd_trace_internal_fn('synchronous_flush', 5000); +$rr->waitForDataAndReplay(); + +$statsRequest = $rr->waitForStats(); +$payload = json_decode($statsRequest['body'], true); + +// env/version come from DD_TAGS (merged into meta) since DD_ENV/DD_VERSION are unset. Without the +// meta fallback in the stats path they would bucket by empty strings while traces carry the values. +echo "env: " . $payload['Env'] . "\n"; +echo "version: " . $payload['Version'] . "\n"; + +?> +--EXPECT-- +env: staging +version: 9.9.9-tags diff --git a/tests/ext/request-replayer/client_side_stats_inferred_span_sampling.phpt b/tests/ext/request-replayer/client_side_stats_inferred_span_sampling.phpt new file mode 100644 index 0000000000..200b7860d8 --- /dev/null +++ b/tests/ext/request-replayer/client_side_stats_inferred_span_sampling.phpt @@ -0,0 +1,69 @@ +--TEST-- +Single-span-sampled p0 root with an inferred span and agent stats does not crash (F1 NULL-guard) +--SKIPIF-- + += 80100) { + echo "nocache\n"; +} +$ctx = stream_context_create([ + 'http' => [ + 'method' => 'PUT', + 'header' => [ + 'Content-Type: application/json', + 'X-Datadog-Test-Session-Token: css_inferred_span_sampling', + ], + 'content' => json_encode(['version' => '7.65.0', 'client_drop_p0s' => true]), + ] +]); +file_get_contents('http://request-replayer/set-agent-info', false, $ctx); +?> +--ENV-- +DD_AGENT_HOST=request-replayer +DD_TRACE_AGENT_PORT=80 +DD_TRACE_AGENT_FLUSH_INTERVAL=333 +DD_TRACE_GENERATE_ROOT_SPAN=0 +DD_INSTRUMENTATION_TELEMETRY_ENABLED=0 +DD_TRACE_SIDECAR_TRACE_SENDER=1 +DD_TRACE_STATS_COMPUTATION_ENABLED=1 +DD_SERVICE=aws-server +DD_TRACE_SAMPLE_RATE=0 +DD_SPAN_SAMPLING_RULES=[{"service":"aws-server","name":"web.request","sample_rate":1.0}] +DD_TRACE_INFERRED_PROXY_SERVICES_ENABLED=1 +HTTP_X_DD_PROXY=aws-apigateway +HTTP_X_DD_PROXY_REQUEST_TIME_MS=1742285908783 +HTTP_X_DD_PROXY_PATH=/test +HTTP_X_DD_PROXY_HTTPMETHOD=GET +HTTP_X_DD_PROXY_DOMAIN_NAME=example.com +HTTP_X_DD_PROXY_STAGE=aws-prod +METHOD=GET +SERVER_NAME=localhost:8888 +SCRIPT_NAME=/foo.php +REQUEST_URI=/foo +DD_TRACE_DEBUG_PRNG_SEED=42 +--INI-- +datadog.trace.agent_test_session_token=css_inferred_span_sampling +--FILE-- +name = "web.request"; +\DDTrace\close_span(); + +echo "before flush\n"; +// Serialization runs here: the p0 root is single-span-sampled (so it builds), then its inferred +// parent recurses and is dropped into the stats concentrator, returning the {0} sentinel sink. +// Without the NULL guard the parent's transfer/set_error deref a NULL builder and crash. +dd_trace_internal_fn('synchronous_flush', 5000); +echo "after flush\n"; + +?> +--EXPECT-- +before flush +after flush diff --git a/tests/ext/request-replayer/dd_trace_exception_span_event.phpt b/tests/ext/request-replayer/dd_trace_exception_span_event.phpt index 44d538e596..a4d0c5e2dc 100644 --- a/tests/ext/request-replayer/dd_trace_exception_span_event.phpt +++ b/tests/ext/request-replayer/dd_trace_exception_span_event.phpt @@ -8,6 +8,7 @@ DD_TRACE_AGENT_PORT=80 DD_TRACE_AGENT_FLUSH_INTERVAL=333 DD_TRACE_GENERATE_ROOT_SPAN=0 DD_INSTRUMENTATION_TELEMETRY_ENABLED=0 +DD_TRACE_SIDECAR_TRACE_SENDER=0 --INI-- datadog.trace.agent_test_session_token=dd_trace_exception_span_event --FILE-- @@ -49,8 +50,40 @@ $root = json_decode($replay["body"], true); $spans = $root["chunks"][0]["spans"] ?? $root[0]; $span = $spans[0]; -var_dump($span['meta']['events']); +// This test pins the in-process sender (v0.4-only): events are legacy `events` meta JSON, no +// `span_events` field. Handle both shapes anyway; ddAnyValueToPhp() unwraps the v1 AnyValue form. +function ddAnyValueToPhp($v) { + if (!is_array($v) || !array_key_exists('type', $v)) { + return $v; // already a plain value (legacy `events` meta JSON) + } + switch ($v['type']) { + case 0: return $v['string_value']; + case 1: return $v['bool_value']; + case 2: return $v['int_value']; + case 3: return $v['double_value']; + case 4: return array_map('ddAnyValueToPhp', $v['array_value']['values']); + default: return $v; + } +} +if (isset($span['span_events'])) { + $event = $span['span_events'][0]; +} else { + $event = json_decode($span['meta']['events'], true)[0]; +} +$attrs = $event['attributes']; +var_dump($event['name']); +// The user-provided "exception.message" overrides the exception's own message (builder last-write-wins). +var_dump(ddAnyValueToPhp($attrs['exception.message'])); +var_dump(ddAnyValueToPhp($attrs['exception.type'])); +var_dump(ddAnyValueToPhp($attrs['custom.attribute'])); +var_dump(ddAnyValueToPhp($attrs['exception.stacktrace'])); ?> --EXPECTF-- Caught exception: Exception in method -string(%d) "[{"name":"exception","time_unix_nano":%d,"attributes":{"exception.message":"override message","exception.type":"Exception","exception.stacktrace":"#0 %s(%d): ExceptionClass->{%s}()\n#1 %s(%d): ExceptionClass->exceptionMethod()\n#2 {main}","custom.attribute":"custom value"}}]" +string(9) "exception" +string(16) "override message" +string(9) "Exception" +string(12) "custom value" +string(%d) "#0 %s(%d): ExceptionClass->{%s}() +#1 %s(%d): ExceptionClass->exceptionMethod() +#2 {main}" diff --git a/tests/ext/request-replayer/dd_trace_span_event.phpt b/tests/ext/request-replayer/dd_trace_span_event.phpt index 9516074caf..0e9c1a6224 100644 --- a/tests/ext/request-replayer/dd_trace_span_event.phpt +++ b/tests/ext/request-replayer/dd_trace_span_event.phpt @@ -8,6 +8,7 @@ DD_TRACE_AGENT_PORT=80 DD_TRACE_AGENT_FLUSH_INTERVAL=333 DD_TRACE_GENERATE_ROOT_SPAN=0 DD_INSTRUMENTATION_TELEMETRY_ENABLED=0 +DD_TRACE_SIDECAR_TRACE_SENDER=0 --INI-- datadog.trace.agent_test_session_token=dd_trace_span_event --FILE-- @@ -41,8 +42,46 @@ $replay = $rr->waitForDataAndReplay(); $root = json_decode($replay["body"], true); $spans = $root["chunks"][0]["spans"] ?? $root[0]; $span = $spans[0]; -var_dump($span['meta']['events']); +// This test pins the in-process sender (v0.4-only): events are legacy `events` meta JSON. Handle +// the v1 AnyValue shape too; ddAnyValueToPhp() unwraps it to the same plain PHP value. +function ddAnyValueToPhp($v) { + if (!is_array($v) || !array_key_exists('type', $v)) { + return $v; // already a plain value (legacy `events` meta JSON) + } + switch ($v['type']) { + case 0: return $v['string_value']; + case 1: return $v['bool_value']; + case 2: return $v['int_value']; + case 3: return $v['double_value']; + case 4: return array_map('ddAnyValueToPhp', $v['array_value']['values']); + default: return $v; + } +} +if (isset($span['span_events'])) { + $event = $span['span_events'][0]; +} else { + $event = json_decode($span['meta']['events'], true)[0]; +} +$attrs = $event['attributes']; +var_dump($event['name'], $event['time_unix_nano']); +var_dump(ddAnyValueToPhp($attrs['arg1'])); +var_dump(ddAnyValueToPhp($attrs['int_array'])); +var_dump(ddAnyValueToPhp($attrs['string_array'])); ?> --EXPECT-- In testMethod -string(134) "[{"name":"event-name","time_unix_nano":1720037568765201300,"attributes":{"arg1":"value1","int_array":[3,4],"string_array":["5","6"]}}]" +string(10) "event-name" +int(1720037568765201300) +string(6) "value1" +array(2) { + [0]=> + int(3) + [1]=> + int(4) +} +array(2) { + [0]=> + string(1) "5" + [1]=> + string(1) "6" +} diff --git a/tests/ext/request-replayer/dd_trace_span_link_with_exception.phpt b/tests/ext/request-replayer/dd_trace_span_link_with_exception.phpt index 6dbbca8840..9795c149b9 100644 --- a/tests/ext/request-replayer/dd_trace_span_link_with_exception.phpt +++ b/tests/ext/request-replayer/dd_trace_span_link_with_exception.phpt @@ -48,14 +48,30 @@ try { echo 'Caught exception: ' . $e->getMessage() . PHP_EOL; } -$replay = $rr->waitForDataAndReplay(); +// Find the request carrying our Foo.bar span (the wire may be v0.4 or v1 depending on which +// protocol the sidecar has negotiated). +$replay = $rr->waitForRequest(function ($r) { + if (strpos($r["uri"], "traces") === false) return false; + $b = json_decode($r["body"], true); + $s = $b["chunks"][0]["spans"][0] ?? ($b[0][0] ?? null); + return $s && ($s["name"] ?? null) === "Foo.bar"; +}); $root = json_decode($replay["body"], true); $spans = $root["chunks"][0]["spans"] ?? $root[0]; $span = $spans[0]; var_dump($span['meta']['error.message']); var_dump($span['meta']['error.type']); var_dump($span['meta']['error.stack']); -var_dump($span['meta']['_dd.span_links']); +// Span links are carried natively (numeric ids) on the v0.4 downgrade wire and as the +// _dd.span_links meta JSON (zero-padded hex ids) on the v1 wire. Both encode the same 128-bit +// trace id (hex 0x42) and span id (0x6); normalise to ":". +if (isset($span['span_links'])) { + $link = $span['span_links'][0]; + printf("link=%x:%x\n", $link['trace_id'], $link['span_id']); +} else { + $link = json_decode($span['meta']['_dd.span_links'], true)[0]; + printf("link=%x:%x\n", hexdec($link['trace_id']), hexdec($link['span_id'])); +} ?> --EXPECTF-- Caught exception: Oops! @@ -64,4 +80,4 @@ string(9) "Exception" string(%d) "#0 %sdd_trace_span_link_with_exception.php(12): Foo->doException() #1 %sdd_trace_span_link_with_exception.php(33): Foo->bar() #2 {main}" -string(33) "[{"trace_id":"42","span_id":"6"}]" +link=42:6 diff --git a/tests/ext/request-replayer/serializer_wire_inprocess_multitrace.phpt b/tests/ext/request-replayer/serializer_wire_inprocess_multitrace.phpt new file mode 100644 index 0000000000..1c3aff755f --- /dev/null +++ b/tests/ext/request-replayer/serializer_wire_inprocess_multitrace.phpt @@ -0,0 +1,67 @@ +--TEST-- +In-process sender frames every trace of a multi-trace flush (per-trace coms group id) +--SKIPIF-- + [ + 'method' => 'PUT', + 'header' => ["Content-Type: application/json", "X-Datadog-Test-Session-Token: inproc_multitrace"], + 'content' => json_encode(["endpoints" => ["/v0.4/traces", "/v0.6/stats", "/v0.7/config"], "client_drop_p0s" => false, "version" => "7.66.0"]), +]]); +if (@file_get_contents("http://request-replayer/set-agent-info", false, $ctx) === false) { + die("skip: request-replayer not reachable"); +} +?> +--ENV-- +DD_TRACE_LOG_LEVEL=info,startup=off +DD_AGENT_HOST=request-replayer +DD_TRACE_AGENT_PORT=80 +DD_TRACE_AGENT_FLUSH_INTERVAL=333 +DD_TRACE_GENERATE_ROOT_SPAN=0 +DD_TRACE_AUTO_FLUSH_ENABLED=0 +DD_INSTRUMENTATION_TELEMETRY_ENABLED=0 +DD_TRACE_SIDECAR_TRACE_SENDER=0 +--INI-- +datadog.trace.agent_test_session_token=inproc_multitrace +--FILE-- +clearDumpedData(); + +dd_trace_internal_fn('await_agent_info'); + +// Three independent root traces closed before a single flush. Each closed span +// stack becomes its own v0.4 trace; the background sender must frame all three +// (outer msgpack array of N) so the agent keeps every trace, not just the first. +for ($i = 0; $i < 3; $i++) { + $s = \DDTrace\start_trace_span(); + $s->name = "root$i"; + $s->service = "svc"; + \DDTrace\close_span(); +} +// One flush serializes all three closed traces together, exercising the +// per-trace coms group-id path; synchronous_flush then pushes the buffer. +\DDTrace\flush(); +dd_trace_internal_fn("synchronous_flush"); + +$req = $rr->waitForRequest(function ($r) { return strpos($r["uri"], "/v0.4/traces") !== false; }); +$traces = json_decode($req["body"], true); +echo "uri=" . $req["uri"] . "\n"; +echo "trace_count_header=" . $req["headers"]["X-Datadog-Trace-Count"] . "\n"; +echo "trace_count=" . count($traces) . "\n"; +$names = array_map(function ($t) { return $t[0]["name"]; }, $traces); +sort($names); +echo "names=" . implode(",", $names) . "\n"; +?> +--EXPECTF-- +[ddtrace] [info] [%d] Flushing 3 v0.4 trace(s) to send-queue for http://request-replayer:80 +uri=/v0.4/traces +trace_count_header=3 +trace_count=3 +names=root0,root1,root2 +[ddtrace] [info] [%d] No finished traces to be sent to the agent diff --git a/tests/ext/request-replayer/serializer_wire_inprocess_v04.phpt b/tests/ext/request-replayer/serializer_wire_inprocess_v04.phpt new file mode 100644 index 0000000000..b49a8d6700 --- /dev/null +++ b/tests/ext/request-replayer/serializer_wire_inprocess_v04.phpt @@ -0,0 +1,61 @@ +--TEST-- +In-process sender + non-v1 agent serializes the v0.4 wire (/v0.4/traces, no chunks) +--SKIPIF-- + [ + 'method' => 'PUT', + 'header' => ["Content-Type: application/json", "X-Datadog-Test-Session-Token: serializer_wire_v04"], + 'content' => json_encode(["endpoints" => ["/v0.4/traces", "/v0.6/stats", "/v0.7/config"], "client_drop_p0s" => false, "version" => "7.66.0"]), +]]); +if (@file_get_contents("http://request-replayer/set-agent-info", false, $ctx) === false) { + die("skip: request-replayer not reachable"); +} +?> +--ENV-- +DD_TRACE_LOG_LEVEL=info,startup=off +DD_AGENT_HOST=request-replayer +DD_TRACE_AGENT_PORT=80 +DD_TRACE_AGENT_FLUSH_INTERVAL=333 +DD_TRACE_GENERATE_ROOT_SPAN=0 +DD_INSTRUMENTATION_TELEMETRY_ENABLED=0 +DD_TRACE_SIDECAR_TRACE_SENDER=0 +--INI-- +datadog.trace.agent_test_session_token=serializer_wire_v04 +--FILE-- +clearDumpedData(); + +// Decide the wire before flushing (reads the non-v1 /info above). +dd_trace_internal_fn('await_agent_info'); + +$s = \DDTrace\start_span(); +$s->name = "root"; +$s->service = "svc"; +$s->meta["span.kind"] = "server"; +\DDTrace\close_span(); +dd_trace_internal_fn("synchronous_flush"); + +$req = $rr->waitForRequest(function ($r) { return strpos($r["uri"], "traces") !== false; }); +$root = json_decode($req["body"], true); +$spans = $root["chunks"][0]["spans"] ?? $root[0]; +echo "uri=" . $req["uri"] . "\n"; +echo "has_chunks=" . (isset($root['chunks']) ? "yes" : "no") . "\n"; +echo "span_name=" . $spans[0]["name"] . "\n"; +echo "priority=" . $spans[0]["metrics"]["_sampling_priority_v1"] . "\n"; +echo "span_kind=" . $spans[0]["meta"]["span.kind"] . "\n"; +?> +--EXPECTF-- +[ddtrace] [info] [%d] Flushing %d v0.4 trace(s) to send-queue for http://request-replayer:80 +uri=/v0.4/traces +has_chunks=no +span_name=root +priority=1 +span_kind=server +[ddtrace] [info] [%d] No finished traces to be sent to the agent diff --git a/tests/ext/request-replayer/serializer_wire_inprocess_v1.phpt b/tests/ext/request-replayer/serializer_wire_inprocess_v1.phpt new file mode 100644 index 0000000000..09653ef7ec --- /dev/null +++ b/tests/ext/request-replayer/serializer_wire_inprocess_v1.phpt @@ -0,0 +1,53 @@ +--TEST-- +In-process sender ignores a v1-capable agent and still serializes the v0.4 wire (/v0.4/traces) +--DESCRIPTION-- +Locks the in-process sender -> v0.4 wire mapping even when the agent advertises /v1.0/traces. The +in-process (<=8.2 / DD_TRACE_SIDECAR_TRACE_SENDER=0) sender ALWAYS downgrades the native V1 builder +to v0.4 and posts each trace to /v0.4/traces; a native V1 payload is a single msgpack MAP that the +background sender's array-of-1 framing (comms_php.c mpack_expect_array_match) cannot parse, so the +in-process path never uses /v1.0/traces regardless of agent capability. +--SKIPIF-- + +--ENV-- +DD_TRACE_LOG_LEVEL=info,startup=off +DD_AGENT_HOST=request-replayer +DD_TRACE_AGENT_PORT=80 +DD_TRACE_AGENT_FLUSH_INTERVAL=333 +DD_TRACE_GENERATE_ROOT_SPAN=0 +DD_INSTRUMENTATION_TELEMETRY_ENABLED=0 +DD_TRACE_SIDECAR_TRACE_SENDER=0 +--INI-- +datadog.trace.agent_test_session_token=serializer_wire_inprocess_v1 +--FILE-- +clearDumpedData(); + +// The default request-replayer /info advertises /v1.0/traces; confirm the in-process sender +// still downgrades to v0.4. +dd_trace_internal_fn('await_agent_info'); + +$s = \DDTrace\start_span(); +$s->name = "root"; +$s->service = "svc"; +\DDTrace\close_span(); +dd_trace_internal_fn("synchronous_flush"); + +$req = $rr->waitForRequest(function ($r) { return strpos($r["uri"], "traces") !== false; }); +$root = json_decode($req["body"], true); +$spans = $root["chunks"][0]["spans"] ?? $root[0]; +echo "uri=" . $req["uri"] . "\n"; +echo "has_chunks=" . (isset($root['chunks']) ? "yes" : "no") . "\n"; +echo "span_name=" . $spans[0]["name"] . "\n"; +?> +--EXPECTF-- +[ddtrace] [info] [%d] Flushing %d v0.4 trace(s) to send-queue for http://request-replayer:80 +uri=/v0.4/traces +has_chunks=no +span_name=root +[ddtrace] [info] [%d] No finished traces to be sent to the agent diff --git a/tests/ext/request-replayer/serializer_wire_sidecar_forced_v04.phpt b/tests/ext/request-replayer/serializer_wire_sidecar_forced_v04.phpt new file mode 100644 index 0000000000..8d70aeabf4 --- /dev/null +++ b/tests/ext/request-replayer/serializer_wire_sidecar_forced_v04.phpt @@ -0,0 +1,43 @@ +--TEST-- +DD_TRACE_AGENT_PROTOCOL_VERSION=0.4 keeps the sidecar on /v0.4/traces although the agent advertises /v1.0/traces +--SKIPIF-- + +--ENV-- +DD_TRACE_LOG_LEVEL=error,startup=off +DD_AGENT_HOST=request-replayer +DD_TRACE_AGENT_PORT=80 +DD_TRACE_AGENT_FLUSH_INTERVAL=333 +DD_TRACE_GENERATE_ROOT_SPAN=0 +DD_INSTRUMENTATION_TELEMETRY_ENABLED=0 +DD_TRACE_SIDECAR_TRACE_SENDER=1 +DD_TRACE_AGENT_PROTOCOL_VERSION=0.4 +--INI-- +datadog.trace.agent_test_session_token=serializer_wire_sidecar_forced_v04 +--FILE-- +clearDumpedData(); + +// Without the setting the sidecar switches to v1 once its /info fetch completes (well within 3s). +$v04 = $v1 = 0; +for ($i = 0; $i < 30; $i++) { + $s = \DDTrace\start_span(); + $s->name = "root"; + \DDTrace\close_span(); + dd_trace_internal_fn("synchronous_flush"); + usleep(100000); + foreach (($rr->replayAllRequests() ?: []) as $r) { + if (strpos($r["uri"], "/v1.0/traces") !== false) $v1++; + if (strpos($r["uri"], "/v0.4/traces") !== false) $v04++; + } +} +echo "v0.4 requests: ", $v04 > 0 ? "some" : "none", "\n"; +echo "v1 requests: $v1\n"; +?> +--EXPECT-- +v0.4 requests: some +v1 requests: 0 diff --git a/tests/ext/request-replayer/serializer_wire_sidecar_v1.phpt b/tests/ext/request-replayer/serializer_wire_sidecar_v1.phpt new file mode 100644 index 0000000000..6e59429000 --- /dev/null +++ b/tests/ext/request-replayer/serializer_wire_sidecar_v1.phpt @@ -0,0 +1,56 @@ +--TEST-- +Sidecar sender + v1-capable agent serializes the v1 wire (/v1.0/traces, chunks) +--SKIPIF-- + +--ENV-- +DD_TRACE_LOG_LEVEL=error,startup=off +DD_AGENT_HOST=request-replayer +DD_TRACE_AGENT_PORT=80 +DD_TRACE_AGENT_FLUSH_INTERVAL=333 +DD_TRACE_GENERATE_ROOT_SPAN=0 +DD_INSTRUMENTATION_TELEMETRY_ENABLED=0 +DD_TRACE_SIDECAR_TRACE_SENDER=1 +--INI-- +datadog.trace.agent_test_session_token=serializer_wire_sidecar_v1 +--FILE-- +clearDumpedData(); + +// The sidecar sends v0.4 until its own /info fetch has advertised /v1.0/traces, and may batch +// several traces per payload: resend "root" until it shows up in any chunk of a v1 request. +$req = null; +$foundSpan = null; +for ($i = 0; $i < 100 && $req === null; $i++) { + $s = \DDTrace\start_span(); + $s->name = "root"; + $s->service = "svc"; + \DDTrace\close_span(); + dd_trace_internal_fn("synchronous_flush"); + usleep(100000); + foreach (($rr->replayAllRequests() ?: []) as $r) { + if (strpos($r["uri"], "/v1.0/traces") === false) continue; + foreach ((json_decode($r["body"], true)["chunks"] ?? []) as $chunk) { + foreach (($chunk["spans"] ?? []) as $span) { + if (($span["name"] ?? null) === "root" && ($span["service"] ?? null) === "svc") { + $req = $r; + $foundSpan = $span; + } + } + } + } +} +echo "uri=" . ($req["uri"] ?? "none") . "\n"; +// Derived from the matched span itself, not from $req's truthiness: proves the +// v1 payload actually carries the span's own name/service, not just any chunk. +echo "span_name=" . ($foundSpan["name"] ?? "none") . "\n"; +echo "span_service=" . ($foundSpan["service"] ?? "none") . "\n"; +?> +--EXPECT-- +uri=/v1.0/traces +span_name=root +span_service=svc diff --git a/tests/ext/request-replayer/span_attributes_v04_wire.phpt b/tests/ext/request-replayer/span_attributes_v04_wire.phpt new file mode 100644 index 0000000000..360a958287 --- /dev/null +++ b/tests/ext/request-replayer/span_attributes_v04_wire.phpt @@ -0,0 +1,69 @@ +--TEST-- +Typed SpanData::$attributes on the v0.4 wire: numbers go to metrics, bools and strings to meta, nested values flatten +--SKIPIF-- + [ + 'method' => 'PUT', + 'header' => ["Content-Type: application/json", "X-Datadog-Test-Session-Token: span_attributes_v04"], + 'content' => json_encode(["endpoints" => ["/v0.4/traces", "/v0.6/stats", "/v0.7/config"], "client_drop_p0s" => false, "version" => "7.66.0"]), +]]); +if (@file_get_contents("http://request-replayer/set-agent-info", false, $ctx) === false) { + die("skip: request-replayer not reachable"); +} +?> +--ENV-- +DD_TRACE_LOG_LEVEL=info,startup=off +DD_AGENT_HOST=request-replayer +DD_TRACE_AGENT_PORT=80 +DD_TRACE_AGENT_FLUSH_INTERVAL=333 +DD_TRACE_GENERATE_ROOT_SPAN=0 +DD_INSTRUMENTATION_TELEMETRY_ENABLED=0 +DD_TRACE_SIDECAR_TRACE_SENDER=0 +--INI-- +datadog.trace.agent_test_session_token=span_attributes_v04 +--FILE-- +clearDumpedData(); + +dd_trace_internal_fn('await_agent_info'); + +$s = \DDTrace\start_span(); +$s->name = "root"; +$s->attributes = ['int' => 42, 'float' => 1.5, 'bool' => true, 'false' => false, 'string' => 's', 'list' => [1, 'two'], 'map' => ['k' => 'v']]; +$s->meta['string'] = 'meta wins'; +$s->meta['meta_only'] = 'm'; +$s->metrics['int'] = 7; +\DDTrace\close_span(); +dd_trace_internal_fn("synchronous_flush"); + +$req = $rr->waitForRequest(function ($r) { return strpos($r["uri"], "traces") !== false; }); +$span = json_decode($req["body"], true)[0][0]; +echo "uri=" . $req["uri"] . "\n"; +foreach (['meta', 'metrics'] as $bucket) { + foreach (['int', 'float', 'bool', 'false', 'string', 'list.0', 'list.1', 'map.k', 'meta_only'] as $key) { + if (isset($span[$bucket][$key])) { + echo "$bucket.$key=", var_export($span[$bucket][$key], true), "\n"; + } + } +} +?> +--EXPECTF-- +[ddtrace] [info] [%d] Flushing %d v0.4 trace(s) to send-queue for http://request-replayer:80 +uri=/v0.4/traces +meta.bool='true' +meta.false='false' +meta.string='meta wins' +meta.list.1='two' +meta.map.k='v' +meta.meta_only='m' +metrics.int=7 +metrics.float=1.5 +metrics.list.0=1 +[ddtrace] [info] [%d] No finished traces to be sent to the agent diff --git a/tests/ext/request-replayer/span_link_event_attributes_v04_wire.phpt b/tests/ext/request-replayer/span_link_event_attributes_v04_wire.phpt new file mode 100644 index 0000000000..2150b976dc --- /dev/null +++ b/tests/ext/request-replayer/span_link_event_attributes_v04_wire.phpt @@ -0,0 +1,76 @@ +--TEST-- +v0.4 native span_links and legacy events JSON print floats like json_encode and objects as property maps +--SKIPIF-- + [ + 'method' => 'PUT', + 'header' => ["Content-Type: application/json", "X-Datadog-Test-Session-Token: span_link_event_attributes_v04_wire"], + 'content' => json_encode(["endpoints" => ["/v0.4/traces", "/v0.6/stats", "/v0.7/config"], "client_drop_p0s" => false, "version" => "7.66.0"]), +]]); +if (@file_get_contents("http://request-replayer/set-agent-info", false, $ctx) === false) { + die("skip: request-replayer not reachable"); +} +?> +--ENV-- +DD_AGENT_HOST=request-replayer +DD_TRACE_AGENT_PORT=80 +DD_TRACE_AGENT_FLUSH_INTERVAL=333 +DD_TRACE_GENERATE_ROOT_SPAN=0 +DD_INSTRUMENTATION_TELEMETRY_ENABLED=0 +DD_TRACE_SIDECAR_TRACE_SENDER=0 +--INI-- +datadog.trace.agent_test_session_token=span_link_event_attributes_v04_wire +serialize_precision=-1 +--FILE-- +clearDumpedData(); +dd_trace_internal_fn('await_agent_info'); + +class Pub { public $a = 1; protected $prot = 'p'; private $priv = 'x'; } + +$floats = [1e20, 1e-5, 0.1, 1.5, 1e17, 123456789012345678.0, -0.0, 3.0]; +$s = \DDTrace\start_span(); +$s->name = "root"; +$link = new \DDTrace\SpanLink(); +$link->traceId = str_repeat('0', 31) . '1'; +$link->spanId = str_repeat('0', 15) . '2'; +$link->attributes = ['floats' => $floats]; +$s->links[] = $link; +$s->events[] = new \DDTrace\SpanEvent('evt', ['f' => 1e20, 'floats' => $floats, 'obj' => new Pub, 'nested' => ['k' => [1e-5]]], 1); +\DDTrace\close_span(); +dd_trace_internal_fn("synchronous_flush"); + +$req = $rr->waitForRequest(function ($r) { return strpos($r["uri"], "traces") !== false; }); +$span = json_decode($req["body"], true)[0][0]; +$meta = $span["meta"]; +$expected = json_encode($floats); +echo $expected, "\n"; +// Native links carry nested values as a JSON string, events as raw JSON: both must print json_encode's floats. +var_dump(!isset($meta["_dd.span_links"]) && $span["span_links"][0]["attributes"]["floats"] === $expected); +var_dump(strpos($meta["events"], '"floats":' . $expected) !== false); +var_dump(strpos($meta["events"], '"f":1.0e+20') !== false); +$attrs = json_decode($meta["events"], true)[0]["attributes"]; +var_dump($attrs["obj"], $attrs["nested"]); +?> +--EXPECT-- +[1.0e+20,1.0e-5,0.1,1.5,1.0e+17,1.2345678901234568e+17,-0,3] +bool(true) +bool(true) +bool(true) +array(1) { + ["a"]=> + int(1) +} +array(1) { + ["k"]=> + array(1) { + [0]=> + float(1.0E-5) + } +} diff --git a/tests/ext/request-replayer/top_level_marked_on_v1_wire.phpt b/tests/ext/request-replayer/top_level_marked_on_v1_wire.phpt new file mode 100644 index 0000000000..e98e70adf9 --- /dev/null +++ b/tests/ext/request-replayer/top_level_marked_on_v1_wire.phpt @@ -0,0 +1,64 @@ +--TEST-- +The sidecar sender marks _dd.top_level on the V1 wire (local root and service changes) without stats computation +--SKIPIF-- + +--ENV-- +DD_TRACE_LOG_LEVEL=error,startup=off +DD_AGENT_HOST=request-replayer +DD_TRACE_AGENT_PORT=80 +DD_TRACE_AGENT_FLUSH_INTERVAL=333 +DD_TRACE_GENERATE_ROOT_SPAN=0 +DD_INSTRUMENTATION_TELEMETRY_ENABLED=0 +DD_TRACE_SIDECAR_TRACE_SENDER=1 +DD_TRACE_STATS_COMPUTATION_ENABLED=0 +--INI-- +datadog.trace.agent_test_session_token=top_level_marked_on_v1_wire +--FILE-- +clearDumpedData(); + +// The sidecar sends v0.4 until its /info fetch advertises /v1.0/traces: resend until a v1 request carries the trace. +$found = null; +for ($i = 0; $i < 100 && $found === null; $i++) { + $root = \DDTrace\start_span(); + $root->name = "root"; + $root->service = "svc"; + $same = \DDTrace\start_span(); + $same->name = "child_same_service"; + $same->service = "svc"; + \DDTrace\close_span(); + $diff = \DDTrace\start_span(); + $diff->name = "child_other_service"; + $diff->service = "other"; + \DDTrace\close_span(); + \DDTrace\close_span(); + dd_trace_internal_fn("synchronous_flush"); + usleep(100000); + foreach (($rr->replayAllRequests() ?: []) as $r) { + if (strpos($r["uri"], "/v1.0/traces") === false) continue; + foreach ((json_decode($r["body"], true)["chunks"] ?? []) as $chunk) { + $names = array_column($chunk["spans"] ?? [], "name"); + if (in_array("child_other_service", $names, true)) { + $found = $chunk["spans"]; + } + } + } +} +$marks = []; +foreach ($found ?: [] as $span) { + $marks[$span["name"]] = isset($span["metrics"]["_dd.top_level"]) ? "1" : "not set"; +} +ksort($marks); +foreach ($marks as $name => $mark) { + echo "$name: _dd.top_level=$mark\n"; +} +?> +--EXPECT-- +child_other_service: _dd.top_level=1 +child_same_service: _dd.top_level=not set +root: _dd.top_level=1 diff --git a/tests/ext/request-replayer/traced_attribute_tags_v04_wire.phpt b/tests/ext/request-replayer/traced_attribute_tags_v04_wire.phpt new file mode 100644 index 0000000000..b3f0264486 --- /dev/null +++ b/tests/ext/request-replayer/traced_attribute_tags_v04_wire.phpt @@ -0,0 +1,72 @@ +--TEST-- +#[DDTrace\Trace] tags keep their meta strings on the v0.4 wire (array leaves included) +--SKIPIF-- + [ + 'method' => 'PUT', + 'header' => ["Content-Type: application/json", "X-Datadog-Test-Session-Token: traced_attribute_tags_v04"], + 'content' => json_encode(["endpoints" => ["/v0.4/traces", "/v0.6/stats", "/v0.7/config"], "client_drop_p0s" => false, "version" => "7.66.0"]), +]]); +if (@file_get_contents("http://request-replayer/set-agent-info", false, $ctx) === false) { + die("skip: request-replayer not reachable"); +} +?> +--ENV-- +DD_TRACE_LOG_LEVEL=info,startup=off +DD_AGENT_HOST=request-replayer +DD_TRACE_AGENT_PORT=80 +DD_TRACE_AGENT_FLUSH_INTERVAL=333 +DD_TRACE_GENERATE_ROOT_SPAN=0 +DD_INSTRUMENTATION_TELEMETRY_ENABLED=0 +DD_TRACE_SIDECAR_TRACE_SENDER=0 +--INI-- +datadog.trace.agent_test_session_token=traced_attribute_tags_v04 +--FILE-- +clearDumpedData(); + +dd_trace_internal_fn('await_agent_info'); + +#[DDTrace\Trace(name: "traced", tags: ["i" => 7, "arr" => [1, true, 2.5, null], "map" => ["k" => 3, "e" => []]])] +function traced() {} + +$s = \DDTrace\start_span(); +$s->name = "root"; +traced(); +\DDTrace\close_span(); +dd_trace_internal_fn("synchronous_flush"); + +$req = $rr->waitForRequest(function ($r) { return strpos($r["uri"], "traces") !== false; }); +foreach (json_decode($req["body"], true)[0] as $span) { + if ($span["name"] !== "traced") { + continue; + } + foreach (['meta', 'metrics'] as $bucket) { + $tags = isset($span[$bucket]) ? $span[$bucket] : []; + ksort($tags); + foreach ($tags as $key => $value) { + if (preg_match('/^(i|arr|map)\b/', $key)) { + echo "$bucket.$key=", var_export($value, true), "\n"; + } + } + } +} +?> +--EXPECTF-- +[ddtrace] [info] [%d] Flushing %d v0.4 trace(s) to send-queue for http://request-replayer:80 +meta.arr.0='1' +meta.arr.1='true' +meta.arr.2='2.5' +meta.arr.3='null' +meta.i='7' +meta.map.e='' +meta.map.k='3' +[ddtrace] [info] [%d] No finished traces to be sent to the agent diff --git a/tests/ext/root_span_default_component.phpt b/tests/ext/root_span_default_component.phpt new file mode 100644 index 0000000000..1efb1ce954 --- /dev/null +++ b/tests/ext/root_span_default_component.phpt @@ -0,0 +1,17 @@ +--TEST-- +Web entrypoint root spans default component to the SAPI name +--ENV-- +DD_TRACE_AUTO_FLUSH_ENABLED=0 +DD_TRACE_GENERATE_ROOT_SPAN=0 +--GET-- +foo=bar +--FILE-- + +--EXPECT-- +string(8) "cgi-fcgi" +string(8) "cgi-fcgi" diff --git a/tests/ext/root_span_default_component_cli.phpt b/tests/ext/root_span_default_component_cli.phpt new file mode 100644 index 0000000000..3fa007b021 --- /dev/null +++ b/tests/ext/root_span_default_component_cli.phpt @@ -0,0 +1,15 @@ +--TEST-- +CLI root spans get no default component +--ENV-- +DD_TRACE_AUTO_FLUSH_ENABLED=0 +DD_TRACE_GENERATE_ROOT_SPAN=0 +--FILE-- + +--EXPECT-- +bool(false) +bool(false) diff --git a/tests/ext/root_span_default_component_framework_wins.phpt b/tests/ext/root_span_default_component_framework_wins.phpt new file mode 100644 index 0000000000..c1e92530f0 --- /dev/null +++ b/tests/ext/root_span_default_component_framework_wins.phpt @@ -0,0 +1,17 @@ +--TEST-- +A component set by an integration overrides the web root span default +--ENV-- +DD_TRACE_AUTO_FLUSH_ENABLED=0 +DD_TRACE_GENERATE_ROOT_SPAN=0 +--GET-- +foo=bar +--FILE-- +meta["component"] = "laravel"; +DDTrace\close_span(); +$spans = dd_trace_serialize_closed_spans(); +var_dump($spans[0]["component"]); +?> +--EXPECT-- +string(7) "laravel" diff --git a/tests/ext/root_span_http_client_ip.phpt b/tests/ext/root_span_http_client_ip.phpt index 8789981f69..e9bd1cd3ac 100644 --- a/tests/ext/root_span_http_client_ip.phpt +++ b/tests/ext/root_span_http_client_ip.phpt @@ -10,7 +10,7 @@ DD_TRACE_CLIENT_IP_ENABLED=true DDTrace\start_span(); DDTrace\close_span(0); $span = dd_trace_serialize_closed_spans(); -var_dump($span[0]["meta"]["http.client_ip"]); +var_dump($span[0]["attributes"]["http.client_ip"]); ?> --EXPECTF-- string(9) "127.0.0.1" diff --git a/tests/ext/root_span_http_client_ip_custom_header.phpt b/tests/ext/root_span_http_client_ip_custom_header.phpt index 3182c9aa6f..1c3aee84f2 100644 --- a/tests/ext/root_span_http_client_ip_custom_header.phpt +++ b/tests/ext/root_span_http_client_ip_custom_header.phpt @@ -11,7 +11,7 @@ DD_TRACE_CLIENT_IP_ENABLED=true DDTrace\start_span(); DDTrace\close_span(0); $span = dd_trace_serialize_closed_spans(); -var_dump($span[0]["meta"]["http.client_ip"]); +var_dump($span[0]["attributes"]["http.client_ip"]); ?> --EXPECTF-- string(7) "7.7.7.7" diff --git a/tests/ext/root_span_http_client_ip_duplicate_ip_headers.phpt b/tests/ext/root_span_http_client_ip_duplicate_ip_headers.phpt index 2615500960..c2ba58361d 100644 --- a/tests/ext/root_span_http_client_ip_duplicate_ip_headers.phpt +++ b/tests/ext/root_span_http_client_ip_duplicate_ip_headers.phpt @@ -17,13 +17,13 @@ DD_TRACE_CLIENT_IP_ENABLED=true DDTrace\start_span(); DDTrace\close_span(0); $span = dd_trace_serialize_closed_spans(); -var_dump(isset($span[0]["meta"]['http.request.headers.x-forwarded-for'])); -var_dump(isset($span[0]["meta"]['http.request.headers.x-real-ip'])); -var_dump(isset($span[0]["meta"]['http.request.headers.x-forwarded'])); -var_dump(isset($span[0]["meta"]['http.request.headers.x-cluster-client-ip'])); -var_dump(isset($span[0]["meta"]['http.request.headers.forwarded-for'])); -var_dump(isset($span[0]["meta"]['http.request.headers.true-client-ip'])); -var_dump($span[0]["meta"]["http.client_ip"]); +var_dump(isset($span[0]["attributes"]['http.request.headers.x-forwarded-for'])); +var_dump(isset($span[0]["attributes"]['http.request.headers.x-real-ip'])); +var_dump(isset($span[0]["attributes"]['http.request.headers.x-forwarded'])); +var_dump(isset($span[0]["attributes"]['http.request.headers.x-cluster-client-ip'])); +var_dump(isset($span[0]["attributes"]['http.request.headers.forwarded-for'])); +var_dump(isset($span[0]["attributes"]['http.request.headers.true-client-ip'])); +var_dump($span[0]["attributes"]["http.client_ip"]); ?> --EXPECTF-- bool(false) diff --git a/tests/ext/root_span_http_client_ip_x_forwarded_for.phpt b/tests/ext/root_span_http_client_ip_x_forwarded_for.phpt index f368665db6..6bd647289c 100644 --- a/tests/ext/root_span_http_client_ip_x_forwarded_for.phpt +++ b/tests/ext/root_span_http_client_ip_x_forwarded_for.phpt @@ -10,7 +10,7 @@ DD_TRACE_CLIENT_IP_ENABLED=true DDTrace\start_span(); DDTrace\close_span(0); $span = dd_trace_serialize_closed_spans(); -var_dump($span[0]["meta"]["http.client_ip"]); +var_dump($span[0]["attributes"]["http.client_ip"]); ?> --EXPECTF-- string(7) "7.7.7.7" diff --git a/tests/ext/root_span_http_useragent.phpt b/tests/ext/root_span_http_useragent.phpt index 4c60e34cde..73fc5bcc1e 100644 --- a/tests/ext/root_span_http_useragent.phpt +++ b/tests/ext/root_span_http_useragent.phpt @@ -9,7 +9,7 @@ HTTP_USER_AGENT=dd_trace_user_agent DDTrace\start_span(); DDTrace\close_span(0); $span = dd_trace_serialize_closed_spans(); -var_dump($span[0]["meta"]["http.useragent"]); +var_dump($span[0]["attributes"]["http.useragent"]); ?> --EXPECTF-- string(19) "dd_trace_user_agent" diff --git a/tests/ext/root_span_security_testing_headers.phpt b/tests/ext/root_span_security_testing_headers.phpt index 2f8a9a9cc0..911e8834d7 100644 --- a/tests/ext/root_span_security_testing_headers.phpt +++ b/tests/ext/root_span_security_testing_headers.phpt @@ -11,8 +11,8 @@ HTTP_X_DATADOG_SECURITY_TEST=security-test-uuid DDTrace\start_span(); DDTrace\close_span(0); $spans = dd_trace_serialize_closed_spans(); -var_dump($spans[0]['meta']['http.request.headers.x-datadog-endpoint-scan']); -var_dump($spans[0]['meta']['http.request.headers.x-datadog-security-test']); +var_dump($spans[0]['attributes']['http.request.headers.x-datadog-endpoint-scan']); +var_dump($spans[0]['attributes']['http.request.headers.x-datadog-security-test']); ?> --EXPECT-- string(18) "endpoint-scan-uuid" diff --git a/tests/ext/root_span_security_testing_headers_absent.phpt b/tests/ext/root_span_security_testing_headers_absent.phpt index c80ae66215..160a09909b 100644 --- a/tests/ext/root_span_security_testing_headers_absent.phpt +++ b/tests/ext/root_span_security_testing_headers_absent.phpt @@ -8,8 +8,8 @@ DD_TRACE_GENERATE_ROOT_SPAN=0 DDTrace\start_span(); DDTrace\close_span(0); $spans = dd_trace_serialize_closed_spans(); -var_dump(array_key_exists('http.request.headers.x-datadog-endpoint-scan', $spans[0]['meta'])); -var_dump(array_key_exists('http.request.headers.x-datadog-security-test', $spans[0]['meta'])); +var_dump(array_key_exists('http.request.headers.x-datadog-endpoint-scan', $spans[0]['attributes'])); +var_dump(array_key_exists('http.request.headers.x-datadog-security-test', $spans[0]['attributes'])); ?> --EXPECT-- bool(false) diff --git a/tests/ext/root_span_url_as_resource_names.phpt b/tests/ext/root_span_url_as_resource_names.phpt index 6ea6f96027..4224d657df 100644 --- a/tests/ext/root_span_url_as_resource_names.phpt +++ b/tests/ext/root_span_url_as_resource_names.phpt @@ -17,26 +17,13 @@ foo=bar DDTrace\start_span(); DDTrace\close_span(); $spans = dd_trace_serialize_closed_spans(); -var_dump($spans[0]['meta']); +var_dump($spans[0]['span_kind']); +var_dump($spans[0]['attributes']['http.method']); +var_dump($spans[0]['attributes']['http.status_code']); +var_dump($spans[0]['attributes']['http.url']); ?> --EXPECTF-- -array(9) { - ["_dd.p.dm"]=> - string(2) "-0" - ["_dd.p.tid"]=> - string(16) "%s" - ["_dd.sdk.otlp_export"]=> - string(5) "false" - ["_dd.tags.process"]=> - string(%d) "%s" - ["http.method"]=> - string(3) "GET" - ["http.status_code"]=> - string(3) "200" - ["http.url"]=> - string(26) "https://localhost:9999/foo" - ["runtime-id"]=> - string(36) "%s" - ["span.kind"]=> - string(6) "server" -} +int(2) +string(3) "GET" +string(3) "200" +string(26) "https://localhost:9999/foo" diff --git a/tests/ext/root_span_url_as_resource_names_no_host.phpt b/tests/ext/root_span_url_as_resource_names_no_host.phpt index e7aaa05caf..780267e781 100644 --- a/tests/ext/root_span_url_as_resource_names_no_host.phpt +++ b/tests/ext/root_span_url_as_resource_names_no_host.phpt @@ -16,26 +16,13 @@ foo=bar DDTrace\start_span(); DDTrace\close_span(); $spans = dd_trace_serialize_closed_spans(); -var_dump($spans[0]['meta']); +var_dump($spans[0]['span_kind']); +var_dump($spans[0]['attributes']['http.method']); +var_dump($spans[0]['attributes']['http.status_code']); +var_dump($spans[0]['attributes']['http.url']); ?> --EXPECTF-- -array(9) { - ["_dd.p.dm"]=> - string(2) "-0" - ["_dd.p.tid"]=> - string(16) "%s" - ["_dd.sdk.otlp_export"]=> - string(5) "false" - ["_dd.tags.process"]=> - string(%d) "%s" - ["http.method"]=> - string(3) "GET" - ["http.status_code"]=> - string(3) "200" - ["http.url"]=> - string(25) "http://localhost:8888/foo" - ["runtime-id"]=> - string(36) "%s" - ["span.kind"]=> - string(6) "server" -} +int(2) +string(3) "GET" +string(3) "200" +string(25) "http://localhost:8888/foo" diff --git a/tests/ext/root_span_url_with_post_array.phpt b/tests/ext/root_span_url_with_post_array.phpt index 61b849504a..4f2d37532d 100644 --- a/tests/ext/root_span_url_with_post_array.phpt +++ b/tests/ext/root_span_url_with_post_array.phpt @@ -14,10 +14,10 @@ password=should_redact&foo[bar][baz]=qux&foo[baz][bar]=quz&foo[bar][password]=sh DDTrace\start_span(); DDTrace\close_span(); $spans = dd_trace_serialize_closed_spans(); -var_dump($spans[0]['meta']['http.request.post.password']); -var_dump($spans[0]['meta']['http.request.post.foo.bar.baz']); -var_dump($spans[0]['meta']['http.request.post.foo.baz.bar']); -var_dump($spans[0]['meta']['http.request.post.foo.bar.password']); +var_dump($spans[0]['attributes']['http.request.post.password']); +var_dump($spans[0]['attributes']['http.request.post.foo.bar.baz']); +var_dump($spans[0]['attributes']['http.request.post.foo.baz.bar']); +var_dump($spans[0]['attributes']['http.request.post.foo.bar.password']); ?> --EXPECT-- string(10) "" diff --git a/tests/ext/root_span_url_with_post_array_allowed.phpt b/tests/ext/root_span_url_with_post_array_allowed.phpt index b8d925b89a..10c6d72861 100644 --- a/tests/ext/root_span_url_with_post_array_allowed.phpt +++ b/tests/ext/root_span_url_with_post_array_allowed.phpt @@ -14,9 +14,9 @@ foo[baz]=bar&foo[bar][key]=baz&foo[bar][baz]=quz DDTrace\start_span(); DDTrace\close_span(); $spans = dd_trace_serialize_closed_spans(); -var_dump($spans[0]['meta']['http.request.post.foo.baz']); -var_dump($spans[0]['meta']['http.request.post.foo.bar.key']); -var_dump($spans[0]['meta']['http.request.post.foo.bar.baz']); +var_dump($spans[0]['attributes']['http.request.post.foo.baz']); +var_dump($spans[0]['attributes']['http.request.post.foo.bar.key']); +var_dump($spans[0]['attributes']['http.request.post.foo.bar.baz']); ?> --EXPECT-- string(3) "bar" diff --git a/tests/ext/root_span_url_with_post_fields.phpt b/tests/ext/root_span_url_with_post_fields.phpt index b38e1745b5..32653c2cd0 100644 --- a/tests/ext/root_span_url_with_post_fields.phpt +++ b/tests/ext/root_span_url_with_post_fields.phpt @@ -15,12 +15,12 @@ DDTrace\start_span(); DDTrace\close_span(); $spans = dd_trace_serialize_closed_spans(); var_dump($spans[0]['resource']); -var_dump($spans[0]['meta']['http.method']); -var_dump($spans[0]['meta']['http.request.post.foo']); -var_dump($spans[0]['meta']['http.request.post.password']); -var_dump($spans[0]['meta']['http.request.post.username']); -var_dump($spans[0]['meta']['http.request.post.token']); -var_dump($spans[0]['meta']['http.request.post.key']); +var_dump($spans[0]['attributes']['http.method']); +var_dump($spans[0]['attributes']['http.request.post.foo']); +var_dump($spans[0]['attributes']['http.request.post.password']); +var_dump($spans[0]['attributes']['http.request.post.username']); +var_dump($spans[0]['attributes']['http.request.post.token']); +var_dump($spans[0]['attributes']['http.request.post.key']); ?> --EXPECT-- string(4) "POST" diff --git a/tests/ext/root_span_url_with_post_implicit_array_key.phpt b/tests/ext/root_span_url_with_post_implicit_array_key.phpt index e73150fc9e..9feba6f17a 100644 --- a/tests/ext/root_span_url_with_post_implicit_array_key.phpt +++ b/tests/ext/root_span_url_with_post_implicit_array_key.phpt @@ -14,8 +14,8 @@ foo[]=a&foo[]=b DDTrace\start_span(); DDTrace\close_span(); $spans = dd_trace_serialize_closed_spans(); -var_dump($spans[0]['meta']['http.request.post.foo.0']); -var_dump($spans[0]['meta']['http.request.post.foo.1']); +var_dump($spans[0]['attributes']['http.request.post.foo.0']); +var_dump($spans[0]['attributes']['http.request.post.foo.1']); ?> --EXPECT-- string(1) "a" diff --git a/tests/ext/root_span_url_with_post_no_param.phpt b/tests/ext/root_span_url_with_post_no_param.phpt index ee48fa4a2a..b50f7f317c 100644 --- a/tests/ext/root_span_url_with_post_no_param.phpt +++ b/tests/ext/root_span_url_with_post_no_param.phpt @@ -15,18 +15,11 @@ METHOD=POST DDTrace\start_span(); DDTrace\close_span(); $spans = dd_trace_serialize_closed_spans(); -var_dump($spans[0]['meta']); +$postKeys = array_filter(array_keys($spans[0]['attributes']), function ($key) { + return strpos($key, 'http.request.post') === 0; +}); +var_dump($postKeys); ?> ---EXPECTF-- -array(5) { - ["_dd.p.dm"]=> - string(2) "-0" - ["_dd.p.tid"]=> - string(16) "%s" - ["_dd.sdk.otlp_export"]=> - string(5) "false" - ["_dd.tags.process"]=> - string(%d) "%s" - ["runtime-id"]=> - string(36) "%s" +--EXPECT-- +array(0) { } diff --git a/tests/ext/root_span_url_with_post_no_param_set.phpt b/tests/ext/root_span_url_with_post_no_param_set.phpt index 2472ca28fd..db1a56f9d0 100644 --- a/tests/ext/root_span_url_with_post_no_param_set.phpt +++ b/tests/ext/root_span_url_with_post_no_param_set.phpt @@ -14,18 +14,11 @@ METHOD=POST DDTrace\start_span(); DDTrace\close_span(); $spans = dd_trace_serialize_closed_spans(); -var_dump($spans[0]['meta']); +$postKeys = array_filter(array_keys($spans[0]['attributes']), function ($key) { + return strpos($key, 'http.request.post') === 0; +}); +var_dump($postKeys); ?> ---EXPECTF-- -array(5) { - ["_dd.p.dm"]=> - string(2) "-0" - ["_dd.p.tid"]=> - string(16) "%s" - ["_dd.sdk.otlp_export"]=> - string(5) "false" - ["_dd.tags.process"]=> - string(%d) "%s" - ["runtime-id"]=> - string(36) "%s" +--EXPECT-- +array(0) { } diff --git a/tests/ext/root_span_url_with_post_only_allowed_params.phpt b/tests/ext/root_span_url_with_post_only_allowed_params.phpt index 1fe141ced9..0e9383bf4f 100644 --- a/tests/ext/root_span_url_with_post_only_allowed_params.phpt +++ b/tests/ext/root_span_url_with_post_only_allowed_params.phpt @@ -14,10 +14,10 @@ username=should_redact&foo[bar]=should_not_redact&foo[baz]=should_redact&bar[foo DDTrace\start_span(); DDTrace\close_span(); $spans = dd_trace_serialize_closed_spans(); -var_dump($spans[0]['meta']['http.request.post.username']); -var_dump($spans[0]['meta']['http.request.post.foo.bar']); -var_dump($spans[0]['meta']['http.request.post.foo.baz']); -var_dump($spans[0]['meta']['http.request.post.bar.foo']); +var_dump($spans[0]['attributes']['http.request.post.username']); +var_dump($spans[0]['attributes']['http.request.post.foo.bar']); +var_dump($spans[0]['attributes']['http.request.post.foo.baz']); +var_dump($spans[0]['attributes']['http.request.post.bar.foo']); ?> --EXPECT-- string(10) "" diff --git a/tests/ext/root_span_url_with_post_simple_whitelist.phpt b/tests/ext/root_span_url_with_post_simple_whitelist.phpt index c294d2741e..a488f11d1e 100644 --- a/tests/ext/root_span_url_with_post_simple_whitelist.phpt +++ b/tests/ext/root_span_url_with_post_simple_whitelist.phpt @@ -14,9 +14,9 @@ foo=bar&password=should_not_redact&username=should_redact DDTrace\start_span(); DDTrace\close_span(); $spans = dd_trace_serialize_closed_spans(); -var_dump($spans[0]['meta']['http.request.post.foo']); -var_dump($spans[0]['meta']['http.request.post.password']); -var_dump($spans[0]['meta']['http.request.post.username']); +var_dump($spans[0]['attributes']['http.request.post.foo']); +var_dump($spans[0]['attributes']['http.request.post.password']); +var_dump($spans[0]['attributes']['http.request.post.username']); ?> --EXPECT-- string(3) "bar" diff --git a/tests/ext/root_span_url_with_query_params.phpt b/tests/ext/root_span_url_with_query_params.phpt index 33f86a772b..1331fd27b3 100644 --- a/tests/ext/root_span_url_with_query_params.phpt +++ b/tests/ext/root_span_url_with_query_params.phpt @@ -20,7 +20,7 @@ DDTrace\start_span(); DDTrace\close_span(); $spans = dd_trace_serialize_closed_spans(); var_dump($spans[0]['resource']); -var_dump($spans[0]['meta']["http.url"]); +var_dump($spans[0]['attributes']["http.url"]); ?> --EXPECT-- string(14) "GET /foo?param" diff --git a/tests/ext/root_span_url_with_query_params_obfuscation.phpt b/tests/ext/root_span_url_with_query_params_obfuscation.phpt index db6133a6db..7f66e030a9 100644 --- a/tests/ext/root_span_url_with_query_params_obfuscation.phpt +++ b/tests/ext/root_span_url_with_query_params_obfuscation.phpt @@ -16,7 +16,7 @@ key1=val1&token=a0b21ce2-006f-4cc6-95d5-d7b550698482&key2=val2&password=somethin DDTrace\start_span(); DDTrace\close_span(); $spans = dd_trace_serialize_closed_spans(); -var_dump($spans[0]['meta']["http.url"]); +var_dump($spans[0]['attributes']["http.url"]); ?> --EXPECT-- string(104) "https://localhost:9999/foo?key1=val1&&key2=val2&&key=%7B%20%7D&other=value" diff --git a/tests/ext/root_span_url_with_query_params_obfuscation_empty.phpt b/tests/ext/root_span_url_with_query_params_obfuscation_empty.phpt index fd83693e72..7075915fe8 100644 --- a/tests/ext/root_span_url_with_query_params_obfuscation_empty.phpt +++ b/tests/ext/root_span_url_with_query_params_obfuscation_empty.phpt @@ -17,7 +17,7 @@ application_key=123 DDTrace\start_span(); DDTrace\close_span(); $spans = dd_trace_serialize_closed_spans(); -var_dump($spans[0]['meta']["http.url"]); +var_dump($spans[0]['attributes']["http.url"]); ?> --EXPECT-- string(48) "https://localhost:9999/users?application_key=123" diff --git a/tests/ext/root_span_url_with_query_params_whitelist.phpt b/tests/ext/root_span_url_with_query_params_whitelist.phpt index 00d83c900c..edcc9425b0 100644 --- a/tests/ext/root_span_url_with_query_params_whitelist.phpt +++ b/tests/ext/root_span_url_with_query_params_whitelist.phpt @@ -16,7 +16,7 @@ password=value&some=query¶m&eters DDTrace\start_span(); DDTrace\close_span(); $spans = dd_trace_serialize_closed_spans(); -var_dump($spans[0]['meta']["http.url"]); +var_dump($spans[0]['attributes']["http.url"]); ?> --EXPECT-- string(41) "https://localhost:9999/foo?password=value" diff --git a/tests/ext/root_span_url_without_query_params.phpt b/tests/ext/root_span_url_without_query_params.phpt index 94ee21e594..087a9326c5 100644 --- a/tests/ext/root_span_url_without_query_params.phpt +++ b/tests/ext/root_span_url_without_query_params.phpt @@ -16,7 +16,7 @@ some=query¶m&eters DDTrace\start_span(); DDTrace\close_span(); $spans = dd_trace_serialize_closed_spans(); -var_dump($spans[0]['meta']["http.url"]); +var_dump($spans[0]['attributes']["http.url"]); ?> --EXPECT-- string(26) "https://localhost:9999/foo" diff --git a/tests/ext/sampling_mechanism_from_decision_maker.phpt b/tests/ext/sampling_mechanism_from_decision_maker.phpt new file mode 100644 index 0000000000..4dc9ad334f --- /dev/null +++ b/tests/ext/sampling_mechanism_from_decision_maker.phpt @@ -0,0 +1,29 @@ +--TEST-- +The V1 chunk sampling_mechanism takes the digits after the last '-' of _dd.p.dm, and is unset when unparseable +--ENV-- +DD_TRACE_GENERATE_ROOT_SPAN=0 +DD_TRACE_AUTO_FLUSH_ENABLED=0 +--FILE-- + '42', + 'x-datadog-parent-id' => '10', + 'x-datadog-sampling-priority' => '1', + 'x-datadog-tags' => "_dd.p.dm=$dm", + ]); + DDTrace\close_span(); + $span = dd_trace_serialize_closed_spans()[0]; + echo json_encode($dm), " => ", $span['sampling_mechanism'] ?? 'unset', "\n"; +} + +?> +--EXPECT-- +"-4" => 4 +"934086a686-4" => 4 +"-12" => 12 +"-abc" => unset +"4-" => unset +"-" => unset diff --git a/tests/ext/sandbox-prehook/dd_trace_method.phpt b/tests/ext/sandbox-prehook/dd_trace_method.phpt index e7ea5c4541..5668afcb1a 100644 --- a/tests/ext/sandbox-prehook/dd_trace_method.phpt +++ b/tests/ext/sandbox-prehook/dd_trace_method.phpt @@ -95,9 +95,11 @@ array(3) { --- array(3) { [0]=> - array(10) { + array(12) { ["trace_id"]=> string(%d) "%d" + ["trace_id_high"]=> + string(16) "%s" ["span_id"]=> string(%d) "%d" ["start"]=> @@ -112,36 +114,31 @@ array(3) { string(10) "FooService" ["type"]=> string(7) "FooType" - ["meta"]=> - array(5) { - ["_dd.p.dm"]=> - string(2) "-0" - ["_dd.p.tid"]=> - string(16) "%s" + ["sampling_priority"]=> + int(1) + ["sampling_mechanism"]=> + int(0) + ["attributes"]=> + array(10) { + ["runtime-id"]=> + string(36) "%s" + ["process_id"]=> + float(%f) ["_dd.svc_src"]=> string(1) "m" ["args.0"]=> string(18) "tracing is awesome" - ["runtime-id"]=> - string(36) "%s" - } - ["metrics"]=> - array(8) { - ["_dd.agent_psr"]=> - float(1) - ["_sampling_priority_v1"]=> - float(1) - ["bar"]=> - float(0) ["foo"]=> float(100) + ["bar"]=> + float(0) + ["_dd.agent_psr"]=> + float(1) ["php.compilation.total_time_ms"]=> float(%f) - ["php.memory.peak_real_usage_bytes"]=> - float(%f) ["php.memory.peak_usage_bytes"]=> float(%f) - ["process_id"]=> + ["php.memory.peak_real_usage_bytes"]=> float(%f) } } @@ -165,16 +162,18 @@ array(3) { string(10) "FooService" ["type"]=> string(7) "FooType" - ["meta"]=> + ["attributes"]=> array(1) { ["rand.range"]=> string(8) "42 - 999" } } [2]=> - array(10) { + array(12) { ["trace_id"]=> string(%d) "%d" + ["trace_id_high"]=> + string(16) "%s" ["span_id"]=> string(%d) "%d" ["start"]=> @@ -189,28 +188,23 @@ array(3) { string(19) "dd_trace_method.php" ["type"]=> string(3) "cli" - ["meta"]=> - array(3) { - ["_dd.p.dm"]=> - string(2) "-0" - ["_dd.p.tid"]=> - string(16) "%s" + ["sampling_priority"]=> + int(1) + ["sampling_mechanism"]=> + int(0) + ["attributes"]=> + array(6) { ["runtime-id"]=> string(36) "%s" - } - ["metrics"]=> - array(6) { + ["process_id"]=> + float(%f) ["_dd.agent_psr"]=> float(1) - ["_sampling_priority_v1"]=> - float(1) ["php.compilation.total_time_ms"]=> float(%f) - ["php.memory.peak_real_usage_bytes"]=> - float(%f) ["php.memory.peak_usage_bytes"]=> float(%f) - ["process_id"]=> + ["php.memory.peak_real_usage_bytes"]=> float(%f) } } diff --git a/tests/ext/sandbox-prehook/exception_error_log.phpt b/tests/ext/sandbox-prehook/exception_error_log.phpt index d7aded0ecc..9b7cb226fa 100644 --- a/tests/ext/sandbox-prehook/exception_error_log.phpt +++ b/tests/ext/sandbox-prehook/exception_error_log.phpt @@ -15,4 +15,4 @@ var_dump($sum); --EXPECTF-- [ddtrace] [warning] [%d] RuntimeException thrown in ddtrace's closure defined at %s:%d for array_sum(): This exception is expected in %s on line %d int(9) -[ddtrace] [info] [%d] Flushing trace of size 2 to send-queue for %s +[ddtrace] [info] [%d] Flushing v1 trace of size 2 to send-queue for %s diff --git a/tests/ext/sandbox-prehook/exception_handling.phpt b/tests/ext/sandbox-prehook/exception_handling.phpt index ac99ec932b..07750c9d57 100644 --- a/tests/ext/sandbox-prehook/exception_handling.phpt +++ b/tests/ext/sandbox-prehook/exception_handling.phpt @@ -24,15 +24,15 @@ try { $span = $stack[0]; echo "error: ", $span['error'], "\n"; - echo "Exception type: ", $span['meta']['error.type'], "\n"; - echo "Exception msg: ", $span['meta']['error.message'], "\n"; - echo "Exception stack:\n", $span['meta']['error.stack'], "\n"; + echo "Exception type: ", $span['attributes']['error.type'], "\n"; + echo "Exception msg: ", $span['attributes']['error.message'], "\n"; + echo "Exception stack:\n", $span['attributes']['error.stack'], "\n"; $span = $stack[1]; echo "error: ", $span['error'], "\n"; - echo "Exception type: ", $span['meta']['error.type'], "\n"; - echo "Exception msg: ", $span['meta']['error.message'], "\n"; - echo "Exception stack:\n", $span['meta']['error.stack'], "\n"; + echo "Exception type: ", $span['attributes']['error.type'], "\n"; + echo "Exception msg: ", $span['attributes']['error.message'], "\n"; + echo "Exception stack:\n", $span['attributes']['error.stack'], "\n"; } ?> diff --git a/tests/ext/sandbox-regression/class_resolver_bailout_hook.phpt b/tests/ext/sandbox-regression/class_resolver_bailout_hook.phpt index 35251dd899..b3c7149deb 100644 --- a/tests/ext/sandbox-regression/class_resolver_bailout_hook.phpt +++ b/tests/ext/sandbox-regression/class_resolver_bailout_hook.phpt @@ -29,4 +29,4 @@ class A extends B {} --EXPECTF-- [ddtrace] [warning] [%d] Error raised in ddtrace's closure defined at %s:%d for x(): No D in %s Leaving Autoloader -[ddtrace] [info] [%d] Flushing trace of size 2 to send-queue for %s +[ddtrace] [info] [%d] Flushing v1 trace of size 2 to send-queue for %s diff --git a/tests/ext/sandbox-regression/limiter_reset_flush_with_open_spans.phpt b/tests/ext/sandbox-regression/limiter_reset_flush_with_open_spans.phpt index ab6883b177..48ffd2fc75 100644 --- a/tests/ext/sandbox-regression/limiter_reset_flush_with_open_spans.phpt +++ b/tests/ext/sandbox-regression/limiter_reset_flush_with_open_spans.phpt @@ -68,7 +68,7 @@ baz() called bar() called string(28) "current :2513787319205155662" string(28) "closing :2513787319205155662" -[ddtrace] [info] [%d] Flushing trace of size 2 to send-queue for %s +[ddtrace] [info] [%d] Flushing v1 trace of size 2 to send-queue for %s string(34) "newly active :13874630024467741450" string(28) "initial :1735254072534978428" string(29) "started :10598951352238613536" @@ -78,7 +78,7 @@ baz() called bar() called string(29) "current :10598951352238613536" string(29) "closing :10598951352238613536" -[ddtrace] [info] [%d] Flushing trace of size 2 to send-queue for %s +[ddtrace] [info] [%d] Flushing v1 trace of size 2 to send-queue for %s string(33) "newly active :1735254072534978428" string(28) "initial :5052085463162682550" string(28) "started :7199227068870524257" @@ -88,8 +88,8 @@ baz() called bar() called string(28) "current :7199227068870524257" string(28) "closing :7199227068870524257" -[ddtrace] [info] [%d] Flushing trace of size 2 to send-queue for %s +[ddtrace] [info] [%d] Flushing v1 trace of size 2 to send-queue for %s string(33) "newly active :5052085463162682550" foo() called -[ddtrace] [info] [%d] Flushing trace of size 5 to send-queue for %s +[ddtrace] [info] [%d] Flushing v1 trace of size 5 to send-queue for %s [ddtrace] [info] [%d] No finished traces to be sent to the agent \ No newline at end of file diff --git a/tests/ext/sandbox-regression/nested_dropped_spans.phpt b/tests/ext/sandbox-regression/nested_dropped_spans.phpt index 8a52ce7516..bdf7cc982b 100644 --- a/tests/ext/sandbox-regression/nested_dropped_spans.phpt +++ b/tests/ext/sandbox-regression/nested_dropped_spans.phpt @@ -30,7 +30,5 @@ dd_dump_spans(); --EXPECTF-- spans(\DDTrace\SpanData) (1) { root span (nested_dropped_spans.php, root span, cli) - _dd.p.dm => -0 - _dd.p.tid => %s inner span (nested_dropped_spans.php, inner span, cli) } diff --git a/tests/ext/sandbox-regression/reset_configured_overrides.phpt b/tests/ext/sandbox-regression/reset_configured_overrides.phpt index 399b57d755..085bc7b65a 100644 --- a/tests/ext/sandbox-regression/reset_configured_overrides.phpt +++ b/tests/ext/sandbox-regression/reset_configured_overrides.phpt @@ -1,5 +1,5 @@ --TEST-- -[Sandbox regression] Traced functions and methods are untraced with reset +[Sandbox regression] Re-tracing a function/method adds an additional hook (hooks stack) --FILE-- m(); test(); -echo (dd_trace_reset() ? "TRUE": "FALSE") . PHP_EOL; - -// Cannot call a function while it is not traced and later expect it to trace -//$object->m(); -//test(); - DDTrace\trace_method("Test", "m", function(){ echo "METHOD HOOK2" . PHP_EOL; }); @@ -47,7 +41,6 @@ METHOD METHOD HOOK FUNCTION FUNCTION HOOK -TRUE METHOD METHOD HOOK2 METHOD HOOK diff --git a/tests/ext/sandbox/auto_flush.phpt b/tests/ext/sandbox/auto_flush.phpt index 146c5f22bb..3c95454513 100644 --- a/tests/ext/sandbox/auto_flush.phpt +++ b/tests/ext/sandbox/auto_flush.phpt @@ -32,14 +32,14 @@ echo PHP_EOL; --EXPECTF-- 3 6 -[ddtrace] [info] [%d] Flushing trace of size 3 to send-queue for %s +[ddtrace] [info] [%d] Flushing v1 trace of size 3 to send-queue for %s 10 15 -[ddtrace] [info] [%d] Flushing trace of size 3 to send-queue for %s +[ddtrace] [info] [%d] Flushing v1 trace of size 3 to send-queue for %s 21 28 -[ddtrace] [info] [%d] Flushing trace of size 3 to send-queue for %s +[ddtrace] [info] [%d] Flushing v1 trace of size 3 to send-queue for %s [ddtrace] [info] [%d] No finished traces to be sent to the agent \ No newline at end of file diff --git a/tests/ext/sandbox/auto_flush_attach_exception.phpt b/tests/ext/sandbox/auto_flush_attach_exception.phpt index 762675d7d3..cb8ca1e7d8 100644 --- a/tests/ext/sandbox/auto_flush_attach_exception.phpt +++ b/tests/ext/sandbox/auto_flush_attach_exception.phpt @@ -34,5 +34,5 @@ try { ?> --EXPECTF-- Caught exception: Oops! -[ddtrace] [info] [%d] Flushing trace of size 2 to send-queue for %s +[ddtrace] [info] [%d] Flushing v1 trace of size 2 to send-queue for %s [ddtrace] [info] [%d] No finished traces to be sent to the agent diff --git a/tests/ext/sandbox/auto_flush_disables_tracing.phpt b/tests/ext/sandbox/auto_flush_disables_tracing.phpt index 33a1771d80..ae0edd7b6c 100644 --- a/tests/ext/sandbox/auto_flush_disables_tracing.phpt +++ b/tests/ext/sandbox/auto_flush_disables_tracing.phpt @@ -37,14 +37,14 @@ echo PHP_EOL; --EXPECTF-- 3 6 -[ddtrace] [info] [%d] Flushing trace of size 3 to send-queue for %s +[ddtrace] [info] [%d] Flushing v1 trace of size 3 to send-queue for %s 10 15 -[ddtrace] [info] [%d] Flushing trace of size 3 to send-queue for %s +[ddtrace] [info] [%d] Flushing v1 trace of size 3 to send-queue for %s 21 28 -[ddtrace] [info] [%d] Flushing trace of size 3 to send-queue for %s +[ddtrace] [info] [%d] Flushing v1 trace of size 3 to send-queue for %s [ddtrace] [info] [%d] No finished traces to be sent to the agent \ No newline at end of file diff --git a/tests/ext/sandbox/auto_flush_sandbox_exception.phpt b/tests/ext/sandbox/auto_flush_sandbox_exception.phpt index d74f856237..3bd840abcc 100644 --- a/tests/ext/sandbox/auto_flush_sandbox_exception.phpt +++ b/tests/ext/sandbox/auto_flush_sandbox_exception.phpt @@ -32,6 +32,6 @@ try { } ?> --EXPECTF-- -[ddtrace] [info] [%d] Flushing trace of size 1 to send-queue for %s +[ddtrace] [info] [%d] Flushing v1 trace of size 1 to send-queue for %s Caught exception: Oops! [ddtrace] [info] [%d] No finished traces to be sent to the agent diff --git a/tests/ext/sandbox/auto_flush_userland_root_span.phpt b/tests/ext/sandbox/auto_flush_userland_root_span.phpt index 07812fc0cd..3a43828a1e 100644 --- a/tests/ext/sandbox/auto_flush_userland_root_span.phpt +++ b/tests/ext/sandbox/auto_flush_userland_root_span.phpt @@ -32,16 +32,16 @@ echo PHP_EOL; 3 6 Has not flushed yet. -[ddtrace] [info] [%d] Flushing trace of size 3 to send-queue for %s +[ddtrace] [info] [%d] Flushing v1 trace of size 3 to send-queue for %s 10 15 Has not flushed yet. -[ddtrace] [info] [%d] Flushing trace of size 3 to send-queue for %s +[ddtrace] [info] [%d] Flushing v1 trace of size 3 to send-queue for %s 21 28 Has not flushed yet. -[ddtrace] [info] [%d] Flushing trace of size 3 to send-queue for %s +[ddtrace] [info] [%d] Flushing v1 trace of size 3 to send-queue for %s [ddtrace] [info] [%d] No finished traces to be sent to the agent \ No newline at end of file diff --git a/tests/ext/sandbox/dd_dumper.inc b/tests/ext/sandbox/dd_dumper.inc index add87210a2..e9789bece2 100644 --- a/tests/ext/sandbox/dd_dumper.inc +++ b/tests/ext/sandbox/dd_dumper.inc @@ -31,18 +31,24 @@ function dd_dump_spans($skipMeta = false) if (!empty($values)) { echo ' (' . implode(', ', $values) . ')'; } - if (isset($span['meta']['error.message'])) { - echo ' (error: ' . $span['meta']['error.message'] . ')'; + if (isset($span['attributes']['error.message'])) { + echo ' (error: ' . $span['attributes']['error.message'] . ')'; } - if (isset($span['meta'])) { + if (isset($span['attributes'])) { if ($skipMeta) { - unset($span['meta']['_dd.p.dm']); + unset($span['attributes']['_dd.p.dm']); } echo PHP_EOL; - unset($span["meta"]["runtime-id"]); - unset($span["meta"]["_dd.tags.process"]); - unset($span["meta"]["_dd.sdk.otlp_export"]); - foreach ($span['meta'] as $k => $v) { + unset($span["attributes"]["runtime-id"]); + unset($span["attributes"]["_dd.tags.process"]); + unset($span["attributes"]["_dd.sdk.otlp_export"]); + // The v1 introspection shape merges the old meta (strings) and metrics + // (numbers) into a single attributes map. This dumper historically showed + // only string meta, so keep string-valued attributes to preserve its view. + foreach ($span['attributes'] as $k => $v) { + if (!is_string($v)) { + continue; + } echo str_repeat(' ', $indent) . ' ' . $k . ' => ' . $v . PHP_EOL; } } else { @@ -81,11 +87,11 @@ function dd_dump_spans($skipMeta = false) function dd_clean_spans() { $spans = dd_trace_serialize_closed_spans(); foreach ($spans as &$span) { - if (isset($span['meta'])) { - unset($span['meta']['_dd.tags.process']); - unset($span['meta']['_dd.sdk.otlp_export']); - if (empty($span['meta'])) { - unset($span['meta']); + if (isset($span['attributes'])) { + unset($span['attributes']['_dd.tags.process']); + unset($span['attributes']['_dd.sdk.otlp_export']); + if (empty($span['attributes'])) { + unset($span['attributes']); } } } diff --git a/tests/ext/sandbox/dd_trace_function_alias.phpt b/tests/ext/sandbox/dd_trace_function_alias.phpt index c1930fcd47..3e93ca1402 100644 --- a/tests/ext/sandbox/dd_trace_function_alias.phpt +++ b/tests/ext/sandbox/dd_trace_function_alias.phpt @@ -27,7 +27,5 @@ dd_dump_spans(); bar(hello) spans(\DDTrace\SpanData) (1) { bar (alias, bar, cli) - _dd.p.dm => -0 - _dd.p.tid => %s _dd.svc_src => m } diff --git a/tests/ext/sandbox/dd_trace_function_complex.phpt b/tests/ext/sandbox/dd_trace_function_complex.phpt index 2de41a7c64..d83c7229fc 100644 --- a/tests/ext/sandbox/dd_trace_function_complex.phpt +++ b/tests/ext/sandbox/dd_trace_function_complex.phpt @@ -96,9 +96,11 @@ array(3) { --- array(5) { [0]=> - array(10) { + array(12) { ["trace_id"]=> string(%d) "%d" + ["trace_id_high"]=> + string(16) "%s" ["span_id"]=> string(%d) "%d" ["start"]=> @@ -113,42 +115,37 @@ array(5) { string(10) "BarService" ["type"]=> string(7) "BarType" - ["meta"]=> - array(8) { - ["_dd.p.dm"]=> - string(2) "-0" - ["_dd.p.tid"]=> - string(16) "%s" + ["sampling_priority"]=> + int(1) + ["sampling_mechanism"]=> + int(0) + ["attributes"]=> + array(13) { + ["runtime-id"]=> + string(36) "%s" + ["process_id"]=> + float(%f) ["_dd.svc_src"]=> string(1) "m" ["args.0"]=> string(18) "tracing is awesome" + ["retval.thoughts"]=> + string(18) "tracing is awesome" ["retval.first"]=> string(5) "first" ["retval.rand"]=> string(%d) "%d" - ["retval.thoughts"]=> - string(18) "tracing is awesome" - ["runtime-id"]=> - string(36) "%s" - } - ["metrics"]=> - array(8) { - ["_dd.agent_psr"]=> - float(1) - ["_sampling_priority_v1"]=> - float(1) - ["bar"]=> - float(25) ["foo"]=> float(1.2) + ["bar"]=> + float(25) + ["_dd.agent_psr"]=> + float(1) ["php.compilation.total_time_ms"]=> float(%f) - ["php.memory.peak_real_usage_bytes"]=> - float(%f) ["php.memory.peak_usage_bytes"]=> float(%f) - ["process_id"]=> + ["php.memory.peak_real_usage_bytes"]=> float(%f) } } @@ -172,7 +169,7 @@ array(5) { string(29) "dd_trace_function_complex.php" ["type"]=> string(3) "cli" - ["meta"]=> + ["attributes"]=> array(1) { ["_dd.base_service"]=> string(10) "BarService" @@ -198,16 +195,18 @@ array(5) { string(29) "dd_trace_function_complex.php" ["type"]=> string(3) "cli" - ["meta"]=> + ["attributes"]=> array(1) { ["_dd.base_service"]=> string(10) "BarService" } } [3]=> - array(10) { + array(12) { ["trace_id"]=> string(%d) "%d" + ["trace_id_high"]=> + string(16) "%s" ["span_id"]=> string(%d) "%d" ["start"]=> @@ -222,35 +221,32 @@ array(5) { string(29) "dd_trace_function_complex.php" ["type"]=> string(3) "cli" - ["meta"]=> - array(3) { - ["_dd.p.dm"]=> - string(2) "-0" - ["_dd.p.tid"]=> - string(16) "%s" + ["sampling_priority"]=> + int(1) + ["sampling_mechanism"]=> + int(0) + ["attributes"]=> + array(6) { ["runtime-id"]=> string(36) "%s" - } - ["metrics"]=> - array(6) { + ["process_id"]=> + float(%f) ["_dd.agent_psr"]=> float(1) - ["_sampling_priority_v1"]=> - float(1) ["php.compilation.total_time_ms"]=> float(%f) - ["php.memory.peak_real_usage_bytes"]=> - float(%f) ["php.memory.peak_usage_bytes"]=> float(%f) - ["process_id"]=> + ["php.memory.peak_real_usage_bytes"]=> float(%f) } } [4]=> - array(10) { + array(12) { ["trace_id"]=> string(%d) "%d" + ["trace_id_high"]=> + string(16) "%s" ["span_id"]=> string(%d) "%d" ["start"]=> @@ -265,28 +261,23 @@ array(5) { string(29) "dd_trace_function_complex.php" ["type"]=> string(3) "cli" - ["meta"]=> - array(3) { - ["_dd.p.dm"]=> - string(2) "-0" - ["_dd.p.tid"]=> - string(16) "%s" + ["sampling_priority"]=> + int(1) + ["sampling_mechanism"]=> + int(0) + ["attributes"]=> + array(6) { ["runtime-id"]=> string(36) "%s" - } - ["metrics"]=> - array(6) { + ["process_id"]=> + float(%f) ["_dd.agent_psr"]=> float(1) - ["_sampling_priority_v1"]=> - float(1) ["php.compilation.total_time_ms"]=> float(%f) - ["php.memory.peak_real_usage_bytes"]=> - float(%f) ["php.memory.peak_usage_bytes"]=> float(%f) - ["process_id"]=> + ["php.memory.peak_real_usage_bytes"]=> float(%f) } } diff --git a/tests/ext/sandbox/dd_trace_function_internal.phpt b/tests/ext/sandbox/dd_trace_function_internal.phpt index f7af2063f7..cd207cca44 100644 --- a/tests/ext/sandbox/dd_trace_function_internal.phpt +++ b/tests/ext/sandbox/dd_trace_function_internal.phpt @@ -27,9 +27,11 @@ int(9) --- array(1) { [0]=> - array(10) { + array(12) { ["trace_id"]=> string(%d) "%d" + ["trace_id_high"]=> + string(16) "%s" ["span_id"]=> string(%d) "%d" ["start"]=> @@ -44,28 +46,23 @@ array(1) { string(30) "dd_trace_function_internal.php" ["type"]=> string(3) "cli" - ["meta"]=> - array(3) { - ["_dd.p.dm"]=> - string(2) "-0" - ["_dd.p.tid"]=> - string(16) "%s" + ["sampling_priority"]=> + int(1) + ["sampling_mechanism"]=> + int(0) + ["attributes"]=> + array(6) { ["runtime-id"]=> string(36) "%s" - } - ["metrics"]=> - array(6) { + ["process_id"]=> + float(%f) ["_dd.agent_psr"]=> float(1) - ["_sampling_priority_v1"]=> - float(1) ["php.compilation.total_time_ms"]=> float(%f) - ["php.memory.peak_real_usage_bytes"]=> - float(%f) ["php.memory.peak_usage_bytes"]=> float(%f) - ["process_id"]=> + ["php.memory.peak_real_usage_bytes"]=> float(%f) } } diff --git a/tests/ext/sandbox/dd_trace_function_userland.phpt b/tests/ext/sandbox/dd_trace_function_userland.phpt index 4995090b88..8cb397114c 100644 --- a/tests/ext/sandbox/dd_trace_function_userland.phpt +++ b/tests/ext/sandbox/dd_trace_function_userland.phpt @@ -39,9 +39,11 @@ array ( --- array(1) { [0]=> - array(9) { + array(10) { ["trace_id"]=> string(%d) "%d" + ["trace_id_high"]=> + string(16) "%s" ["span_id"]=> string(%d) "%d" ["parent_id"]=> diff --git a/tests/ext/sandbox/dd_trace_method.phpt b/tests/ext/sandbox/dd_trace_method.phpt index 16762177c0..388e2a789d 100644 --- a/tests/ext/sandbox/dd_trace_method.phpt +++ b/tests/ext/sandbox/dd_trace_method.phpt @@ -104,9 +104,11 @@ array(3) { --- array(3) { [0]=> - array(10) { + array(12) { ["trace_id"]=> string(%d) "%d" + ["trace_id_high"]=> + string(16) "%s" ["span_id"]=> string(%d) "%d" ["start"]=> @@ -121,42 +123,37 @@ array(3) { string(10) "FooService" ["type"]=> string(7) "FooType" - ["meta"]=> - array(8) { - ["_dd.p.dm"]=> - string(2) "-0" - ["_dd.p.tid"]=> - string(16) "%s" + ["sampling_priority"]=> + int(1) + ["sampling_mechanism"]=> + int(0) + ["attributes"]=> + array(13) { + ["runtime-id"]=> + string(36) "%s" + ["process_id"]=> + float(%f) ["_dd.svc_src"]=> string(1) "m" ["args.0"]=> string(18) "tracing is awesome" + ["retval.thoughts"]=> + string(18) "tracing is awesome" ["retval.first"]=> string(5) "first" ["retval.rand"]=> string(%d) "%d" - ["retval.thoughts"]=> - string(18) "tracing is awesome" - ["runtime-id"]=> - string(36) "%s" - } - ["metrics"]=> - array(8) { - ["_dd.agent_psr"]=> - float(1) - ["_sampling_priority_v1"]=> - float(1) - ["bar"]=> - float(0) ["foo"]=> float(100) + ["bar"]=> + float(0) + ["_dd.agent_psr"]=> + float(1) ["php.compilation.total_time_ms"]=> float(%f) - ["php.memory.peak_real_usage_bytes"]=> - float(%f) ["php.memory.peak_usage_bytes"]=> float(%f) - ["process_id"]=> + ["php.memory.peak_real_usage_bytes"]=> float(%f) } } @@ -180,20 +177,22 @@ array(3) { string(19) "dd_trace_method.php" ["type"]=> string(3) "cli" - ["meta"]=> + ["attributes"]=> array(3) { - ["_dd.base_service"]=> - string(10) "FooService" ["rand.range"]=> string(8) "42 - 999" ["rand.value"]=> string(%d) "%d" + ["_dd.base_service"]=> + string(10) "FooService" } } [2]=> - array(10) { + array(12) { ["trace_id"]=> string(%d) "%d" + ["trace_id_high"]=> + string(16) "%s" ["span_id"]=> string(%d) "%d" ["start"]=> @@ -208,28 +207,23 @@ array(3) { string(19) "dd_trace_method.php" ["type"]=> string(3) "cli" - ["meta"]=> - array(3) { - ["_dd.p.dm"]=> - string(2) "-0" - ["_dd.p.tid"]=> - string(16) "%s" + ["sampling_priority"]=> + int(1) + ["sampling_mechanism"]=> + int(0) + ["attributes"]=> + array(6) { ["runtime-id"]=> string(36) "%s" - } - ["metrics"]=> - array(6) { + ["process_id"]=> + float(%f) ["_dd.agent_psr"]=> float(1) - ["_sampling_priority_v1"]=> - float(1) ["php.compilation.total_time_ms"]=> float(%f) - ["php.memory.peak_real_usage_bytes"]=> - float(%f) ["php.memory.peak_usage_bytes"]=> float(%f) - ["process_id"]=> + ["php.memory.peak_real_usage_bytes"]=> float(%f) } } diff --git a/tests/ext/sandbox/dd_trace_method_alias.phpt b/tests/ext/sandbox/dd_trace_method_alias.phpt index 931b038444..66a074eed7 100644 --- a/tests/ext/sandbox/dd_trace_method_alias.phpt +++ b/tests/ext/sandbox/dd_trace_method_alias.phpt @@ -31,7 +31,5 @@ dd_dump_spans(); Foo::bar(hello) spans(\DDTrace\SpanData) (1) { Foo.bar (alias, Foo.bar, cli) - _dd.p.dm => -0 - _dd.p.tid => %s _dd.svc_src => m } diff --git a/tests/ext/sandbox/default_span_properties.phpt b/tests/ext/sandbox/default_span_properties.phpt index 47ff97370f..a2ff04faf6 100644 --- a/tests/ext/sandbox/default_span_properties.phpt +++ b/tests/ext/sandbox/default_span_properties.phpt @@ -35,15 +35,13 @@ dd_dump_spans(); 28 spans(\DDTrace\SpanData) (1) { main (default_span_properties.php, main, cli) + max => 6 + _dd.code_origin.type => entry _dd.code_origin.frames.0.file => %sdefault_span_properties.php _dd.code_origin.frames.0.line => 16 _dd.code_origin.frames.0.method => main _dd.code_origin.frames.1.file => %sdefault_span_properties.php _dd.code_origin.frames.1.line => 21 - _dd.code_origin.type => entry - _dd.p.dm => -0 - _dd.p.tid => %s - max => 6 MyRange (default_span_properties.php, MyRange, cli) array_sum (default_span_properties.php, array_sum, cli) retval => 21 diff --git a/tests/ext/sandbox/default_span_properties_method.phpt b/tests/ext/sandbox/default_span_properties_method.phpt index 0fd4226144..0a63f431dd 100644 --- a/tests/ext/sandbox/default_span_properties_method.phpt +++ b/tests/ext/sandbox/default_span_properties_method.phpt @@ -43,8 +43,6 @@ dd_dump_spans(); 06 spans(\DDTrace\SpanData) (1) { Foo.main (default_span_properties_method.php, Foo.main, cli) - _dd.p.dm => -0 - _dd.p.tid => %s year => 2020 DateTime.__construct (default_span_properties_method.php, DateTime.__construct, cli) date => 2020-06-15 diff --git a/tests/ext/sandbox/deferred_load_attempt_loading_once.phpt b/tests/ext/sandbox/deferred_load_attempt_loading_once.phpt index 1d2c442da5..0048f1e73b 100644 --- a/tests/ext/sandbox/deferred_load_attempt_loading_once.phpt +++ b/tests/ext/sandbox/deferred_load_attempt_loading_once.phpt @@ -37,4 +37,4 @@ namespace autoload_attempted PUBLIC STATIC METHOD PUBLIC STATIC METHOD -[ddtrace] [info] [%d] Flushing trace of size 1 to send-queue for %s +[ddtrace] [info] [%d] Flushing v1 trace of size 1 to send-queue for %s diff --git a/tests/ext/sandbox/die_in_sandbox.phpt b/tests/ext/sandbox/die_in_sandbox.phpt index dea8d53cc7..d91c341475 100644 --- a/tests/ext/sandbox/die_in_sandbox.phpt +++ b/tests/ext/sandbox/die_in_sandbox.phpt @@ -18,7 +18,7 @@ x(); ?> --EXPECTF-- [ddtrace] [warning] [%d] UnwindExit thrown in ddtrace's closure defined at %s:%d for x(): in Unknown on line 0 -[ddtrace] [span] [%d] Encoding span: Span { service: die_in_sandbox.php, name: die_in_sandbox.php, resource: die_in_sandbox.php, type: cli, trace_id: %d, span_id: %d, parent_id: %d, start: %d, duration: %d, error: %d, meta: %s, metrics: %s, meta_struct: %s, span_links: %s, span_events: %s } -[ddtrace] [span] [%d] Encoding span: Span { service: die_in_sandbox.php, name: x, resource: x, type: cli, trace_id: %d, span_id: %d, parent_id: %d, start: %d, duration: %d, error: %d, meta: %s, metrics: %s, meta_struct: %s, span_links: %s, span_events: %s } -[ddtrace] [info] [%d] Flushing trace of size 2 to send-queue for %s +[ddtrace] [span] [%d] Encoding span: trace_id=%s service="die_in_sandbox.php" name="die_in_sandbox.php" resource="die_in_sandbox.php" type="cli" span_id=%d parent_id=%d start=%d duration=%d error=%s kind=%s env="" version="" component="" attributes=%s links=%d events=%d +[ddtrace] [span] [%d] Encoding span: trace_id=%s service="die_in_sandbox.php" name="x" resource="x" type="cli" span_id=%d parent_id=%d start=%d duration=%d error=%s kind=%s env="" version="" component="" attributes=%s links=%d events=%d +[ddtrace] [info] [%d] Flushing v1 trace of size 2 to send-queue for %s diff --git a/tests/ext/sandbox/errors_are_flagged_from_userland.phpt b/tests/ext/sandbox/errors_are_flagged_from_userland.phpt index 9839c6dc57..6abce1e1aa 100644 --- a/tests/ext/sandbox/errors_are_flagged_from_userland.phpt +++ b/tests/ext/sandbox/errors_are_flagged_from_userland.phpt @@ -27,9 +27,11 @@ var_dump(dd_clean_spans()); testErrorFromUserland() array(1) { [0]=> - array(11) { + array(13) { ["trace_id"]=> string(%d) "%d" + ["trace_id_high"]=> + string(16) "%s" ["span_id"]=> string(%d) "%d" ["start"]=> @@ -46,30 +48,25 @@ array(1) { string(3) "cli" ["error"]=> int(1) - ["meta"]=> - array(4) { - ["_dd.p.dm"]=> - string(2) "-0" - ["_dd.p.tid"]=> - string(16) "%s" - ["error.message"]=> - string(9) "Foo error" + ["sampling_priority"]=> + int(1) + ["sampling_mechanism"]=> + int(0) + ["attributes"]=> + array(7) { ["runtime-id"]=> string(36) "%s" - } - ["metrics"]=> - array(6) { + ["process_id"]=> + float(%f) + ["error.message"]=> + string(9) "Foo error" ["_dd.agent_psr"]=> float(1) - ["_sampling_priority_v1"]=> - float(1) ["php.compilation.total_time_ms"]=> float(%f) - ["php.memory.peak_real_usage_bytes"]=> - float(%f) ["php.memory.peak_usage_bytes"]=> float(%f) - ["process_id"]=> + ["php.memory.peak_real_usage_bytes"]=> float(%f) } } diff --git a/tests/ext/sandbox/exception_error_log.phpt b/tests/ext/sandbox/exception_error_log.phpt index 6da3f0d707..c86e8a636c 100644 --- a/tests/ext/sandbox/exception_error_log.phpt +++ b/tests/ext/sandbox/exception_error_log.phpt @@ -15,4 +15,4 @@ var_dump($sum); --EXPECTF-- [ddtrace] [warning] [%d] RuntimeException thrown in ddtrace's closure defined at %s:%d for array_sum(): This exception is expected in %s on line %d int(9) -[ddtrace] [info] [%d] Flushing trace of size 2 to send-queue for %s +[ddtrace] [info] [%d] Flushing v1 trace of size 2 to send-queue for %s diff --git a/tests/ext/sandbox/exception_from_user_error_handler_internal.phpt b/tests/ext/sandbox/exception_from_user_error_handler_internal.phpt index 1984f816f1..e132c51460 100644 --- a/tests/ext/sandbox/exception_from_user_error_handler_internal.phpt +++ b/tests/ext/sandbox/exception_from_user_error_handler_internal.phpt @@ -22,9 +22,9 @@ try { $span = $spans[0]; echo 'error: ' . $span['error'] . PHP_EOL; - echo 'error.type: ' . $span['meta']['error.type'] . PHP_EOL; - echo 'error.message: ' . $span['meta']['error.message'] . PHP_EOL; - echo 'Has error.stack: ' . isset($span['meta']['error.stack']) . PHP_EOL; + echo 'error.type: ' . $span['attributes']['error.type'] . PHP_EOL; + echo 'error.message: ' . $span['attributes']['error.message'] . PHP_EOL; + echo 'Has error.stack: ' . isset($span['attributes']['error.stack']) . PHP_EOL; } ?> --EXPECTF-- diff --git a/tests/ext/sandbox/exception_handled_for_correct_catch_block.phpt b/tests/ext/sandbox/exception_handled_for_correct_catch_block.phpt index 87eb037f2e..41d88ebc61 100644 --- a/tests/ext/sandbox/exception_handled_for_correct_catch_block.phpt +++ b/tests/ext/sandbox/exception_handled_for_correct_catch_block.phpt @@ -63,7 +63,7 @@ echo embeddedCatch() . PHP_EOL; array_map(function($span) { echo $span['name']; echo isset($span['resource']) ? ', ' . $span['resource'] : ''; - echo isset($span['meta']['error.message']) ? ', ' . $span['meta']['error.message'] : ''; + echo isset($span['attributes']['error.message']) ? ', ' . $span['attributes']['error.message'] : ''; echo PHP_EOL; }, dd_trace_serialize_closed_spans()); ?> diff --git a/tests/ext/sandbox/exception_handled_in_correct_catch_frame.phpt b/tests/ext/sandbox/exception_handled_in_correct_catch_frame.phpt index 1b0e458bec..d1ff9421f3 100644 --- a/tests/ext/sandbox/exception_handled_in_correct_catch_frame.phpt +++ b/tests/ext/sandbox/exception_handled_in_correct_catch_frame.phpt @@ -67,8 +67,8 @@ array_map(function($span) { if (isset($span['resource'])) { echo '-' . $span['resource']; } - if (isset($span['meta']['error.message'])) { - echo ' (' . $span['meta']['error.message'] . ')'; + if (isset($span['attributes']['error.message'])) { + echo ' (' . $span['attributes']['error.message'] . ')'; } echo PHP_EOL; }, dd_trace_serialize_closed_spans()); diff --git a/tests/ext/sandbox/exception_handled_in_multicatch.phpt b/tests/ext/sandbox/exception_handled_in_multicatch.phpt index 4bafe494a9..30c1e5b09b 100644 --- a/tests/ext/sandbox/exception_handled_in_multicatch.phpt +++ b/tests/ext/sandbox/exception_handled_in_multicatch.phpt @@ -38,7 +38,7 @@ echo multiCatch() . PHP_EOL; array_map(function($span) { echo $span['name']; echo isset($span['resource']) ? ', ' . $span['resource'] : ''; - echo isset($span['meta']['error.message']) ? ', ' . $span['meta']['error.message'] : ''; + echo isset($span['attributes']['error.message']) ? ', ' . $span['attributes']['error.message'] : ''; echo PHP_EOL; }, dd_trace_serialize_closed_spans()); ?> diff --git a/tests/ext/sandbox/exception_handled_with_finally.phpt b/tests/ext/sandbox/exception_handled_with_finally.phpt index d1cd2259f0..ba7f5ee028 100644 --- a/tests/ext/sandbox/exception_handled_with_finally.phpt +++ b/tests/ext/sandbox/exception_handled_with_finally.phpt @@ -37,7 +37,7 @@ echo doCatchWithFinally() . PHP_EOL; array_map(function($span) { echo $span['name']; echo isset($span['resource']) ? ', ' . $span['resource'] : ''; - echo isset($span['meta']['error.message']) ? ', ' . $span['meta']['error.message'] : ''; + echo isset($span['attributes']['error.message']) ? ', ' . $span['attributes']['error.message'] : ''; echo PHP_EOL; }, dd_trace_serialize_closed_spans()); ?> diff --git a/tests/ext/sandbox/exception_handling.phpt b/tests/ext/sandbox/exception_handling.phpt index 32b43000e1..1be3557dc2 100644 --- a/tests/ext/sandbox/exception_handling.phpt +++ b/tests/ext/sandbox/exception_handling.phpt @@ -30,15 +30,15 @@ try { $span = $stack[0]; echo "error: ", $span['error'], "\n"; - echo "Exception type: ", $span['meta']['error.type'], "\n"; - echo "Exception msg: ", $span['meta']['error.message'], "\n"; - echo "Exception stack:\n", $span['meta']['error.stack'], "\n"; + echo "Exception type: ", $span['attributes']['error.type'], "\n"; + echo "Exception msg: ", $span['attributes']['error.message'], "\n"; + echo "Exception stack:\n", $span['attributes']['error.stack'], "\n"; $span = $stack[1]; echo "error: ", $span['error'], "\n"; - echo "Exception type: ", $span['meta']['error.type'], "\n"; - echo "Exception msg: ", $span['meta']['error.message'], "\n"; - echo "Exception stack:\n", $span['meta']['error.stack'], "\n"; + echo "Exception type: ", $span['attributes']['error.type'], "\n"; + echo "Exception msg: ", $span['attributes']['error.message'], "\n"; + echo "Exception stack:\n", $span['attributes']['error.stack'], "\n"; } ?> diff --git a/tests/ext/sandbox/exceptions_are_passed_to_the_tracing_closure.phpt b/tests/ext/sandbox/exceptions_are_passed_to_the_tracing_closure.phpt index 71c6c5d8ee..c828092614 100644 --- a/tests/ext/sandbox/exceptions_are_passed_to_the_tracing_closure.phpt +++ b/tests/ext/sandbox/exceptions_are_passed_to_the_tracing_closure.phpt @@ -34,8 +34,8 @@ try { array_map(function($span) { echo $span['name']; - if (isset($span['meta']['error.message'])) { - echo ' with exception: ' . $span['meta']['error.message']; + if (isset($span['attributes']['error.message'])) { + echo ' with exception: ' . $span['attributes']['error.message']; } echo PHP_EOL; }, dd_trace_serialize_closed_spans()); diff --git a/tests/ext/sandbox/exceptions_in_original_call_rethrown_in_tracing_closure.phpt b/tests/ext/sandbox/exceptions_in_original_call_rethrown_in_tracing_closure.phpt index facb68382c..885df67cca 100644 --- a/tests/ext/sandbox/exceptions_in_original_call_rethrown_in_tracing_closure.phpt +++ b/tests/ext/sandbox/exceptions_in_original_call_rethrown_in_tracing_closure.phpt @@ -23,7 +23,7 @@ array_map(function($span) { printf( "%s with exception: %s\n", $span['name'], - $span['meta']['error.message'] + $span['attributes']['error.message'] ); }, dd_trace_serialize_closed_spans()); ?> diff --git a/tests/ext/sandbox/fatal_errors_are_tracked_001.phpt b/tests/ext/sandbox/fatal_errors_are_tracked_001.phpt index 069bf90c60..2555674c1e 100644 --- a/tests/ext/sandbox/fatal_errors_are_tracked_001.phpt +++ b/tests/ext/sandbox/fatal_errors_are_tracked_001.phpt @@ -11,9 +11,9 @@ register_shutdown_function(function () { foreach (dd_trace_serialize_closed_spans() as $span) { echo $span['name'] . PHP_EOL; if (isset($span['error']) && $span['error'] === 1) { - echo $span['meta']['error.type'] . PHP_EOL; - echo $span['meta']['error.message'] . PHP_EOL; - echo $span['meta']['error.stack'] . PHP_EOL; + echo $span['attributes']['error.type'] . PHP_EOL; + echo $span['attributes']['error.message'] . PHP_EOL; + echo $span['attributes']['error.stack'] . PHP_EOL; } } }); diff --git a/tests/ext/sandbox/fatal_errors_are_tracked_002.phpt b/tests/ext/sandbox/fatal_errors_are_tracked_002.phpt index f60eeabc17..d8944d0042 100644 --- a/tests/ext/sandbox/fatal_errors_are_tracked_002.phpt +++ b/tests/ext/sandbox/fatal_errors_are_tracked_002.phpt @@ -14,9 +14,9 @@ register_shutdown_function(function () { foreach (dd_trace_serialize_closed_spans() as $span) { echo $span['name'] . PHP_EOL; if (isset($span['error']) && $span['error'] === 1) { - echo $span['meta']['error.type'] . PHP_EOL; - echo $span['meta']['error.message'] . PHP_EOL; - echo $span['meta']['error.stack'] . PHP_EOL; + echo $span['attributes']['error.type'] . PHP_EOL; + echo $span['attributes']['error.message'] . PHP_EOL; + echo $span['attributes']['error.stack'] . PHP_EOL; } } }); diff --git a/tests/ext/sandbox/fatal_errors_are_tracked_003.phpt b/tests/ext/sandbox/fatal_errors_are_tracked_003.phpt index 7561b0f153..b1b3d85020 100644 --- a/tests/ext/sandbox/fatal_errors_are_tracked_003.phpt +++ b/tests/ext/sandbox/fatal_errors_are_tracked_003.phpt @@ -14,9 +14,9 @@ register_shutdown_function(function () { foreach (dd_trace_serialize_closed_spans() as $span) { echo $span['name'] . PHP_EOL; if (isset($span['error']) && $span['error'] === 1) { - echo $span['meta']['error.type'] . PHP_EOL; - echo $span['meta']['error.message'] . PHP_EOL; - echo $span['meta']['error.stack'] . PHP_EOL; + echo $span['attributes']['error.type'] . PHP_EOL; + echo $span['attributes']['error.message'] . PHP_EOL; + echo $span['attributes']['error.stack'] . PHP_EOL; } } }); diff --git a/tests/ext/sandbox/fatal_errors_are_tracked_004.phpt b/tests/ext/sandbox/fatal_errors_are_tracked_004.phpt index 7d3e2f56cd..2acb184131 100644 --- a/tests/ext/sandbox/fatal_errors_are_tracked_004.phpt +++ b/tests/ext/sandbox/fatal_errors_are_tracked_004.phpt @@ -11,9 +11,9 @@ register_shutdown_function(function () { foreach (dd_trace_serialize_closed_spans() as $span) { echo $span['name'] . PHP_EOL; if (isset($span['error']) && $span['error'] === 1) { - echo $span['meta']['error.type'] . PHP_EOL; - echo $span['meta']['error.message'] . PHP_EOL; - echo $span['meta']['error.stack'] . PHP_EOL; + echo $span['attributes']['error.type'] . PHP_EOL; + echo $span['attributes']['error.message'] . PHP_EOL; + echo $span['attributes']['error.stack'] . PHP_EOL; } } }); diff --git a/tests/ext/sandbox/fatal_errors_are_tracked_005.phpt b/tests/ext/sandbox/fatal_errors_are_tracked_005.phpt index 886b2d8f4f..db6036d680 100644 --- a/tests/ext/sandbox/fatal_errors_are_tracked_005.phpt +++ b/tests/ext/sandbox/fatal_errors_are_tracked_005.phpt @@ -11,9 +11,9 @@ register_shutdown_function(function () { foreach (dd_trace_serialize_closed_spans() as $span) { echo $span['name'] . PHP_EOL; if (isset($span['error']) && $span['error'] === 1) { - echo $span['meta']['error.type'] . PHP_EOL; - echo $span['meta']['error.message'] . PHP_EOL; - echo $span['meta']['error.stack'] . PHP_EOL; + echo $span['attributes']['error.type'] . PHP_EOL; + echo $span['attributes']['error.message'] . PHP_EOL; + echo $span['attributes']['error.stack'] . PHP_EOL; } } }); diff --git a/tests/ext/sandbox/generator_with_exception.phpt b/tests/ext/sandbox/generator_with_exception.phpt index 2ecb9930d2..5a42c8b606 100644 --- a/tests/ext/sandbox/generator_with_exception.phpt +++ b/tests/ext/sandbox/generator_with_exception.phpt @@ -42,7 +42,7 @@ echo doSomething() . PHP_EOL; array_map(function($span) { echo $span['name']; echo isset($span['resource']) ? ', ' . $span['resource'] : ''; - echo isset($span['meta']['error.message']) ? ', ' . $span['meta']['error.message'] : ''; + echo isset($span['attributes']['error.message']) ? ', ' . $span['attributes']['error.message'] : ''; echo PHP_EOL; }, dd_trace_serialize_closed_spans()); ?> diff --git a/tests/ext/sandbox/hook_function/03.phpt b/tests/ext/sandbox/hook_function/03.phpt index bc2bc06991..14886e2aeb 100644 --- a/tests/ext/sandbox/hook_function/03.phpt +++ b/tests/ext/sandbox/hook_function/03.phpt @@ -20,4 +20,4 @@ greet('Datadog'); [ddtrace] [warning] [%d] DDTrace\hook_function was given neither prehook nor posthook in %s on line %d; This message is only displayed once. Specify DD_TRACE_ONCE_LOGS=0 to show all messages. bool(false) Hello, Datadog. -[ddtrace] [info] [%d] Flushing trace of size 1 to send-queue for %s +[ddtrace] [info] [%d] Flushing v1 trace of size 1 to send-queue for %s diff --git a/tests/ext/sandbox/hook_function/hook_does_not_leak_error.phpt b/tests/ext/sandbox/hook_function/hook_does_not_leak_error.phpt index cd26d5d523..519039c3cb 100644 --- a/tests/ext/sandbox/hook_function/hook_does_not_leak_error.phpt +++ b/tests/ext/sandbox/hook_function/hook_does_not_leak_error.phpt @@ -33,4 +33,4 @@ foo int(200) foo [ddtrace] [warning] [%d] Error raised in ddtrace's closure defined at %s:%d for foo(): Fatal in %s on line %d -[ddtrace] [info] [%d] Flushing trace of size %s +[ddtrace] [info] [%d] Flushing v1 trace of size %s diff --git a/tests/ext/sandbox/hook_function/posthook_error_02.phpt b/tests/ext/sandbox/hook_function/posthook_error_02.phpt index ebc2ecd55a..84b2afd37d 100644 --- a/tests/ext/sandbox/hook_function/posthook_error_02.phpt +++ b/tests/ext/sandbox/hook_function/posthook_error_02.phpt @@ -28,4 +28,4 @@ greet('Datadog'); Hello, Datadog. greet hooked. [ddtrace] [warning] [%d] %s in ddtrace's closure defined at %s:%d for greet(): Undefined variable%sthis_normally_raises_an_%s -[ddtrace] [info] [%d] Flushing trace of size 1 to send-queue for %s +[ddtrace] [info] [%d] Flushing v1 trace of size 1 to send-queue for %s diff --git a/tests/ext/sandbox/hook_function/posthook_exceptions_04.phpt b/tests/ext/sandbox/hook_function/posthook_exceptions_04.phpt index 1b345fcfde..399b3e5910 100644 --- a/tests/ext/sandbox/hook_function/posthook_exceptions_04.phpt +++ b/tests/ext/sandbox/hook_function/posthook_exceptions_04.phpt @@ -32,4 +32,4 @@ try { array_sum hooked. [ddtrace] [warning] [%d] Exception thrown in ddtrace's closure defined at %s:%d for array_sum(): ! in %s on line %d Sum = 4. -[ddtrace] [info] [%d] Flushing trace of size 1 to send-queue for %s +[ddtrace] [info] [%d] Flushing v1 trace of size 1 to send-queue for %s diff --git a/tests/ext/sandbox/hook_function/prehook_error_02.phpt b/tests/ext/sandbox/hook_function/prehook_error_02.phpt index 5b07a34fea..2b4533a6bf 100644 --- a/tests/ext/sandbox/hook_function/prehook_error_02.phpt +++ b/tests/ext/sandbox/hook_function/prehook_error_02.phpt @@ -27,4 +27,4 @@ greet('Datadog'); greet hooked. [ddtrace] [warning] [%d] %s in ddtrace's closure defined at %s:%d for greet(): Undefined variable%sthis_normally_raises_an_%s Hello, Datadog. -[ddtrace] [info] [%d] Flushing trace of size 1 to send-queue for %s +[ddtrace] [info] [%d] Flushing v1 trace of size 1 to send-queue for %s diff --git a/tests/ext/sandbox/hook_function/prehook_exceptions_02.phpt b/tests/ext/sandbox/hook_function/prehook_exceptions_02.phpt index c4eca6d758..028ed20498 100644 --- a/tests/ext/sandbox/hook_function/prehook_exceptions_02.phpt +++ b/tests/ext/sandbox/hook_function/prehook_exceptions_02.phpt @@ -35,4 +35,4 @@ greet hooked. [ddtrace] [warning] [%d] Exception thrown in ddtrace's closure defined at %s:%d for greet(): ! in %s on line %d Hello, Datadog. Done. -[ddtrace] [info] [%d] Flushing trace of size 1 to send-queue for %s +[ddtrace] [info] [%d] Flushing v1 trace of size 1 to send-queue for %s diff --git a/tests/ext/sandbox/hook_function/prehook_exceptions_04.phpt b/tests/ext/sandbox/hook_function/prehook_exceptions_04.phpt index b643afd666..18096f11ff 100644 --- a/tests/ext/sandbox/hook_function/prehook_exceptions_04.phpt +++ b/tests/ext/sandbox/hook_function/prehook_exceptions_04.phpt @@ -30,4 +30,4 @@ try { array_sum hooked. [ddtrace] [warning] [%d] Exception thrown in ddtrace's closure defined at %s:%d for array_sum(): ! in %s on line %d Sum = 4. -[ddtrace] [info] [%d] Flushing trace of size 1 to send-queue for %s +[ddtrace] [info] [%d] Flushing v1 trace of size 1 to send-queue for %s diff --git a/tests/ext/sandbox/hook_method/03.phpt b/tests/ext/sandbox/hook_method/03.phpt index 2f47e493ca..8265769997 100644 --- a/tests/ext/sandbox/hook_method/03.phpt +++ b/tests/ext/sandbox/hook_method/03.phpt @@ -23,4 +23,4 @@ Greeter::greet('Datadog'); [ddtrace] [warning] [%d] DDTrace\hook_method was given neither prehook nor posthook in %s on line %d; This message is only displayed once. Specify DD_TRACE_ONCE_LOGS=0 to show all messages. bool(false) Hello, Datadog. -[ddtrace] [info] [%d] Flushing trace of size 1 to send-queue for %s +[ddtrace] [info] [%d] Flushing v1 trace of size 1 to send-queue for %s diff --git a/tests/ext/sandbox/hook_method/posthook_07.phpt b/tests/ext/sandbox/hook_method/posthook_07.phpt index aa1f72f0bb..ca4e45c227 100644 --- a/tests/ext/sandbox/hook_method/posthook_07.phpt +++ b/tests/ext/sandbox/hook_method/posthook_07.phpt @@ -57,4 +57,4 @@ $app->run(); App::__construct hooked. App::run App::run traced. -[ddtrace] [info] [%d] Flushing trace of size 2 to send-queue for %s +[ddtrace] [info] [%d] Flushing v1 trace of size 2 to send-queue for %s diff --git a/tests/ext/sandbox/hook_method/posthook_error_02.phpt b/tests/ext/sandbox/hook_method/posthook_error_02.phpt index b206252922..c6edb3f157 100644 --- a/tests/ext/sandbox/hook_method/posthook_error_02.phpt +++ b/tests/ext/sandbox/hook_method/posthook_error_02.phpt @@ -31,4 +31,4 @@ Greeter::greet('Datadog'); Hello, Datadog. Greeter::greet hooked. [ddtrace] [warning] [%d] %s in ddtrace's closure defined at %s:%d for Greeter::greet(): Undefined variable%sthis_normally_raises_an_%s -[ddtrace] [info] [%d] Flushing trace of size 1 to send-queue for %s +[ddtrace] [info] [%d] Flushing v1 trace of size 1 to send-queue for %s diff --git a/tests/ext/sandbox/hook_method/prehook_error_02.phpt b/tests/ext/sandbox/hook_method/prehook_error_02.phpt index 8560f29d75..4e8163a710 100644 --- a/tests/ext/sandbox/hook_method/prehook_error_02.phpt +++ b/tests/ext/sandbox/hook_method/prehook_error_02.phpt @@ -31,4 +31,4 @@ Greeter::greet('Datadog'); Greeter::greet hooked. [ddtrace] [warning] [%d] %s in ddtrace's closure defined at %s:%d for Greeter::greet(): Undefined variable%sthis_normally_raises_an_%s Hello, Datadog. -[ddtrace] [info] [%d] Flushing trace of size 1 to send-queue for %s +[ddtrace] [info] [%d] Flushing v1 trace of size 1 to send-queue for %s diff --git a/tests/ext/sandbox/hook_method/prehook_exceptions_02.phpt b/tests/ext/sandbox/hook_method/prehook_exceptions_02.phpt index cad41da9e1..44ce172c86 100644 --- a/tests/ext/sandbox/hook_method/prehook_exceptions_02.phpt +++ b/tests/ext/sandbox/hook_method/prehook_exceptions_02.phpt @@ -36,4 +36,4 @@ Greeter::greet hooked. [ddtrace] [warning] [%d] Exception thrown in ddtrace's closure defined at %s:%d for Greeter::greet(): ! in %s on line %d Hello, Datadog. Done. -[ddtrace] [info] [%d] Flushing trace of size 1 to send-queue for %s +[ddtrace] [info] [%d] Flushing v1 trace of size 1 to send-queue for %s diff --git a/tests/ext/sandbox/install_hook/hook_scoped_file.phpt b/tests/ext/sandbox/install_hook/hook_scoped_file.phpt index f2936e1074..c2e0695a6a 100644 --- a/tests/ext/sandbox/install_hook/hook_scoped_file.phpt +++ b/tests/ext/sandbox/install_hook/hook_scoped_file.phpt @@ -32,7 +32,5 @@ dd_dump_spans(); test spans(\DDTrace\SpanData) (1) { A.include (hook_scoped_file.php, A.include, cli) - _dd.p.dm => -0 - _dd.p.tid => %s %stestinclude.inc (hook_scoped_file.php, %stestinclude.inc, cli) } diff --git a/tests/ext/sandbox/install_hook/trace_callable.phpt b/tests/ext/sandbox/install_hook/trace_callable.phpt index 805ebd8bd4..d4002c46eb 100644 --- a/tests/ext/sandbox/install_hook/trace_callable.phpt +++ b/tests/ext/sandbox/install_hook/trace_callable.phpt @@ -63,13 +63,10 @@ include __DIR__ . '/../dd_dumper.inc'; --EXPECTF-- spans(\DDTrace\SpanData) (3) { test\foo (trace_callable.php, 0, cli) - _dd.p.tid => %s result => 1 test\bar.foo (trace_callable.php, 1, cli) - _dd.p.tid => %s result => 2 test\closure.{closure} (trace_callable.php, 2, cli) - _dd.p.tid => %s closure.declaration => %s:%d result => 3 } diff --git a/tests/ext/sandbox/install_hook/trace_closure.phpt b/tests/ext/sandbox/install_hook/trace_closure.phpt index 671c9ddb02..c0dcede6be 100644 --- a/tests/ext/sandbox/install_hook/trace_closure.phpt +++ b/tests/ext/sandbox/install_hook/trace_closure.phpt @@ -72,33 +72,25 @@ include __DIR__ . '/../dd_dumper.inc'; --EXPECTF-- spans(\DDTrace\SpanData) (8) { intval (trace_closure.php, 0, cli) - _dd.p.tid => %s result => 0 test\trace_closure.php:7\{%s} (trace_closure.php, 1, cli) - _dd.p.tid => %s closure.declaration => %stests%cext%csandbox%cinstall_hook%ctrace_closure.php:7 result => 1 test\foo.{closure} (trace_closure.php, 2, cli) - _dd.p.tid => %s closure.declaration => %stests%cext%csandbox%cinstall_hook%ctrace_closure.php:12 result => 2 test\bar.foo.{closure} (trace_closure.php, 3, cli) - _dd.p.tid => %s closure.declaration => %stests%cext%csandbox%cinstall_hook%ctrace_closure.php:19 result => 3 intval (trace_closure.php, 0, cli) - _dd.p.tid => %s result => 1 test\trace_closure.php:7\{%s} (trace_closure.php, 1, cli) - _dd.p.tid => %s closure.declaration => %stests%cext%csandbox%cinstall_hook%ctrace_closure.php:7 result => 2 test\foo.{closure} (trace_closure.php, 2, cli) - _dd.p.tid => %s closure.declaration => %stests%cext%csandbox%cinstall_hook%ctrace_closure.php:12 result => 3 test\bar.foo.{closure} (trace_closure.php, 3, cli) - _dd.p.tid => %s closure.declaration => %stests%cext%csandbox%cinstall_hook%ctrace_closure.php:19 result => 4 } diff --git a/tests/ext/sandbox/install_hook/trace_closure_from_callable.phpt b/tests/ext/sandbox/install_hook/trace_closure_from_callable.phpt index 079728fa30..ff5f05b47a 100644 --- a/tests/ext/sandbox/install_hook/trace_closure_from_callable.phpt +++ b/tests/ext/sandbox/install_hook/trace_closure_from_callable.phpt @@ -37,16 +37,12 @@ include __DIR__ . '/../dd_dumper.inc'; --EXPECTF-- spans(\DDTrace\SpanData) (4) { foo (trace_closure_from_callable.php, foo, cli) - _dd.p.tid => %s global => 1 foo (trace_closure_from_callable.php, foo, cli) - _dd.p.tid => %s - fake => 1 global => 1 + fake => 1 foo (trace_closure_from_callable.php, foo, cli) - _dd.p.tid => %s global => 1 foo (trace_closure_from_callable.php, foo, cli) - _dd.p.tid => %s global => 1 } diff --git a/tests/ext/sandbox/install_hook/trace_closure_ge_php_84.phpt b/tests/ext/sandbox/install_hook/trace_closure_ge_php_84.phpt index fbf920b9df..bb3ad57b5a 100644 --- a/tests/ext/sandbox/install_hook/trace_closure_ge_php_84.phpt +++ b/tests/ext/sandbox/install_hook/trace_closure_ge_php_84.phpt @@ -71,33 +71,25 @@ include __DIR__ . '/../dd_dumper.inc'; --EXPECTF-- spans(\DDTrace\SpanData) (8) { intval (trace_closure_ge_php_84.php, 0, cli) - _dd.p.tid => %s result => 0 {closure:%s.php:7\{closure} (trace_closure_ge_php_84.php, 1, cli) - _dd.p.tid => %s closure.declaration => %stests%cext%csandbox%cinstall_hook%ctrace_closure_ge_php_84.php:7 result => 1 test\foo.{closure} (trace_closure_ge_php_84.php, 2, cli) - _dd.p.tid => %s closure.declaration => %stests%cext%csandbox%cinstall_hook%ctrace_closure_ge_php_84.php:12 result => 2 test\bar.foo.{closure} (trace_closure_ge_php_84.php, 3, cli) - _dd.p.tid => %s closure.declaration => %stests%cext%csandbox%cinstall_hook%ctrace_closure_ge_php_84.php:19 result => 3 intval (trace_closure_ge_php_84.php, 0, cli) - _dd.p.tid => %s result => 1 {closure:%s.php:7\{closure} (trace_closure_ge_php_84.php, 1, cli) - _dd.p.tid => %s closure.declaration => %stests%cext%csandbox%cinstall_hook%ctrace_closure_ge_php_84.php:7 result => 2 test\foo.{closure} (trace_closure_ge_php_84.php, 2, cli) - _dd.p.tid => %s closure.declaration => %stests%cext%csandbox%cinstall_hook%ctrace_closure_ge_php_84.php:12 result => 3 test\bar.foo.{closure} (trace_closure_ge_php_84.php, 3, cli) - _dd.p.tid => %s closure.declaration => %stests%cext%csandbox%cinstall_hook%ctrace_closure_ge_php_84.php:19 result => 4 } diff --git a/tests/ext/sandbox/install_hook/trace_file.phpt b/tests/ext/sandbox/install_hook/trace_file.phpt index 382f4531e4..101c89ad00 100644 --- a/tests/ext/sandbox/install_hook/trace_file.phpt +++ b/tests/ext/sandbox/install_hook/trace_file.phpt @@ -25,9 +25,5 @@ test test spans(\DDTrace\SpanData) (2) { %stestinclude.inc (trace_file.php, %sinstall_hook%ctestinclude.inc, cli) - _dd.p.dm => -0 - _dd.p.tid => %s %stestinclude.inc (trace_file.php, %sinstall_hook%ctestinclude.inc, cli) - _dd.p.dm => -0 - _dd.p.tid => %s } diff --git a/tests/ext/sandbox/install_hook/trace_function.phpt b/tests/ext/sandbox/install_hook/trace_function.phpt index 664e0a6494..ac8e4cb34a 100644 --- a/tests/ext/sandbox/install_hook/trace_function.phpt +++ b/tests/ext/sandbox/install_hook/trace_function.phpt @@ -49,9 +49,7 @@ include __DIR__ . '/../dd_dumper.inc'; --EXPECTF-- spans(\DDTrace\SpanData) (2) { test\foo (trace_function.php, 0, cli) - _dd.p.tid => %s result => 1 test\bar.foo (trace_function.php, 1, cli) - _dd.p.tid => %s result => 2 } diff --git a/tests/ext/sandbox/install_hook/trace_generator.phpt b/tests/ext/sandbox/install_hook/trace_generator.phpt index d1223a0204..b9fd082052 100644 --- a/tests/ext/sandbox/install_hook/trace_generator.phpt +++ b/tests/ext/sandbox/install_hook/trace_generator.phpt @@ -39,7 +39,6 @@ include __DIR__ . '/../dd_dumper.inc'; --EXPECTF-- spans(\DDTrace\SpanData) (1) { test\trace_generator.php:%d\{%s} (trace_generator.php, test\trace_generator.php:%d\{%s}, cli) - _dd.p.tid => %s closure.declaration => %s:%d result => 3 (trace_generator.php, cli) diff --git a/tests/ext/sandbox/install_hook/trace_generator_ge_php_84.phpt b/tests/ext/sandbox/install_hook/trace_generator_ge_php_84.phpt index 8954f507ab..44d3c41ed2 100644 --- a/tests/ext/sandbox/install_hook/trace_generator_ge_php_84.phpt +++ b/tests/ext/sandbox/install_hook/trace_generator_ge_php_84.phpt @@ -39,7 +39,6 @@ include __DIR__ . '/../dd_dumper.inc'; --EXPECTF-- spans(\DDTrace\SpanData) (1) { {closure:%s.php:%d\{closure} (trace_generator_ge_php_84.php, {closure:%s.php:%d\{closure}, cli) - _dd.p.tid => %s closure.declaration => %s:%d result => 3 (trace_generator_ge_php_84.php, cli) diff --git a/tests/ext/sandbox/manual_flush.phpt b/tests/ext/sandbox/manual_flush.phpt index ba000554ff..ff6ad4d632 100644 --- a/tests/ext/sandbox/manual_flush.phpt +++ b/tests/ext/sandbox/manual_flush.phpt @@ -21,5 +21,5 @@ main(); ?> --EXPECTF-- -[ddtrace] [info] [%d] Flushing trace of size 1 to send-queue for %s -[ddtrace] [info] [%d] Flushing trace of size 1 to send-queue for %s +[ddtrace] [info] [%d] Flushing v1 trace of size 1 to send-queue for %s +[ddtrace] [info] [%d] Flushing v1 trace of size 1 to send-queue for %s diff --git a/tests/ext/sandbox/retval_is_null_with_exception.phpt b/tests/ext/sandbox/retval_is_null_with_exception.phpt index be69b90dbb..50cf0c568b 100644 --- a/tests/ext/sandbox/retval_is_null_with_exception.phpt +++ b/tests/ext/sandbox/retval_is_null_with_exception.phpt @@ -31,4 +31,4 @@ try { bool(true) NULL Oops! -[ddtrace] [info] [%d] Flushing trace of size 2 to send-queue for %s +[ddtrace] [info] [%d] Flushing v1 trace of size 2 to send-queue for %s diff --git a/tests/ext/sandbox/safe_to_string_metadata.phpt b/tests/ext/sandbox/safe_to_string_metadata.phpt index 58efbfa21b..97dab3a546 100644 --- a/tests/ext/sandbox/safe_to_string_metadata.phpt +++ b/tests/ext/sandbox/safe_to_string_metadata.phpt @@ -57,9 +57,12 @@ $allTheTypes[0][1] = &$allTheTypes[0]; call_user_func_array('meta_to_string', $allTheTypes); list($span) = dd_trace_serialize_closed_spans(); -unset($span['meta']['process_id'], $span['meta']['_dd.tags.process'], $span['meta']['_dd.sdk.otlp_export']); +unset($span['attributes']['process_id'], $span['attributes']['_dd.tags.process'], $span['attributes']['_dd.sdk.otlp_export']); $last = -1; -foreach ($span['meta'] as $key => $value) { +foreach ($span['attributes'] as $key => $value) { + if (strpos($key, 'arg.') !== 0) { + continue; + } $index = (int)substr($key, 4); if ($last != $index) { echo PHP_EOL; @@ -74,50 +77,20 @@ foreach ($span['meta'] as $key => $value) { } ?> --EXPECTF-- - array(1) { [0]=> string(9) "recursive" } -arg.0.0: string(9) "recursive" -arg.0.1: string(0) "" +arg.0: array(2) { + [0]=> + string(9) "recursive" + [1]=> + string(0) "" +} string(16) "already a string" arg.1: string(16) "already a string" -array(1) { - ["foo"]=> - int(0) -} -arg.10.foo: string(1) "0" - -array(1) { - ["bar"]=> - array(2) { - [0]=> - int(1) - ["key"]=> - int(2) - } -} -arg.11.bar.0: string(1) "1" -arg.11.bar.key: string(1) "2" - -resource(%d) of type (stream) -arg.12: string(%d) "Resource id #%d" - -string(17) "string from const" -arg.13: string(17) "string from const" - -int(42) -arg.14: string(2) "42" - -bool(true) -arg.15: string(4) "true" - -float(4.2) -arg.16: string(3) "4.2" - int(42) arg.2: string(2) "42" @@ -145,9 +118,14 @@ object(DateTime)#%d (3) { ["timezone"]=> string(3) "UTC" } -arg.8.date: string(26) "2019-09-10 00:00:00.000000" -arg.8.timezone: string(3) "UTC" -arg.8.timezone_type: string(1) "3" +arg.8: array(3) { + ["date"]=> + string(26) "2019-09-10 00:00:00.000000" + ["timezone_type"]=> + string(1) "3" + ["timezone"]=> + string(3) "UTC" +} object(MyDt)#%d (3) { ["date"]=> @@ -157,6 +135,54 @@ object(MyDt)#%d (3) { ["timezone"]=> string(3) "UTC" } -arg.9.date: string(26) "2019-09-10 00:00:00.000000" -arg.9.timezone: string(3) "UTC" -arg.9.timezone_type: string(1) "3" +arg.9: array(3) { + ["date"]=> + string(26) "2019-09-10 00:00:00.000000" + ["timezone_type"]=> + string(1) "3" + ["timezone"]=> + string(3) "UTC" +} + +array(1) { + ["foo"]=> + int(0) +} +arg.10: array(1) { + ["foo"]=> + string(1) "0" +} + +array(1) { + ["bar"]=> + array(2) { + [0]=> + int(1) + ["key"]=> + int(2) + } +} +arg.11: array(1) { + ["bar"]=> + array(2) { + [0]=> + string(1) "1" + ["key"]=> + string(1) "2" + } +} + +resource(%d) of type (stream) +arg.12: string(%d) "Resource id #%d" + +string(17) "string from const" +arg.13: string(17) "string from const" + +int(42) +arg.14: string(2) "42" + +bool(true) +arg.15: string(4) "true" + +float(4.2) +arg.16: string(3) "4.2" \ No newline at end of file diff --git a/tests/ext/sandbox/safe_to_string_metadata_drops_invalid_keys.phpt b/tests/ext/sandbox/safe_to_string_metadata_drops_invalid_keys.phpt index db07b28e3a..900eb8dc58 100644 --- a/tests/ext/sandbox/safe_to_string_metadata_drops_invalid_keys.phpt +++ b/tests/ext/sandbox/safe_to_string_metadata_drops_invalid_keys.phpt @@ -20,8 +20,8 @@ DDTrace\trace_function('meta_to_string', function (SpanData $span) { meta_to_string(); list($span) = dd_clean_spans(); -unset($span['meta']['process_id']); -var_dump($span['meta']); +unset($span['attributes']['process_id']); +var_dump($span['attributes']); ?> --EXPECT-- array(2) { diff --git a/tests/ext/sandbox/safe_to_string_metadata_ge_php_84.phpt b/tests/ext/sandbox/safe_to_string_metadata_ge_php_84.phpt index fbec543abc..fd811fb96e 100644 --- a/tests/ext/sandbox/safe_to_string_metadata_ge_php_84.phpt +++ b/tests/ext/sandbox/safe_to_string_metadata_ge_php_84.phpt @@ -58,9 +58,14 @@ $allTheTypes[0][1] = &$allTheTypes[0]; call_user_func_array('meta_to_string', $allTheTypes); list($span) = dd_clean_spans(); -unset($span['meta']['process_id']); +// The v1 introspection shape merges meta+metrics into a single attributes map, so +// filter to the 'arg.*' string entries this test set (skipping runtime metrics, +// code-origin tags, etc.) before applying the arg-index/stringify assertions. $last = -1; -foreach ($span['meta'] as $key => $value) { +foreach ($span['attributes'] as $key => $value) { + if (strncmp($key, 'arg.', 4) !== 0) { + continue; + } $index = (int)substr($key, 4); if ($last != $index) { echo PHP_EOL; @@ -80,45 +85,16 @@ array(1) { [0]=> string(9) "recursive" } -arg.0.0: string(9) "recursive" -arg.0.1: string(0) "" +arg.0: array(2) { + [0]=> + string(9) "recursive" + [1]=> + string(0) "" +} string(16) "already a string" arg.1: string(16) "already a string" -array(1) { - ["foo"]=> - int(0) -} -arg.10.foo: string(1) "0" - -array(1) { - ["bar"]=> - array(2) { - [0]=> - int(1) - ["key"]=> - int(2) - } -} -arg.11.bar.0: string(1) "1" -arg.11.bar.key: string(1) "2" - -resource(%d) of type (stream) -arg.12: string(%d) "Resource id #%d" - -string(17) "string from const" -arg.13: string(17) "string from const" - -int(42) -arg.14: string(2) "42" - -bool(true) -arg.15: string(4) "true" - -float(4.2) -arg.16: string(3) "4.2" - int(42) arg.2: string(2) "42" @@ -152,9 +128,14 @@ object(DateTime)#%d (3) { ["timezone"]=> string(3) "UTC" } -arg.8.date: string(26) "2019-09-10 00:00:00.000000" -arg.8.timezone: string(3) "UTC" -arg.8.timezone_type: string(1) "3" +arg.8: array(3) { + ["date"]=> + string(26) "2019-09-10 00:00:00.000000" + ["timezone_type"]=> + string(1) "3" + ["timezone"]=> + string(3) "UTC" +} object(MyDt)#%d (3) { ["date"]=> @@ -164,6 +145,54 @@ object(MyDt)#%d (3) { ["timezone"]=> string(3) "UTC" } -arg.9.date: string(26) "2019-09-10 00:00:00.000000" -arg.9.timezone: string(3) "UTC" -arg.9.timezone_type: string(1) "3" +arg.9: array(3) { + ["date"]=> + string(26) "2019-09-10 00:00:00.000000" + ["timezone_type"]=> + string(1) "3" + ["timezone"]=> + string(3) "UTC" +} + +array(1) { + ["foo"]=> + int(0) +} +arg.10: array(1) { + ["foo"]=> + string(1) "0" +} + +array(1) { + ["bar"]=> + array(2) { + [0]=> + int(1) + ["key"]=> + int(2) + } +} +arg.11: array(1) { + ["bar"]=> + array(2) { + [0]=> + string(1) "1" + ["key"]=> + string(1) "2" + } +} + +resource(%d) of type (stream) +arg.12: string(%d) "Resource id #%d" + +string(17) "string from const" +arg.13: string(17) "string from const" + +int(42) +arg.14: string(2) "42" + +bool(true) +arg.15: string(4) "true" + +float(4.2) +arg.16: string(3) "4.2" diff --git a/tests/ext/sandbox/safe_to_string_metrics.phpt b/tests/ext/sandbox/safe_to_string_metrics.phpt index c3f1ee325b..723ba50051 100644 --- a/tests/ext/sandbox/safe_to_string_metrics.phpt +++ b/tests/ext/sandbox/safe_to_string_metrics.phpt @@ -33,7 +33,10 @@ call_user_func_array('metrics_to_string', $allTheTypes); list($span) = dd_trace_serialize_closed_spans(); $last = -1; -foreach ($span['metrics'] as $key => $value) { +foreach ($span['attributes'] as $key => $value) { + if (strpos($key, 'arg.') !== 0) { + continue; + } $index = (int)substr($key, 4); if ($last != $index) { echo PHP_EOL; @@ -48,13 +51,16 @@ foreach ($span['metrics'] as $key => $value) { } ?> --EXPECTF-- - array(1) { [0]=> int(42) } -arg.0.0: float(42) -arg.0.1: float(0) +arg.0: array(2) { + [0]=> + float(42) + [1]=> + float(0) +} int(42) arg.1: float(42) @@ -72,7 +78,10 @@ array(1) { [0]=> float(4.2) } -arg.5.0: float(4.2) +arg.5: array(1) { + [0]=> + float(4.2) +} array(3) { [0]=> @@ -82,9 +91,14 @@ array(3) { [2]=> float(3.3) } -arg.6.0: float(1.1) -arg.6.1: float(2.2) -arg.6.2: float(3.3) +arg.6: array(3) { + [0]=> + float(1.1) + [1]=> + float(2.2) + [2]=> + float(3.3) +} array(3) { [0]=> @@ -102,7 +116,19 @@ array(3) { float(3.3) } } -arg.7.0.0: float(4.2) -arg.7.0.1: float(42) -arg.7.1: float(2.2) -arg.7.2.0: float(3.3) +arg.7: array(3) { + [0]=> + array(2) { + [0]=> + float(4.2) + [1]=> + float(42) + } + [1]=> + float(2.2) + [2]=> + array(1) { + [0]=> + float(3.3) + } +} \ No newline at end of file diff --git a/tests/ext/sandbox/span_clone.phpt b/tests/ext/sandbox/span_clone.phpt index 0ce6e5ee72..44d2d29fc6 100644 --- a/tests/ext/sandbox/span_clone.phpt +++ b/tests/ext/sandbox/span_clone.phpt @@ -27,17 +27,13 @@ var_dump(dd_clean_spans()); ?> --EXPECTF-- -object(DDTrace\RootSpanData)#%d (24) { +object(DDTrace\RootSpanData)#%d (30) { ["name"]=> string(3) "foo" ["resource"]=> string(3) "abc" ["service"]=> string(14) "span_clone.php" - ["env"]=> - string(0) "" - ["version"]=> - string(0) "" ["meta_struct"]=> array(0) { } @@ -69,9 +65,9 @@ object(DDTrace\RootSpanData)#%d (24) { ["parent"]=> NULL ["stack"]=> - object(DDTrace\SpanStack)#%d (3) { + object(DDTrace\SpanStack)#%d (4) { ["parent"]=> - object(DDTrace\SpanStack)#%d (3) { + object(DDTrace\SpanStack)#%d (4) { ["parent"]=> NULL ["active"]=> @@ -79,24 +75,49 @@ object(DDTrace\RootSpanData)#%d (24) { ["spanCreationObservers"]=> array(0) { } + ["attributes"]=> + array(0) { + } } ["active"]=> *RECURSION* ["spanCreationObservers"]=> array(0) { } + ["attributes"]=> + array(0) { + } } ["onClose"]=> array(0) { } ["baggage"]=> array(0) { - }%r(\s*\["origin"\]=>\s+uninitialized\(string\))?%r + } + ["env"]=> + string(0) "" + ["version"]=> + string(0) "" + ["component"]=> + string(0) "" + ["spanKind"]=> + int(0) + ["attributes"]=> + array(2) { + ["runtime-id"]=> + string(36) "%s" + ["process_id"]=> + float(%f) + } + ["ignoreError"]=> + bool(false)%r(\s*\["origin"\]=>\s+uninitialized\(string\))?%r ["propagatedTags"]=> array(0) { } ["samplingPriority"]=> - int(1073741824)%r(\s*\["propagatedSamplingPriority"\]=>\s+uninitialized\(int\)\s*\["tracestate"\]=>\s+uninitialized\(string\))?%r + int(1073741824) + ["samplingMechanism"]=> + int(0)%r(\s*\["propagatedSamplingPriority"\]=>\s+uninitialized\(int\)\s*\["tracestate"\]=>\s+uninitialized\(string\))?%r ["tracestateTags"]=> array(0) { }%r(\s*\["parentId"\]=>\s+uninitialized\(string\))?%r @@ -106,18 +127,16 @@ object(DDTrace\RootSpanData)#%d (24) { NULL ["inferredSpan"]=> NULL + ["hostname"]=> + string(0) "" } -object(DDTrace\RootSpanData)#%d (24) { +object(DDTrace\RootSpanData)#%d (30) { ["name"]=> string(5) "dummy" ["resource"]=> string(3) "abc" ["service"]=> string(14) "span_clone.php" - ["env"]=> - string(0) "" - ["version"]=> - string(0) "" ["meta_struct"]=> array(0) { } @@ -149,9 +168,9 @@ object(DDTrace\RootSpanData)#%d (24) { ["parent"]=> NULL ["stack"]=> - object(DDTrace\SpanStack)#%d (3) { + object(DDTrace\SpanStack)#%d (4) { ["parent"]=> - object(DDTrace\SpanStack)#%d (3) { + object(DDTrace\SpanStack)#%d (4) { ["parent"]=> NULL ["active"]=> @@ -159,19 +178,18 @@ object(DDTrace\RootSpanData)#%d (24) { ["spanCreationObservers"]=> array(0) { } + ["attributes"]=> + array(0) { + } } ["active"]=> - object(DDTrace\RootSpanData)#%d (24) { + object(DDTrace\RootSpanData)#%d (30) { ["name"]=> string(3) "foo" ["resource"]=> string(3) "abc" ["service"]=> string(14) "span_clone.php" - ["env"]=> - string(0) "" - ["version"]=> - string(0) "" ["meta_struct"]=> array(0) { } @@ -209,12 +227,31 @@ object(DDTrace\RootSpanData)#%d (24) { } ["baggage"]=> array(0) { - }%r(\s*\["origin"\]=>\s+uninitialized\(string\))?%r + } + ["env"]=> + string(0) "" + ["version"]=> + string(0) "" + ["component"]=> + string(0) "" + ["spanKind"]=> + int(0) + ["attributes"]=> + array(2) { + ["runtime-id"]=> + string(36) "%s" + ["process_id"]=> + float(%f) + } + ["ignoreError"]=> + bool(false)%r(\s*\["origin"\]=>\s+uninitialized\(string\))?%r ["propagatedTags"]=> array(0) { } ["samplingPriority"]=> - int(1073741824)%r(\s*\["propagatedSamplingPriority"\]=>\s+uninitialized\(int\)\s*\["tracestate"\]=>\s+uninitialized\(string\))?%r + int(1073741824) + ["samplingMechanism"]=> + int(0)%r(\s*\["propagatedSamplingPriority"\]=>\s+uninitialized\(int\)\s*\["tracestate"\]=>\s+uninitialized\(string\))?%r ["tracestateTags"]=> array(0) { }%r(\s*\["parentId"\]=>\s+uninitialized\(string\))?%r @@ -224,22 +261,46 @@ object(DDTrace\RootSpanData)#%d (24) { NULL ["inferredSpan"]=> NULL + ["hostname"]=> + string(0) "" } ["spanCreationObservers"]=> array(0) { } + ["attributes"]=> + array(0) { + } } ["onClose"]=> array(0) { } ["baggage"]=> array(0) { - }%r(\s*\["origin"\]=>\s+uninitialized\(string\))?%r + } + ["env"]=> + string(0) "" + ["version"]=> + string(0) "" + ["component"]=> + string(0) "" + ["spanKind"]=> + int(0) + ["attributes"]=> + array(2) { + ["runtime-id"]=> + string(36) "%s" + ["process_id"]=> + float(%f) + } + ["ignoreError"]=> + bool(false)%r(\s*\["origin"\]=>\s+uninitialized\(string\))?%r ["propagatedTags"]=> array(0) { } ["samplingPriority"]=> - int(1073741824)%r(\s*\["propagatedSamplingPriority"\]=>\s+uninitialized\(int\)\s*\["tracestate"\]=>\s+uninitialized\(string\))?%r + int(1073741824) + ["samplingMechanism"]=> + int(0)%r(\s*\["propagatedSamplingPriority"\]=>\s+uninitialized\(int\)\s*\["tracestate"\]=>\s+uninitialized\(string\))?%r ["tracestateTags"]=> array(0) { }%r(\s*\["parentId"\]=>\s+uninitialized\(string\))?%r @@ -249,12 +310,16 @@ object(DDTrace\RootSpanData)#%d (24) { NULL ["inferredSpan"]=> NULL + ["hostname"]=> + string(0) "" } array(1) { [0]=> - array(10) { + array(12) { ["trace_id"]=> string(%d) "%d" + ["trace_id_high"]=> + string(16) "%s" ["span_id"]=> string(%d) "%d" ["start"]=> @@ -269,28 +334,23 @@ array(1) { string(14) "span_clone.php" ["type"]=> string(3) "cli" - ["meta"]=> - array(3) { - ["_dd.p.dm"]=> - string(2) "-0" - ["_dd.p.tid"]=> - string(16) "%s" + ["sampling_priority"]=> + int(1) + ["sampling_mechanism"]=> + int(0) + ["attributes"]=> + array(6) { ["runtime-id"]=> string(36) "%s" - } - ["metrics"]=> - array(6) { + ["process_id"]=> + float(%f) ["_dd.agent_psr"]=> float(1) - ["_sampling_priority_v1"]=> - float(1) ["php.compilation.total_time_ms"]=> float(%f) - ["php.memory.peak_real_usage_bytes"]=> - float(%f) ["php.memory.peak_usage_bytes"]=> float(%f) - ["process_id"]=> + ["php.memory.peak_real_usage_bytes"]=> float(%f) } } diff --git a/tests/ext/sandbox/static_tracing_closures_will_not_bind_this.phpt b/tests/ext/sandbox/static_tracing_closures_will_not_bind_this.phpt index a706195765..07d092f1c0 100644 --- a/tests/ext/sandbox/static_tracing_closures_will_not_bind_this.phpt +++ b/tests/ext/sandbox/static_tracing_closures_will_not_bind_this.phpt @@ -25,4 +25,4 @@ $foo->test(); --EXPECTF-- Foo::test() TRACED Foo::test() -[ddtrace] [info] [%d] Flushing trace of size 2 to send-queue for %s +[ddtrace] [info] [%d] Flushing v1 trace of size 2 to send-queue for %s diff --git a/tests/ext/sdk_otlp_export_marker.phpt b/tests/ext/sdk_otlp_export_marker.phpt index 1c04645c8f..0a9fb54f4b 100644 --- a/tests/ext/sdk_otlp_export_marker.phpt +++ b/tests/ext/sdk_otlp_export_marker.phpt @@ -18,7 +18,7 @@ $seen = []; foreach (dd_trace_serialize_closed_spans() as $span) { $first = !isset($seen[$span['trace_id']]); $seen[$span['trace_id']] = true; - echo ($first ? "first" : "other"), ": ", var_export($span['meta']['_dd.sdk.otlp_export'] ?? null, true), "\n"; + echo ($first ? "first" : "other"), ": ", var_export($span['attributes']['_dd.sdk.otlp_export'] ?? null, true), "\n"; } echo count($seen), " chunks\n"; ?> diff --git a/tests/ext/single-span_sampling/accept-single-span.phpt b/tests/ext/single-span_sampling/accept-single-span.phpt index 85f3f5014f..a101cf2f42 100644 --- a/tests/ext/single-span_sampling/accept-single-span.phpt +++ b/tests/ext/single-span_sampling/accept-single-span.phpt @@ -9,7 +9,11 @@ DD_SPAN_SAMPLING_RULES=[{"sample_rate":1}] DDTrace\start_span(); DDTrace\close_span(); -var_dump(dd_trace_serialize_closed_spans()[0]["metrics"]); +$attributes = dd_trace_serialize_closed_spans()[0]["attributes"]; +var_dump([ + "_dd.span_sampling.mechanism" => $attributes["_dd.span_sampling.mechanism"], + "_dd.span_sampling.rule_rate" => $attributes["_dd.span_sampling.rule_rate"], +]); ?> --EXPECT-- diff --git a/tests/ext/single-span_sampling/check-sample-rate.phpt b/tests/ext/single-span_sampling/check-sample-rate.phpt index 569ff40bc7..03104991a1 100644 --- a/tests/ext/single-span_sampling/check-sample-rate.phpt +++ b/tests/ext/single-span_sampling/check-sample-rate.phpt @@ -14,7 +14,7 @@ DD_TRACE_GENERATE_ROOT_SPAN=0 DDTrace\start_span(); DDTrace\close_span(); -$last = dd_trace_serialize_closed_spans()[0]["metrics"]; +$last = dd_trace_serialize_closed_spans()[0]["attributes"]; print "First span: rule_rate={$last["_dd.span_sampling.rule_rate"]}\n"; $droppedCount = 0; @@ -22,7 +22,7 @@ for ($i = 0; $i < 7; ++$i) { DDTrace\start_span(); DDTrace\close_span(); - $last = dd_trace_serialize_closed_spans()[0]["metrics"]; + $last = dd_trace_serialize_closed_spans()[0]["attributes"]; $droppedCount += !isset($last["_dd.span_sampling.mechanism"]); } echo "$droppedCount dropped out of 7\n"; @@ -32,7 +32,7 @@ for ($i = 0; $i < 3; ++$i) { DDTrace\start_span(); DDTrace\close_span(); - $last = dd_trace_serialize_closed_spans()[0]["metrics"]; + $last = dd_trace_serialize_closed_spans()[0]["attributes"]; $droppedCount += !isset($last["_dd.span_sampling.mechanism"]); } echo "$droppedCount dropped out of 3\n"; @@ -42,7 +42,7 @@ usleep(350000); DDTrace\start_span(); DDTrace\close_span(); -$last = dd_trace_serialize_closed_spans()[0]["metrics"]; +$last = dd_trace_serialize_closed_spans()[0]["attributes"]; echo "11th span: rule_rate={$last["_dd.span_sampling.rule_rate"]}\n"; ?> diff --git a/tests/ext/single-span_sampling/limited-single-span-with-match.phpt b/tests/ext/single-span_sampling/limited-single-span-with-match.phpt index 20df9b9f21..1efa998485 100644 --- a/tests/ext/single-span_sampling/limited-single-span-with-match.phpt +++ b/tests/ext/single-span_sampling/limited-single-span-with-match.phpt @@ -16,7 +16,7 @@ for ($i = 0; $i < 5; ++$i) { DDTrace\active_span()->service = "a"; DDTrace\close_span(); - $last = dd_trace_serialize_closed_spans()[0]["metrics"]; + $last = dd_trace_serialize_closed_spans()[0]["attributes"]; $droppedCount += !isset($last["_dd.span_sampling.mechanism"]); } @@ -28,7 +28,7 @@ for ($i = 0; $i < 5; ++$i) { DDTrace\active_span()->name = "b"; DDTrace\close_span(); - $last = dd_trace_serialize_closed_spans()[0]["metrics"]; + $last = dd_trace_serialize_closed_spans()[0]["attributes"]; $droppedCount += !isset($last["_dd.span_sampling.mechanism"]); } @@ -41,7 +41,7 @@ for ($i = 0; $i < 5; ++$i) { DDTrace\active_span()->name = "b"; DDTrace\close_span(); - $last = dd_trace_serialize_closed_spans()[0]["metrics"]; + $last = dd_trace_serialize_closed_spans()[0]["attributes"]; $droppedCount += !isset($last["_dd.span_sampling.mechanism"]); } diff --git a/tests/ext/single-span_sampling/limited-single-span.phpt b/tests/ext/single-span_sampling/limited-single-span.phpt index fae3630103..1c2dacae45 100644 --- a/tests/ext/single-span_sampling/limited-single-span.phpt +++ b/tests/ext/single-span_sampling/limited-single-span.phpt @@ -14,7 +14,7 @@ for ($i = 0; $i < 3; ++$i) { DDTrace\start_span(); DDTrace\close_span(); - $last = dd_trace_serialize_closed_spans()[0]["metrics"]; + $last = dd_trace_serialize_closed_spans()[0]["attributes"]; } echo "mechanism after 3: ", $last["_dd.span_sampling.mechanism"], "\n"; @@ -23,7 +23,7 @@ for ($i = 0; $i < 12; ++$i) { DDTrace\start_span(); DDTrace\close_span(); - $last = dd_trace_serialize_closed_spans()[0]["metrics"]; + $last = dd_trace_serialize_closed_spans()[0]["attributes"]; } echo "sampling present after 12: "; diff --git a/tests/ext/single-span_sampling/name-matching-single-span.phpt b/tests/ext/single-span_sampling/name-matching-single-span.phpt index 713dd552a2..0b93c97006 100644 --- a/tests/ext/single-span_sampling/name-matching-single-span.phpt +++ b/tests/ext/single-span_sampling/name-matching-single-span.phpt @@ -27,14 +27,14 @@ foreach ($tests as list($pattern, $service)) { DDTrace\start_span()->service = $service; DDTrace\close_span(); echo "$pattern matches $service (service): "; - var_dump((dd_trace_serialize_closed_spans()[0]["metrics"]["_dd.span_sampling.mechanism"] ?? 0) == 8); + var_dump((dd_trace_serialize_closed_spans()[0]["attributes"]["_dd.span_sampling.mechanism"] ?? 0) == 8); ini_set("datadog.span_sampling_rules", '[{"name":"' . $pattern . '","sample_rate":1}]'); DDTrace\start_span()->name = $service; DDTrace\close_span(); echo "$pattern matches $service (name): "; - var_dump((dd_trace_serialize_closed_spans()[0]["metrics"]["_dd.span_sampling.mechanism"] ?? 0) == 8); + var_dump((dd_trace_serialize_closed_spans()[0]["attributes"]["_dd.span_sampling.mechanism"] ?? 0) == 8); } ?> diff --git a/tests/ext/single-span_sampling/read-single-span-sampling-config-from-file.phpt b/tests/ext/single-span_sampling/read-single-span-sampling-config-from-file.phpt index 235bb2cdf8..4c9d625460 100644 --- a/tests/ext/single-span_sampling/read-single-span-sampling-config-from-file.phpt +++ b/tests/ext/single-span_sampling/read-single-span-sampling-config-from-file.phpt @@ -12,14 +12,14 @@ ini_set("datadog.span_sampling_rules_file", __DIR__ . "/read-single-span-samplin DDTrace\start_span(); DDTrace\close_span(); -$last = dd_trace_serialize_closed_spans()[0]["metrics"]; +$last = dd_trace_serialize_closed_spans()[0]["attributes"]; echo "sampling present after simple span: "; var_dump(isset($last["_dd.span_sampling.mechanism"])); $a = DDTrace\start_span(); $a->service = "a"; DDTrace\close_span(); -$last = dd_trace_serialize_closed_spans()[0]["metrics"]; +$last = dd_trace_serialize_closed_spans()[0]["attributes"]; echo "sampling present after span of service a: "; var_dump(isset($last["_dd.span_sampling.mechanism"])); diff --git a/tests/ext/span_attributes_empty_keys.phpt b/tests/ext/span_attributes_empty_keys.phpt new file mode 100644 index 0000000000..aa75f194f8 --- /dev/null +++ b/tests/ext/span_attributes_empty_keys.phpt @@ -0,0 +1,27 @@ +--TEST-- +Empty attribute keys and values survive the native read-back (empty Rust slices carry a dangling ptr) +--ENV-- +DD_TRACE_GENERATE_ROOT_SPAN=0 +DD_TRACE_AUTO_FLUSH_ENABLED=0 +DD_CODE_ORIGIN_FOR_SPANS_ENABLED=0 +--FILE-- +attributes = [ + '' => 'empty key', // dropped: a top-level attribute needs a key + 'empty' => '', + 'nested' => ['a' => ['b' => ['' => 1, 'c' => '']]], + 'list' => ['', ['' => '']], +]; +\DDTrace\close_span(); + +$attrs = dd_trace_serialize_closed_spans()[0]['attributes']; +foreach (['', 'empty', 'nested', 'list'] as $key) { + echo var_export($key, true), ' => ', json_encode(isset($attrs[$key]) ? $attrs[$key] : null), "\n"; +} +?> +--EXPECT-- +'' => null +'empty' => "" +'nested' => {"a":{"b":{"":1,"c":""}}} +'list' => ["",{"":""}] diff --git a/tests/ext/span_attributes_input.phpt b/tests/ext/span_attributes_input.phpt new file mode 100644 index 0000000000..60b4f712f7 --- /dev/null +++ b/tests/ext/span_attributes_input.phpt @@ -0,0 +1,119 @@ +--TEST-- +SpanData::$attributes is the tag store: typed values, $meta/$metrics writes land in it (last write wins), special keys lifted +--ENV-- +DD_TRACE_GENERATE_ROOT_SPAN=0 +DD_TRACE_AUTO_FLUSH_ENABLED=0 +DD_CODE_ORIGIN_FOR_SPANS_ENABLED=0 +--FILE-- +name = 'original.name'; +$s->attributes = [ + 'int' => 42, + 'float' => 1.5, + 'bool' => true, + 'string' => 'str', + 'null' => null, + 'list' => [1, 'two', false], + 'map' => ['k' => 'v', 'n' => [3]], + 'object' => new Point, + // overwritten below through $meta / $metrics + 'both' => 'from attributes', + 'all' => 'from attributes', + // special keys + 'service.name' => 'attr-service', + 'resource.name' => 'attr-resource', + 'operation.name' => 'Attr.Operation', + 'span.type' => 'attr-type', + 'env' => 'attr-env', + 'version' => 'attr-version', + 'component' => 'attr-component', + 'span.kind' => 'client', + 'analytics.event' => true, + 'http.status_code' => 404, + '_sampling_priority_v1' => 2, + '_dd1.sr.eausr' => 1, + 'error.ignored' => true, +]; +$s->meta['both'] = 'from meta'; +$s->meta['all'] = 'from meta'; +$s->meta['meta_only'] = 'from meta'; +$s->meta['meta_metric'] = 'from meta'; +$s->metrics['all'] = 3; +$s->metrics['meta_metric'] = 4; +$s->metrics['metric_only'] = 5; +$s->exception = new Exception('ignored via the attributes tag'); +\DDTrace\close_span(); + +$span = dd_trace_serialize_closed_spans()[0]; +foreach (['name', 'resource', 'service', 'type', 'env', 'version', 'component', 'span_kind'] as $field) { + echo "$field: ", var_export(isset($span[$field]) ? $span[$field] : null, true), "\n"; +} +echo "error: ", isset($span['error']) ? $span['error'] : 0, "\n"; +$attrs = $span['attributes']; +foreach (['runtime-id', 'process_id', '_dd.p.tid', '_dd.p.dm', '_dd.tags.process', '_dd.sdk.otlp_export', '_dd.agent_psr', '_dd.svc_src', 'php.compilation.total_time_ms', 'php.memory.peak_real_usage_bytes', 'php.memory.peak_usage_bytes'] as $volatile) { + unset($attrs[$volatile]); +} +ksort($attrs); +var_dump($attrs); +?> +--EXPECT-- +name: 'attr.operation' +resource: 'attr-resource' +service: 'attr-service' +type: 'attr-type' +env: 'attr-env' +version: 'attr-version' +component: 'attr-component' +span_kind: 3 +error: 0 +array(14) { + ["_dd1.sr.eausr"]=> + float(1) + ["all"]=> + float(3) + ["bool"]=> + bool(true) + ["both"]=> + string(9) "from meta" + ["float"]=> + float(1.5) + ["http.status_code"]=> + string(3) "404" + ["int"]=> + int(42) + ["list"]=> + array(3) { + [0]=> + int(1) + [1]=> + string(3) "two" + [2]=> + bool(false) + } + ["map"]=> + array(2) { + ["k"]=> + string(1) "v" + ["n"]=> + array(1) { + [0]=> + int(3) + } + } + ["meta_metric"]=> + float(4) + ["meta_only"]=> + string(9) "from meta" + ["metric_only"]=> + float(5) + ["object"]=> + array(1) { + ["x"]=> + int(1) + } + ["string"]=> + string(3) "str" +} \ No newline at end of file diff --git a/tests/ext/span_data_attributes_init.phpt b/tests/ext/span_data_attributes_init.phpt new file mode 100644 index 0000000000..bacd6de58a --- /dev/null +++ b/tests/ext/span_data_attributes_init.phpt @@ -0,0 +1,47 @@ +--TEST-- +Directly constructed span/stack objects expose an initialized attributes array +--DESCRIPTION-- +The declared `public array $attributes = []` must materialize to an empty array on +every PHP version. On PHP 7 the create_object callbacks (dd_init_span_data_object, +ddtrace_span_stack_create) must init property_attributes explicitly, since typed +array properties there default to NULL rather than their stub default. +--FILE-- +attributes); +var_dump((new \DDTrace\RootSpanData())->attributes); +var_dump((new \DDTrace\InferredSpanData())->attributes); +var_dump((new \DDTrace\SpanStack())->attributes); +var_dump((new UserSpan())->attributes); + +$span = new UserSpan(); +$span->attributes['k'] = 'v'; +var_dump($span->attributes); + +// Tracer-created spans and stacks go through the same create_object callbacks. +$s = \DDTrace\start_span(); +var_dump($s->attributes, $s->stack->attributes); +\DDTrace\close_span(); +?> +--EXPECT-- +array(0) { +} +array(0) { +} +array(0) { +} +array(0) { +} +array(0) { +} +array(1) { + ["k"]=> + string(1) "v" +} +array(0) { +} +array(0) { +} diff --git a/tests/ext/span_data_meta_view.phpt b/tests/ext/span_data_meta_view.phpt new file mode 100644 index 0000000000..c86802fa5b --- /dev/null +++ b/tests/ext/span_data_meta_view.phpt @@ -0,0 +1,141 @@ +--TEST-- +SpanData::$meta and $metrics are views onto SpanData::$attributes +--DESCRIPTION-- +$attributes is the single tag store: writes, unsets and reads through the deprecated $meta +(non-numeric entries, stored as strings) and $metrics (numeric entries, stored as floats) act on it, +and the last write wins. +--ENV-- +DD_TRACE_AUTO_FLUSH_ENABLED=0 +DD_TRACE_GENERATE_ROOT_SPAN=0 +DD_TAGS=team:a,region:eu +--FILE-- +attributes['http.url'] = 'https://tracer.example'; +var_dump($span->meta['http.url']); +$span->meta['http.url'] = 'https://user.example'; +var_dump($span->attributes['http.url']); + +echo "-- unset through meta\n"; +unset($span->meta['http.url']); +var_dump(isset($span->attributes['http.url']), isset($span->meta['http.url'])); + +echo "-- buckets and coercion\n"; +$span->meta['num'] = 42; +$span->metrics['m'] = 3; +var_dump($span->attributes['num'], $span->attributes['m']); +var_dump(isset($span->meta['m']), isset($span->metrics['m']), isset($span->metrics['num'])); +var_dump($span->meta['missing'] ?? 'default', empty($span->meta['num'])); + +echo "-- array functions on a read\n"; +var_dump(is_array($span->meta), array_key_exists('num', $span->meta), array_key_exists('m', $span->meta)); +$merged = array_merge($span->meta, ['x' => 'y']); +var_dump($merged['num'], $merged['x']); +$span->meta += ['added' => 'yes']; +var_dump($span->attributes['added']); + +echo "-- nested values keep the old string leaves\n"; +$span->meta['nested'] = ['a' => 1, 'b' => [true, null], 'c' => []]; +var_dump($span->attributes['nested']); + +echo "-- whole-array assignment replaces the bucket\n"; +$span->meta = ['only' => 'this']; +var_dump($span->meta, $span->metrics['m'], isset($span->attributes['team'])); + +echo "-- iteration and the view object\n"; +$span->meta['k2'] = 'v2'; +foreach ($span->meta as $k => $v) { + echo "$k=$v\n"; +} +$view = &$span->meta; +var_dump(get_class($view), count($view), $view instanceof ArrayAccess, $view instanceof Countable, $view instanceof IteratorAggregate); +$view['via_ref'] = 'r'; +unset($view); +var_dump($span->attributes['via_ref']); + +echo "-- isset/?? contexts and writes through attributes\n"; +$x = $span->meta ?? []; +var_dump(is_array($x), array_merge($x, ['extra' => 'e'])['extra']); +$span->attributes['via_attrs'] = 'a'; +var_dump(isset($span->meta['via_attrs']), isset($span->metrics['via_attrs'])); +\DDTrace\close_span(); + +echo "-- DD_TAGS globals\n"; +$s1 = \DDTrace\start_span(); +$s1->name = 's1'; +unset($s1->meta['team']); +\DDTrace\close_span(); +$s2 = \DDTrace\start_span(); +$s2->name = 's2'; +$s2->meta['team'] = 'b'; +\DDTrace\close_span(); +\DDTrace\close_span(); +foreach (dd_trace_serialize_closed_spans() as $serialized) { + if (in_array($serialized['name'], ['s1', 's2'])) { + echo $serialized['name'], ': team=', $serialized['attributes']['team'] ?? 'unset', ' region=', $serialized['attributes']['region'], "\n"; + } +} +?> +--EXPECT-- +-- tracer tag read and overridden through meta +string(22) "https://tracer.example" +string(20) "https://user.example" +-- unset through meta +bool(false) +bool(false) +-- buckets and coercion +string(2) "42" +float(3) +bool(false) +bool(true) +bool(false) +string(7) "default" +bool(false) +-- array functions on a read +bool(true) +bool(true) +bool(false) +string(2) "42" +string(1) "y" +string(3) "yes" +-- nested values keep the old string leaves +array(3) { + ["a"]=> + string(1) "1" + ["b"]=> + array(2) { + [0]=> + string(4) "true" + [1]=> + string(4) "null" + } + ["c"]=> + string(0) "" +} +-- whole-array assignment replaces the bucket +array(1) { + ["only"]=> + string(4) "this" +} +float(3) +bool(false) +-- iteration and the view object +only=this +k2=v2 +string(20) "DDTrace\SpanTagsView" +int(2) +bool(true) +bool(true) +bool(true) +string(1) "r" +-- isset/?? contexts and writes through attributes +bool(true) +string(1) "e" +bool(true) +bool(false) +-- DD_TAGS globals +s2: team=b region=eu +s1: team=unset region=eu diff --git a/tests/ext/span_data_meta_view_jit.phpt b/tests/ext/span_data_meta_view_jit.phpt new file mode 100644 index 0000000000..3b45f92eff --- /dev/null +++ b/tests/ext/span_data_meta_view_jit.phpt @@ -0,0 +1,48 @@ +--TEST-- +SpanData::$meta / $metrics views under the tracing JIT +--SKIPIF-- + + +--ENV-- +DD_TRACE_AUTO_FLUSH_ENABLED=0 +DD_TRACE_GENERATE_ROOT_SPAN=0 +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.jit_buffer_size=32M +opcache.jit=tracing +opcache.jit_hot_loop=1 +opcache.jit_hot_func=1 +zend_extension=opcache.so +--FILE-- +meta["k$i"] = $i; + $span->metrics["m$i"] = $i; + if (isset($span->meta["k" . ($i - 1)])) { + unset($span->meta["k" . ($i - 1)]); + } + return count($span->meta) + count($span->metrics); +} + +\DDTrace\start_span(); +$span = \DDTrace\start_span(); +$total = 0; +for ($i = 0; $i < 200; $i++) { + $total += tag($span, $i); +} +$meta = $span->meta; +var_dump($total > 0, array_values(preg_grep('/^k/', array_keys($meta))), $span->attributes['k199']); +var_dump(count(preg_grep('/^m\d+$/', array_keys($span->metrics))), $span->metrics['m199']); +\DDTrace\close_span(); +\DDTrace\close_span(); +?> +--EXPECT-- +bool(true) +array(1) { + [0]=> + string(4) "k199" +} +string(3) "199" +int(200) +float(199) diff --git a/tests/ext/span_ignore_error.phpt b/tests/ext/span_ignore_error.phpt new file mode 100644 index 0000000000..513c8c6190 --- /dev/null +++ b/tests/ext/span_ignore_error.phpt @@ -0,0 +1,65 @@ +--TEST-- +SpanData::$ignoreError and the deprecated meta['error.ignored'] suppress the span error; the child gets track_error=false +--ENV-- +DD_TRACE_GENERATE_ROOT_SPAN=0 +DD_TRACE_AUTO_FLUSH_ENABLED=0 +--FILE-- +ignoreError); + +function run($label, $ignore) { + echo "$label\n"; + $e = new Exception("boom"); + $root = \DDTrace\start_span(); + $root->name = 'root'; + $child = \DDTrace\start_span(); + $child->name = 'child'; + $child->exception = $e; + \DDTrace\close_span(); + $root->exception = $e; + $ignore($root); + \DDTrace\close_span(); + foreach (dd_trace_serialize_closed_spans() as $span) { + $attrs = isset($span['attributes']) ? $span['attributes'] : []; + $errorTags = array_filter(array_keys($attrs), function ($k) { return strpos($k, 'error') === 0; }); + sort($errorTags); + echo " ", $span['name'], ": error=", isset($span['error']) ? $span['error'] : 0, + " error tags=[", implode(',', $errorTags), "]", + " track_error=", isset($attrs['track_error']) ? $attrs['track_error'] : '-', "\n"; + } + echo " root ignoreError after flush: ", var_export($root->ignoreError, true), "\n"; +} + +run('not ignored', function ($root) {}); +run('property', function ($root) { $root->ignoreError = true; }); +run('deprecated tag', function ($root) { $root->meta['error.ignored'] = 1; }); +run('deprecated falsy tag cannot unset the property', function ($root) { $root->ignoreError = true; $root->meta['error.ignored'] = 0; }); +run('deprecated falsy tag alone', function ($root) { $root->meta['error.ignored'] = 0; }); +run('falsy attributes tag does not mask a truthy meta tag', function ($root) { $root->attributes['error.ignored'] = 0; $root->meta['error.ignored'] = 1; }); +?> +--EXPECT-- +bool(false) +not ignored + root: error=1 error tags=[error.message,error.stack,error.type] track_error=- + child: error=1 error tags=[error.message,error.stack,error.type] track_error=- + root ignoreError after flush: false +property + root: error=0 error tags=[] track_error=- + child: error=1 error tags=[error.message,error.stack,error.type] track_error=false + root ignoreError after flush: true +deprecated tag + root: error=0 error tags=[] track_error=- + child: error=1 error tags=[error.message,error.stack,error.type] track_error=false + root ignoreError after flush: true +deprecated falsy tag cannot unset the property + root: error=0 error tags=[] track_error=- + child: error=1 error tags=[error.message,error.stack,error.type] track_error=false + root ignoreError after flush: true +deprecated falsy tag alone + root: error=1 error tags=[error.message,error.stack,error.type] track_error=- + child: error=1 error tags=[error.message,error.stack,error.type] track_error=- + root ignoreError after flush: false +falsy attributes tag does not mask a truthy meta tag + root: error=0 error tags=[] track_error=- + child: error=1 error tags=[error.message,error.stack,error.type] track_error=false + root ignoreError after flush: true diff --git a/tests/ext/span_kind_meta_fallback_promoted.phpt b/tests/ext/span_kind_meta_fallback_promoted.phpt new file mode 100644 index 0000000000..b764dc426e --- /dev/null +++ b/tests/ext/span_kind_meta_fallback_promoted.phpt @@ -0,0 +1,30 @@ +--TEST-- +Root span with only meta["span.kind"] (no property) still promotes span_kind (R2 meta fallback) +--DESCRIPTION-- +Entrypoint/integration spans set span.kind via meta (serializer writes meta["span.kind"]="server" +for HTTP roots), not via the OTel property. The V1-only serializer must fall back to the meta value +when property_span_kind is unset, so the promoted top-level span_kind is still emitted. Agent-free: +asserts the introspection view that mirrors the V1 builder's promoted fields. +--INI-- +datadog.trace.generate_root_span=0 +--ENV-- +DD_TRACE_AUTO_FLUSH_ENABLED=0 +--FILE-- +name = "http.request"; +$s->service = "web"; +$s->meta["span.kind"] = "server"; // meta only, no $s->kind property +\DDTrace\close_span(); + +$spans = dd_trace_serialize_closed_spans(); +$root = $spans[0]; +// server == OTEL SpanKind 2; promoted from meta fallback (dd_span_kind_meta_to_otel). The serializer +// consumes meta["span.kind"] once promoted, so the introspection (pre-encode builder) view no longer +// carries it in the unified attributes map; the wire decoders re-materialise span.kind downstream. +echo "span_kind=" . var_export($root["span_kind"] ?? null, true) . "\n"; +echo "attributes.span.kind=" . var_export($root["attributes"]["span.kind"] ?? null, true) . "\n"; +?> +--EXPECT-- +span_kind=2 +attributes.span.kind=NULL diff --git a/tests/ext/span_link_event_recursive_attributes.phpt b/tests/ext/span_link_event_recursive_attributes.phpt new file mode 100644 index 0000000000..9363a9061e --- /dev/null +++ b/tests/ext/span_link_event_recursive_attributes.phpt @@ -0,0 +1,57 @@ +--TEST-- +Self-referencing span link, event and meta attributes serialize with a bounded "" placeholder +--ENV-- +DD_TRACE_DEBUG_PRNG_SEED=42 +--FILE-- +name = 'foo'; + + $arr = ['x']; + $arr[] = &$arr; + $obj = new stdClass; + $obj->v = 1; + $obj->self = $obj; + $ao = new ArrayObject(['d' => 2]); + $ao['self'] = $ao; + // DateTime builds a fresh properties table on every read, so only an object-level guard stops it. + $dt = new DateTime('2020-01-01 00:00:00 UTC'); + @$dt->self = $dt; + $attrs = ['arr' => $arr, 'obj' => $obj, 'ao' => $ao, 'empty' => []]; + + $link = new SpanLink(); + $link->traceId = "42"; + $link->spanId = "6"; + $link->attributes = $attrs + ['dt' => $dt]; + $span->links[] = $link; + $span->events[] = new SpanEvent('evt', $attrs + ['dt' => $dt], 1); + $span->meta['dt'] = $dt; +}); + +foo(); + +$spans = dd_trace_serialize_closed_spans(); +foreach ([$spans[0]['span_links'][0]['attributes'], $spans[0]['span_events'][0]['attributes']] as $attrs) { + $dt = $attrs['dt']; + unset($attrs['dt']); + echo json_encode($attrs), "\n"; + var_dump($dt['self'], $dt['timezone']); +} +var_dump($spans[0]['attributes']['dt']['self']); + +?> +--EXPECT-- +{"arr":["x",""],"obj":{"v":1,"self":""},"ao":{"d":2,"self":""},"empty":[]} +string(0) "" +string(3) "UTC" +{"arr":["x",""],"obj":{"v":1,"self":""},"ao":{"d":2,"self":""},"empty":[]} +string(0) "" +string(3) "UTC" +string(0) "" diff --git a/tests/ext/span_on_close.phpt b/tests/ext/span_on_close.phpt index a58461fa4e..7267d0e6fb 100644 --- a/tests/ext/span_on_close.phpt +++ b/tests/ext/span_on_close.phpt @@ -26,8 +26,8 @@ $span->onClose = [ --EXPECTF-- Second First -[ddtrace] [span] [%d] Encoding span: Span { service: %s, name: root span, resource: root span, type: cli, trace_id: %d, span_id: %d, parent_id: %d, start: %d, duration: %d, error: %d, meta: %s, metrics: %s, meta_struct: %s, span_links: %s, span_events: %s } -[ddtrace] [span] [%d] Encoding span: Span { service: %s, name: inner span, resource: datadogs are awesome, type: cli, trace_id: %d, span_id: %d, parent_id: %d, start: %d, duration: %d, error: %d, meta: %s, metrics: %s, meta_struct: %s, span_links: %s, span_events: %s } -[ddtrace] [info] [%d] Flushing trace of size 2 to send-queue for %s +[ddtrace] [span] [%d] Encoding span: trace_id=%s service="%s" name="root span" resource="root span" type="cli" span_id=%d parent_id=%d start=%d duration=%d error=%s kind=%s env="" version="" component="" attributes=%s links=%d events=%d +[ddtrace] [span] [%d] Encoding span: trace_id=%s service="%s" name="inner span" resource="datadogs are awesome" type="cli" span_id=%d parent_id=%d start=%d duration=%d error=%s kind=%s env="" version="" component="" attributes=%s links=%d events=%d +[ddtrace] [info] [%d] Flushing v1 trace of size 2 to send-queue for %s [ddtrace] [info] [%d] No finished traces to be sent to the agent diff --git a/tests/ext/span_stack/span_stack_clone.phpt b/tests/ext/span_stack/span_stack_clone.phpt index 0fac818cd8..09fb6a7089 100644 --- a/tests/ext/span_stack/span_stack_clone.phpt +++ b/tests/ext/span_stack/span_stack_clone.phpt @@ -53,18 +53,8 @@ A clone of the primary trace has the root stack as parent: bool(true) Switching to an initial stacks parent has no effect: bool(true) spans(\DDTrace\SpanData) (5) { primary (span_stack_clone.php, primary, cli) - _dd.p.dm => -0 - _dd.p.tid => %s root (span_stack_clone.php, root, cli) - _dd.p.dm => -0 - _dd.p.tid => %s root clone (span_stack_clone.php, root clone, cli) - _dd.p.dm => -0 - _dd.p.tid => %s primary clone (span_stack_clone.php, primary clone, cli) - _dd.p.dm => -0 - _dd.p.tid => %s initial clone (span_stack_clone.php, initial clone, cli) - _dd.p.dm => -0 - _dd.p.tid => %s } diff --git a/tests/ext/span_stack/span_stack_swap.phpt b/tests/ext/span_stack/span_stack_swap.phpt index 6265967c55..13583bca43 100644 --- a/tests/ext/span_stack/span_stack_swap.phpt +++ b/tests/ext/span_stack/span_stack_swap.phpt @@ -81,12 +81,8 @@ But we can still swap to stacks started before that: bool(true) We closed the active stack after all other stacks were closed. No other span is active right now: bool(true) spans(\DDTrace\SpanData) (2) { span_stack_swap.php (span_stack_swap.php, span_stack_swap.php, cli) - _dd.p.dm => -0 - _dd.p.tid => %s (span_stack_swap.php, cli) (span_stack_swap.php, cli) (span_stack_swap.php, cli) other root (span_stack_swap.php, other root, cli) - _dd.p.dm => -0 - _dd.p.tid => %s } diff --git a/tests/ext/span_stack/span_stack_swap_traced_function.phpt b/tests/ext/span_stack/span_stack_swap_traced_function.phpt index 8906df1d6c..45bb78d1a1 100644 --- a/tests/ext/span_stack/span_stack_swap_traced_function.phpt +++ b/tests/ext/span_stack/span_stack_swap_traced_function.phpt @@ -59,8 +59,6 @@ Now, we have explicitly closed it: bool(true) We closed the active stack after all other stacks were closed. No other span is active right now: bool(true) spans(\DDTrace\SpanData) (1) { span_stack_swap_traced_function.php (span_stack_swap_traced_function.php, span_stack_swap_traced_function.php, cli) - _dd.p.dm => -0 - _dd.p.tid => %s outer (span_stack_swap_traced_function.php, outer, cli) creates_span_stack (span_stack_swap_traced_function.php, creates_span_stack, cli) inner (span_stack_swap_traced_function.php, inner, cli) diff --git a/tests/ext/span_stack/span_trace_stack_autoclose.phpt b/tests/ext/span_stack/span_trace_stack_autoclose.phpt index 92283b61b4..03a54c0d0e 100644 --- a/tests/ext/span_stack/span_trace_stack_autoclose.phpt +++ b/tests/ext/span_stack/span_trace_stack_autoclose.phpt @@ -36,7 +36,5 @@ We are back on our primary stack: bool(true) Having lost all references to the that span stacks objects, it is autoclosed: bool(true) spans(\DDTrace\SpanData) (1) { span_trace_stack_autoclose.php (span_trace_stack_autoclose.php, span_trace_stack_autoclose.php, cli) - _dd.p.dm => -0 - _dd.p.tid => %s (span_trace_stack_autoclose.php, cli) } diff --git a/tests/ext/span_stack/span_trace_swap.phpt b/tests/ext/span_stack/span_trace_swap.phpt index c7378ee633..8d584b80cf 100644 --- a/tests/ext/span_stack/span_trace_swap.phpt +++ b/tests/ext/span_stack/span_trace_swap.phpt @@ -42,9 +42,5 @@ We closed the active stack after all other stacks were closed. No other span is This automatically switches back to the parent stack: bool(true) spans(\DDTrace\SpanData) (2) { span_trace_swap.php (span_trace_swap.php, span_trace_swap.php, cli) - _dd.p.dm => -0 - _dd.p.tid => %s other root (span_trace_swap.php, other root, cli) - _dd.p.dm => -0 - _dd.p.tid => %s } diff --git a/tests/ext/span_stack/start_span_new_trace.phpt b/tests/ext/span_stack/start_span_new_trace.phpt index 8975ff2d70..12eb653bd3 100644 --- a/tests/ext/span_stack/start_span_new_trace.phpt +++ b/tests/ext/span_stack/start_span_new_trace.phpt @@ -61,12 +61,8 @@ After closing the trace root, we swap back to the previously active stack: bool( With the trace root also accordingly updated: bool(true) spans(\DDTrace\SpanData) (2) { start_span_new_trace.php (start_span_new_trace.php, start_span_new_trace.php, cli) - _dd.p.dm => -0 - _dd.p.tid => %s (start_span_new_trace.php, cli) (start_span_new_trace.php, cli) other root (start_span_new_trace.php, other root, cli) - _dd.p.dm => -0 - _dd.p.tid => %s (start_span_new_trace.php, cli) } diff --git a/tests/ext/span_stack/start_span_stack.phpt b/tests/ext/span_stack/start_span_stack.phpt index 39ee073d44..77a08041bb 100644 --- a/tests/ext/span_stack/start_span_stack.phpt +++ b/tests/ext/span_stack/start_span_stack.phpt @@ -55,8 +55,6 @@ Active stack is swapped back when a span below the current span stack is closed: The stack still retains its direct parent as active: bool(true) spans(\DDTrace\SpanData) (1) { start_span_stack.php (start_span_stack.php, start_span_stack.php, cli) - _dd.p.dm => -0 - _dd.p.tid => %s (start_span_stack.php, cli) (start_span_stack.php, cli) } diff --git a/tests/ext/span_stack/start_top_level_span_stack.phpt b/tests/ext/span_stack/start_top_level_span_stack.phpt index 4552b54f28..b52ef5cf99 100644 --- a/tests/ext/span_stack/start_top_level_span_stack.phpt +++ b/tests/ext/span_stack/start_top_level_span_stack.phpt @@ -46,6 +46,4 @@ Now, we are back on the global span stack: bool(true) Impliying we also have no active span: bool(true) spans(\DDTrace\SpanData) (1) { start_top_level_span_stack.php (start_top_level_span_stack.php, start_top_level_span_stack.php, cli) - _dd.p.dm => -0 - _dd.p.tid => %s } diff --git a/tests/ext/span_with_removed_exception.phpt b/tests/ext/span_with_removed_exception.phpt index a4bf52232f..f09f177e2c 100644 --- a/tests/ext/span_with_removed_exception.phpt +++ b/tests/ext/span_with_removed_exception.phpt @@ -54,9 +54,11 @@ try { --EXPECTF-- array(1) { [0]=> - array(10) { + array(12) { ["trace_id"]=> string(%d) "%d" + ["trace_id_high"]=> + string(16) "%s" ["span_id"]=> string(%d) "%d" ["start"]=> @@ -71,37 +73,34 @@ array(1) { string(31) "span_with_removed_exception.php" ["type"]=> string(3) "cli" - ["meta"]=> - array(3) { - ["_dd.p.dm"]=> - string(2) "-0" - ["_dd.p.tid"]=> - string(16) "%s" + ["sampling_priority"]=> + int(1) + ["sampling_mechanism"]=> + int(0) + ["attributes"]=> + array(6) { ["runtime-id"]=> string(36) "%s" - } - ["metrics"]=> - array(6) { + ["process_id"]=> + float(%f) ["_dd.agent_psr"]=> float(1) - ["_sampling_priority_v1"]=> - float(1) ["php.compilation.total_time_ms"]=> float(%f) - ["php.memory.peak_real_usage_bytes"]=> - float(%f) ["php.memory.peak_usage_bytes"]=> float(%f) - ["process_id"]=> + ["php.memory.peak_real_usage_bytes"]=> float(%f) } } } array(1) { [0]=> - array(10) { + array(12) { ["trace_id"]=> string(%d) "%d" + ["trace_id_high"]=> + string(16) "%s" ["span_id"]=> string(%d) "%d" ["start"]=> @@ -116,37 +115,34 @@ array(1) { string(31) "span_with_removed_exception.php" ["type"]=> string(3) "cli" - ["meta"]=> - array(3) { - ["_dd.p.dm"]=> - string(2) "-0" - ["_dd.p.tid"]=> - string(16) "%s" + ["sampling_priority"]=> + int(1) + ["sampling_mechanism"]=> + int(0) + ["attributes"]=> + array(6) { ["runtime-id"]=> string(36) "%s" - } - ["metrics"]=> - array(6) { + ["process_id"]=> + float(%f) ["_dd.agent_psr"]=> float(1) - ["_sampling_priority_v1"]=> - float(1) ["php.compilation.total_time_ms"]=> float(%f) - ["php.memory.peak_real_usage_bytes"]=> - float(%f) ["php.memory.peak_usage_bytes"]=> float(%f) - ["process_id"]=> + ["php.memory.peak_real_usage_bytes"]=> float(%f) } } } array(1) { [0]=> - array(10) { + array(12) { ["trace_id"]=> string(%d) "%d" + ["trace_id_high"]=> + string(16) "%s" ["span_id"]=> string(%d) "%d" ["start"]=> @@ -161,28 +157,23 @@ array(1) { string(31) "span_with_removed_exception.php" ["type"]=> string(3) "cli" - ["meta"]=> - array(3) { - ["_dd.p.dm"]=> - string(2) "-0" - ["_dd.p.tid"]=> - string(16) "%s" + ["sampling_priority"]=> + int(1) + ["sampling_mechanism"]=> + int(0) + ["attributes"]=> + array(6) { ["runtime-id"]=> string(36) "%s" - } - ["metrics"]=> - array(6) { + ["process_id"]=> + float(%f) ["_dd.agent_psr"]=> float(1) - ["_sampling_priority_v1"]=> - float(1) ["php.compilation.total_time_ms"]=> float(%f) - ["php.memory.peak_real_usage_bytes"]=> - float(%f) ["php.memory.peak_usage_bytes"]=> float(%f) - ["process_id"]=> + ["php.memory.peak_real_usage_bytes"]=> float(%f) } } diff --git a/tests/ext/start_span_with_all_properties.phpt b/tests/ext/start_span_with_all_properties.phpt index 4ce1682c97..c264bafd55 100644 --- a/tests/ext/start_span_with_all_properties.phpt +++ b/tests/ext/start_span_with_all_properties.phpt @@ -58,9 +58,11 @@ bool(true) float(2000000000) array(2) { [0]=> - array(10) { + array(12) { ["trace_id"]=> string(%d) "%d" + ["trace_id_high"]=> + string(16) "%s" ["span_id"]=> string(%d) "%d" ["start"]=> @@ -75,35 +77,32 @@ array(2) { string(34) "start_span_with_all_properties.php" ["type"]=> string(3) "cli" - ["meta"]=> - array(3) { - ["_dd.p.dm"]=> - string(2) "-0" - ["_dd.p.tid"]=> - string(16) "%s" + ["sampling_priority"]=> + int(1) + ["sampling_mechanism"]=> + int(0) + ["attributes"]=> + array(6) { ["runtime-id"]=> string(36) "%s" - } - ["metrics"]=> - array(6) { + ["process_id"]=> + float(%f) ["_dd.agent_psr"]=> float(1) - ["_sampling_priority_v1"]=> - float(1) ["php.compilation.total_time_ms"]=> float(%f) - ["php.memory.peak_real_usage_bytes"]=> - float(%f) ["php.memory.peak_usage_bytes"]=> float(%f) - ["process_id"]=> + ["php.memory.peak_real_usage_bytes"]=> float(%f) } } [1]=> - array(10) { + array(12) { ["trace_id"]=> string(%d) "%d" + ["trace_id_high"]=> + string(16) "%s" ["span_id"]=> string(%d) "%d" ["start"]=> @@ -118,34 +117,29 @@ array(2) { string(4) "test" ["type"]=> string(6) "runner" - ["meta"]=> - array(5) { - ["_dd.p.dm"]=> - string(2) "-0" - ["_dd.p.tid"]=> - string(16) "%s" + ["sampling_priority"]=> + int(1) + ["sampling_mechanism"]=> + int(0) + ["attributes"]=> + array(9) { + ["runtime-id"]=> + string(36) "%s" + ["process_id"]=> + float(%f) ["_dd.svc_src"]=> string(1) "m" ["aa"]=> string(2) "bb" - ["runtime-id"]=> - string(36) "%s" - } - ["metrics"]=> - array(7) { - ["_dd.agent_psr"]=> - float(1) - ["_sampling_priority_v1"]=> - float(1) ["cc"]=> float(0) + ["_dd.agent_psr"]=> + float(1) ["php.compilation.total_time_ms"]=> float(%f) - ["php.memory.peak_real_usage_bytes"]=> - float(%f) ["php.memory.peak_usage_bytes"]=> float(%f) - ["process_id"]=> + ["php.memory.peak_real_usage_bytes"]=> float(%f) } } diff --git a/tests/ext/start_span_without_closing.phpt b/tests/ext/start_span_without_closing.phpt index b0d3a73e8a..eca8c28fab 100644 --- a/tests/ext/start_span_without_closing.phpt +++ b/tests/ext/start_span_without_closing.phpt @@ -30,9 +30,11 @@ var_dump(dd_clean_spans()); [ddtrace] [warning] [%d] Found unfinished span while automatically closing spans with name 'my precious span' array(1) { [0]=> - array(10) { + array(12) { ["trace_id"]=> string(%d) "%d" + ["trace_id_high"]=> + string(16) "%s" ["span_id"]=> string(%d) "%d" ["start"]=> @@ -47,28 +49,23 @@ array(1) { string(30) "start_span_without_closing.php" ["type"]=> string(3) "cli" - ["meta"]=> - array(3) { - ["_dd.p.dm"]=> - string(2) "-0" - ["_dd.p.tid"]=> - string(16) "%s" + ["sampling_priority"]=> + int(1) + ["sampling_mechanism"]=> + int(0) + ["attributes"]=> + array(6) { ["runtime-id"]=> string(36) "%s" - } - ["metrics"]=> - array(6) { + ["process_id"]=> + float(%f) ["_dd.agent_psr"]=> float(1) - ["_sampling_priority_v1"]=> - float(1) ["php.compilation.total_time_ms"]=> float(%f) - ["php.memory.peak_real_usage_bytes"]=> - float(%f) ["php.memory.peak_usage_bytes"]=> float(%f) - ["process_id"]=> + ["php.memory.peak_real_usage_bytes"]=> float(%f) } } diff --git a/tests/ext/start_span_without_closing_autofinish.phpt b/tests/ext/start_span_without_closing_autofinish.phpt index a0d14033fe..338eefdb7d 100644 --- a/tests/ext/start_span_without_closing_autofinish.phpt +++ b/tests/ext/start_span_without_closing_autofinish.phpt @@ -28,9 +28,11 @@ var_dump(dd_clean_spans()); [ddtrace] [warning] [%d] Found unfinished span while automatically closing spans with name 'my precious span' array(2) { [0]=> - array(9) { + array(10) { ["trace_id"]=> string(%d) "%d" + ["trace_id_high"]=> + string(16) "%s" ["span_id"]=> string(%d) "%d" ["parent_id"]=> diff --git a/tests/ext/svc_auto_tag_cli.phpt b/tests/ext/svc_auto_tag_cli.phpt index a46ee44b26..bffef820c9 100644 --- a/tests/ext/svc_auto_tag_cli.phpt +++ b/tests/ext/svc_auto_tag_cli.phpt @@ -11,7 +11,7 @@ $span->name = 'op'; \DDTrace\close_span(); $spans = dd_trace_serialize_closed_spans(); -$processTags = $spans[0]['meta']['_dd.tags.process']; +$processTags = $spans[0]['attributes']['_dd.tags.process']; echo "has svc.user: " . (strpos($processTags, 'svc.user') !== false ? 'YES' : 'NO') . "\n"; echo "has svc.auto: " . (strpos($processTags, 'svc.auto:') !== false ? 'YES' : 'NO') . "\n"; diff --git a/tests/ext/svc_auto_tag_otel.phpt b/tests/ext/svc_auto_tag_otel.phpt index 7c05ce2ff5..a5b19cf02f 100644 --- a/tests/ext/svc_auto_tag_otel.phpt +++ b/tests/ext/svc_auto_tag_otel.phpt @@ -12,7 +12,7 @@ $span->name = 'op'; \DDTrace\close_span(); $spans = dd_trace_serialize_closed_spans(); -$processTags = $spans[0]['meta']['_dd.tags.process']; +$processTags = $spans[0]['attributes']['_dd.tags.process']; echo "DD_SERVICE resolved to: " . ini_get('datadog.service') . "\n"; echo "has svc.user:true: " . (strpos($processTags, 'svc.user:true') !== false ? 'YES' : 'NO') . "\n"; diff --git a/tests/ext/svc_runtime_change.phpt b/tests/ext/svc_runtime_change.phpt index 7a06cbf7a0..244049d066 100644 --- a/tests/ext/svc_runtime_change.phpt +++ b/tests/ext/svc_runtime_change.phpt @@ -8,7 +8,7 @@ DD_TRACE_AUTO_FLUSH_ENABLED=0 --EXPECT-- root service: my-app diff --git a/tests/ext/svc_src_inheritance.phpt b/tests/ext/svc_src_inheritance.phpt index 0e339b5a4a..c330b7c7d4 100644 --- a/tests/ext/svc_src_inheritance.phpt +++ b/tests/ext/svc_src_inheritance.phpt @@ -18,8 +18,8 @@ $child->name = 'child'; $byName = []; foreach (dd_trace_serialize_closed_spans() as $s) { $byName[$s['name']] = $s; } -echo "root svc_src: " . ($byName['root']['meta']['_dd.svc_src'] ?? '(unset)') . "\n"; -echo "child svc_src: " . ($byName['child']['meta']['_dd.svc_src'] ?? '(unset)') . "\n"; +echo "root svc_src: " . ($byName['root']['attributes']['_dd.svc_src'] ?? '(unset)') . "\n"; +echo "child svc_src: " . ($byName['child']['attributes']['_dd.svc_src'] ?? '(unset)') . "\n"; ?> --EXPECT-- root svc_src: redis diff --git a/tests/ext/svc_src_manual_override.phpt b/tests/ext/svc_src_manual_override.phpt index 07527277bf..f27a58c91c 100644 --- a/tests/ext/svc_src_manual_override.phpt +++ b/tests/ext/svc_src_manual_override.phpt @@ -18,8 +18,8 @@ $child->service = 'overridden'; $byName = []; foreach (dd_trace_serialize_closed_spans() as $s) { $byName[$s['name']] = $s; } -echo "root svc_src: " . ($byName['root']['meta']['_dd.svc_src'] ?? '(unset)') . "\n"; -echo "child svc_src: " . ($byName['child']['meta']['_dd.svc_src'] ?? '(unset)') . "\n"; +echo "root svc_src: " . ($byName['root']['attributes']['_dd.svc_src'] ?? '(unset)') . "\n"; +echo "child svc_src: " . ($byName['child']['attributes']['_dd.svc_src'] ?? '(unset)') . "\n"; ?> --EXPECT-- root svc_src: m diff --git a/tests/ext/svc_user_tag.phpt b/tests/ext/svc_user_tag.phpt index cd673e65e3..e5641d1101 100644 --- a/tests/ext/svc_user_tag.phpt +++ b/tests/ext/svc_user_tag.phpt @@ -12,7 +12,7 @@ $span->name = 'op'; \DDTrace\close_span(); $spans = dd_trace_serialize_closed_spans(); -$processTags = $spans[0]['meta']['_dd.tags.process']; +$processTags = $spans[0]['attributes']['_dd.tags.process']; echo "has svc.user:true: " . (strpos($processTags, 'svc.user:true') !== false ? 'YES' : 'NO') . "\n"; echo "has svc.auto: : " . (strpos($processTags, 'svc.auto:') !== false ? 'YES' : 'NO') . "\n"; diff --git a/tests/ext/telemetry/broken_pipe.phpt b/tests/ext/telemetry/broken_pipe.phpt index 9bd666c7b4..73ab1163d6 100644 --- a/tests/ext/telemetry/broken_pipe.phpt +++ b/tests/ext/telemetry/broken_pipe.phpt @@ -73,7 +73,7 @@ if ($i == 300) { ?> --EXPECTF-- -[ddtrace] [info] [%d] Flushing trace of size 1 to send-queue for %sbroken_pipe-telemetry.out%A +[ddtrace] [info] [%d] Flushing v1 trace of size 1 to send-queue for %sbroken_pipe-telemetry.out%A [ddtrace] [datadog_sidecar::service::blocking] [%d] The sidecar transport is closed. Reconnecting... This generally indicates a problem with the sidecar, most likely a crash. Check the logs / core dump locations and possibly report a bug. string(11) "app-started" string(25) "broken_pipe-telemetry-app" diff --git a/tests/ext/test_special_attributes.phpt b/tests/ext/test_special_attributes.phpt index 1539e37ff7..2f010af503 100644 --- a/tests/ext/test_special_attributes.phpt +++ b/tests/ext/test_special_attributes.phpt @@ -36,6 +36,8 @@ array(1) { array(11) { ["trace_id"]=> string(%d) "%d" + ["trace_id_high"]=> + string(16) "%s" ["span_id"]=> string(%d) "%d" ["parent_id"]=> @@ -52,17 +54,14 @@ array(1) { string(11) "new.service" ["type"]=> string(8) "new.type" - ["meta"]=> - array(2) { - ["_dd.base_service"]=> - string(27) "test_special_attributes.php" - ["_dd.svc_src"]=> - string(1) "m" - } - ["metrics"]=> - array(1) { + ["attributes"]=> + array(3) { ["_dd1.sr.eausr"]=> float(1) + ["_dd.svc_src"]=> + string(1) "m" + ["_dd.base_service"]=> + string(27) "test_special_attributes.php" } } } diff --git a/tests/ext/test_special_attributes_bis.phpt b/tests/ext/test_special_attributes_bis.phpt index d08ff85c7b..d0486fc96a 100644 --- a/tests/ext/test_special_attributes_bis.phpt +++ b/tests/ext/test_special_attributes_bis.phpt @@ -37,6 +37,8 @@ array(1) { array(11) { ["trace_id"]=> string(%d) "%d" + ["trace_id_high"]=> + string(16) "%s" ["span_id"]=> string(%d) "%d" ["parent_id"]=> @@ -53,17 +55,14 @@ array(1) { string(14) "mapped.service" ["type"]=> string(8) "new.type" - ["meta"]=> - array(2) { - ["_dd.base_service"]=> - string(31) "test_special_attributes_bis.php" - ["_dd.svc_src"]=> - string(1) "m" - } - ["metrics"]=> - array(1) { + ["attributes"]=> + array(3) { ["_dd1.sr.eausr"]=> float(1) + ["_dd.svc_src"]=> + string(1) "m" + ["_dd.base_service"]=> + string(31) "test_special_attributes_bis.php" } } } diff --git a/tests/ext/traced_attribute.phpt b/tests/ext/traced_attribute.phpt index cbc2dfafd5..99e6e1b45d 100644 --- a/tests/ext/traced_attribute.phpt +++ b/tests/ext/traced_attribute.phpt @@ -59,16 +59,17 @@ dd_dump_spans(); --EXPECTF-- spans(\DDTrace\SpanData) (3) { bar (traced_attribute.php, bar, cli) + _dd.code_origin.type => entry _dd.code_origin.frames.0.file => %s _dd.code_origin.frames.0.line => 22 _dd.code_origin.frames.0.method => bar _dd.code_origin.frames.1.file => %s _dd.code_origin.frames.1.line => 40 - _dd.code_origin.type => entry - _dd.p.dm => -0 - _dd.p.tid => %s simplename (test, rsrc, typeee) - _dd.base_service => traced_attribute.php + _dd.svc_src => m + a => b + data => dog + _dd.code_origin.type => exit _dd.code_origin.frames.0.file => %s _dd.code_origin.frames.0.line => 7 _dd.code_origin.frames.0.method => simple @@ -78,28 +79,21 @@ spans(\DDTrace\SpanData) (3) { _dd.code_origin.frames.1.method => bar _dd.code_origin.frames.2.file => %s _dd.code_origin.frames.2.line => 40 - _dd.code_origin.type => exit - _dd.svc_src => m - a => b - data => dog + _dd.base_service => traced_attribute.php recursion (traced_attribute.php, recursion, cli) + _dd.code_origin.type => entry _dd.code_origin.frames.0.file => %s _dd.code_origin.frames.0.line => 27 _dd.code_origin.frames.0.method => recursion _dd.code_origin.frames.1.file => %s _dd.code_origin.frames.1.line => 45 - _dd.code_origin.type => entry - _dd.p.dm => -0 - _dd.p.tid => %s recursion (traced_attribute.php, recursion, cli) recursion (traced_attribute.php, recursion, cli) noRecursion (traced_attribute.php, noRecursion, cli) + _dd.code_origin.type => entry _dd.code_origin.frames.0.file => %s _dd.code_origin.frames.0.line => 34 _dd.code_origin.frames.0.method => noRecursion _dd.code_origin.frames.1.file => %s _dd.code_origin.frames.1.line => 46 - _dd.code_origin.type => entry - _dd.p.dm => -0 - _dd.p.tid => %s } diff --git a/tests/ext/traced_attribute_delayed.phpt b/tests/ext/traced_attribute_delayed.phpt index d14f68bdd0..fb704e74ec 100644 --- a/tests/ext/traced_attribute_delayed.phpt +++ b/tests/ext/traced_attribute_delayed.phpt @@ -51,9 +51,5 @@ int(1) int(1) spans(\DDTrace\SpanData) (2) { simpleclass (traced_attribute_delayed.php, simpleclass, cli) - _dd.p.dm => -0 - _dd.p.tid => %s simplefunc (traced_attribute_delayed.php, simplefunc, cli) - _dd.p.dm => -0 - _dd.p.tid => %s } diff --git a/tests/ext/traced_attribute_tags_recursive_and_empty.phpt b/tests/ext/traced_attribute_tags_recursive_and_empty.phpt new file mode 100644 index 0000000000..276de719d5 --- /dev/null +++ b/tests/ext/traced_attribute_tags_recursive_and_empty.phpt @@ -0,0 +1,32 @@ +--TEST-- +#[DDTrace\Trace] tags: a self-referencing object tag becomes "" at the cycle, and empty tags are accepted +--SKIPIF-- + +--ENV-- +DD_TRACE_GENERATE_ROOT_SPAN=0 +DD_TRACE_AUTO_FLUSH_ENABLED=0 +DD_CODE_ORIGIN_FOR_SPANS_ENABLED=0 +--FILE-- +me = $this; } +} + +#[DDTrace\Trace(name: "recursive", tags: ["s" => new SelfRef])] +function recursive() {} + +#[DDTrace\Trace(name: "empty", tags: [])] +function emptyTags() {} + +recursive(); +emptyTags(); + +foreach (dd_trace_serialize_closed_spans() as $span) { + echo $span['name'], ": ", json_encode(isset($span['attributes']['s']) ? $span['attributes']['s'] : null), "\n"; +} +?> +--EXPECT-- +empty: null +recursive: {"me":"","v":"1"} diff --git a/tests/ext/ust.phpt b/tests/ext/ust.phpt index 08e02f7387..7f36e2485b 100644 --- a/tests/ext/ust.phpt +++ b/tests/ext/ust.phpt @@ -30,6 +30,8 @@ array(2) { array(%d) { ["trace_id"]=> string(%d) "%s" + ["trace_id_high"]=> + string(16) "%s" ["span_id"]=> string(%d) "%s" ["start"]=> @@ -44,32 +46,27 @@ array(2) { string(12) "version_test" ["type"]=> string(3) "cli" - ["meta"]=> + ["env"]=> + string(8) "env_test" + ["version"]=> + string(5) "5.2.0" + ["sampling_priority"]=> + int(1) + ["sampling_mechanism"]=> + int(0) + ["attributes"]=> array(%d) { - ["_dd.p.dm"]=> - string(2) "-0" - ["_dd.p.tid"]=> - string(16) "%s" - ["env"]=> - string(8) "env_test" ["runtime-id"]=> string(36) "%s" - ["version"]=> - string(5) "5.2.0" - } - ["metrics"]=> - array(%d) { + ["process_id"]=> + float(%f) ["_dd.agent_psr"]=> float(1) - ["_sampling_priority_v1"]=> - float(1) ["php.compilation.total_time_ms"]=> float(%f) - ["php.memory.peak_real_usage_bytes"]=> - float(%f) ["php.memory.peak_usage_bytes"]=> float(%f) - ["process_id"]=> + ["php.memory.peak_real_usage_bytes"]=> float(%f) } } @@ -77,6 +74,8 @@ array(2) { array(%d) { ["trace_id"]=> string(%d) "%s" + ["trace_id_high"]=> + string(16) "%s" ["span_id"]=> string(%d) "%s" ["start"]=> @@ -91,27 +90,22 @@ array(2) { string(13) "no dd_service" ["type"]=> string(3) "cli" - ["meta"]=> + ["env"]=> + string(8) "env_test" + ["sampling_priority"]=> + int(1) + ["sampling_mechanism"]=> + int(0) + ["attributes"]=> array(%d) { - ["_dd.p.dm"]=> - string(2) "-0" - ["_dd.p.tid"]=> - string(16) "%s" - ["_dd.svc_src"]=> - string(1) "m" - ["env"]=> - string(8) "env_test" ["runtime-id"]=> string(36) "%s" - } - ["metrics"]=> - array(%d) { - ["_dd.agent_psr"]=> - float(1) - ["_sampling_priority_v1"]=> - float(1) ["process_id"]=> float(%f) + ["_dd.svc_src"]=> + string(1) "m" + ["_dd.agent_psr"]=> + float(1) } } } diff --git a/tests/ext/ust_precedence_over_ddtags.phpt b/tests/ext/ust_precedence_over_ddtags.phpt index 116999116f..f456a6060e 100644 --- a/tests/ext/ust_precedence_over_ddtags.phpt +++ b/tests/ext/ust_precedence_over_ddtags.phpt @@ -27,14 +27,14 @@ if (count($spans) >= 2) { 'span1' => [ 'name' => $spans[0]['name'], 'service' => $spans[0]['service'], - 'version' => $spans[0]['meta']['version'], - 'env' => $spans[0]['meta']['env'] + 'version' => $spans[0]['version'], + 'env' => $spans[0]['env'] ], 'span2' => [ 'name' => $spans[1]['name'], 'service' => $spans[1]['service'], - 'version' => $spans[1]['meta']['version'], - 'env' => $spans[1]['meta']['env'] + 'version' => $spans[1]['version'], + 'env' => $spans[1]['env'] ] ]); } diff --git a/tests/ext/ust_via_ddtags.phpt b/tests/ext/ust_via_ddtags.phpt index 4502567e32..4436c1efff 100644 --- a/tests/ext/ust_via_ddtags.phpt +++ b/tests/ext/ust_via_ddtags.phpt @@ -27,14 +27,14 @@ if (count($spans) >= 2) { 'span1' => [ 'name' => $spans[0]['name'], 'service' => $spans[0]['service'], - 'version' => $spans[0]['meta']['version'], - 'env' => $spans[0]['meta']['env'] + 'version' => $spans[0]['version'], + 'env' => $spans[0]['env'] ], 'span2' => [ 'name' => $spans[1]['name'], 'service' => $spans[1]['service'], - 'version' => $spans[1]['meta']['version'], - 'env' => $spans[1]['meta']['env'] + 'version' => $spans[1]['version'], + 'env' => $spans[1]['env'] ] ]); } diff --git a/tests/ext/wrong-parameter-errors/dd_trace_send_traces_via_thread.phpt b/tests/ext/wrong-parameter-errors/dd_trace_send_traces_via_thread.phpt deleted file mode 100644 index ebd5f4b013..0000000000 --- a/tests/ext/wrong-parameter-errors/dd_trace_send_traces_via_thread.phpt +++ /dev/null @@ -1,59 +0,0 @@ ---TEST-- -dd_trace_send_traces_via_thread is passed wrong parameters ---FILE-- - ---EXPECT-- -OK1 -OK2 -OK3 -OK4 -OK5 diff --git a/tests/opcache/span_attributes_immutable_arrays.phpt b/tests/opcache/span_attributes_immutable_arrays.phpt new file mode 100644 index 0000000000..28143ffff0 --- /dev/null +++ b/tests/opcache/span_attributes_immutable_arrays.phpt @@ -0,0 +1,45 @@ +--TEST-- +Immutable (opcache SHM) arrays as span meta/metrics and link/event attributes serialize without being written to +--SKIPIF-- + +--ENV-- +DD_TRACE_DEBUG_PRNG_SEED=42 +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.protect_memory=1 +opcache.file_update_protection=0 +--FILE-- +name = 'foo'; +$span->meta['flat'] = ['a', 'b']; +$span->meta['nested'] = ['k' => ['x' => [1, 2]], 'v' => 'w']; +$span->metrics['m'] = [1, 2.5]; + +$link = new SpanLink(); +$link->traceId = "42"; +$link->spanId = "6"; +$link->attributes = ['list' => [1, 2], 'map' => ['a' => ['b' => true]]]; +$span->links[] = $link; +$span->events[] = new SpanEvent('evt', ['list' => ['x', 'y'], 'map' => ['n' => [3]]], 1); +\DDTrace\close_span(); + +$spans = dd_trace_serialize_closed_spans(); +echo json_encode([ + $spans[0]['attributes']['flat'], + $spans[0]['attributes']['nested'], + $spans[0]['attributes']['m'], + $spans[0]['span_links'][0]['attributes'], + $spans[0]['span_events'][0]['attributes'], +]), "\n"; +var_dump(opcache_get_status(false)['opcache_enabled']); + +?> +--EXPECT-- +[["a","b"],{"k":{"x":["1","2"]},"v":"w"},[1,2.5],{"list":[1,2],"map":{"a":{"b":true}}},{"list":["x","y"],"map":{"n":[3]}}] +bool(true) diff --git a/tests/snapshots/integrations.code_igniter.v3_1.no_ci_controller_test.test_scenario_health_check.json b/tests/snapshots/integrations.code_igniter.v3_1.no_ci_controller_test.test_scenario_health_check.json index 94f4baa203..4b434afcda 100644 --- a/tests/snapshots/integrations.code_igniter.v3_1.no_ci_controller_test.test_scenario_health_check.json +++ b/tests/snapshots/integrations.code_igniter.v3_1.no_ci_controller_test.test_scenario_health_check.json @@ -19,6 +19,7 @@ "span.kind": "server" }, "metrics": { + "_dd.top_level": 1.0, "_sampling_priority_v1": 1.0 } }, diff --git a/tests/snapshots/tests.integrations.cli.symfony.latest.common_scenarios_test.test_silenced_spans_are_dropped.json b/tests/snapshots/tests.integrations.cli.symfony.latest.common_scenarios_test.test_silenced_spans_are_dropped.json index b70090a34d..41edfa5f22 100644 --- a/tests/snapshots/tests.integrations.cli.symfony.latest.common_scenarios_test.test_silenced_spans_are_dropped.json +++ b/tests/snapshots/tests.integrations.cli.symfony.latest.common_scenarios_test.test_silenced_spans_are_dropped.json @@ -14,6 +14,7 @@ }, "metrics": { "_dd.agent_psr": 1, + "_dd.top_level": 1, "_sampling_priority_v1": 1 } }, @@ -48,6 +49,9 @@ "_dd.code_origin.frames.6.line": "11", "_dd.code_origin.type": "exit", "component": "symfony" + }, + "metrics": { + "_dd.top_level": 1 } }, { @@ -61,6 +65,9 @@ "meta": { "_dd.base_service": "console", "component": "symfony" + }, + "metrics": { + "_dd.top_level": 1 } }, { @@ -75,6 +82,9 @@ "_dd.base_service": "console", "component": "symfony", "symfony.console.command.class": "App\\Command\\SttyCommand" + }, + "metrics": { + "_dd.top_level": 1 } }, { @@ -88,5 +98,8 @@ "meta": { "_dd.base_service": "console", "component": "symfony" + }, + "metrics": { + "_dd.top_level": 1 } }]] diff --git a/tests/snapshots/tests.integrations.cli.symfony.v4_4.common_scenarios_test.test_silenced_spans_are_dropped.json b/tests/snapshots/tests.integrations.cli.symfony.v4_4.common_scenarios_test.test_silenced_spans_are_dropped.json index 33cae852b2..5158782ea4 100644 --- a/tests/snapshots/tests.integrations.cli.symfony.v4_4.common_scenarios_test.test_silenced_spans_are_dropped.json +++ b/tests/snapshots/tests.integrations.cli.symfony.v4_4.common_scenarios_test.test_silenced_spans_are_dropped.json @@ -14,6 +14,7 @@ }, "metrics": { "_dd.agent_psr": 1, + "_dd.top_level": 1, "_sampling_priority_v1": 1 } }, @@ -48,6 +49,9 @@ "_dd.code_origin.frames.4.line": "42", "_dd.code_origin.type": "exit", "component": "symfony" + }, + "metrics": { + "_dd.top_level": 1 } }, { @@ -61,6 +65,9 @@ "meta": { "_dd.base_service": "console", "component": "symfony" + }, + "metrics": { + "_dd.top_level": 1 } }, { @@ -75,6 +82,9 @@ "_dd.base_service": "console", "component": "symfony", "symfony.console.command.class": "App\\Command\\SttyCommand" + }, + "metrics": { + "_dd.top_level": 1 } }, { @@ -88,5 +98,8 @@ "meta": { "_dd.base_service": "console", "component": "symfony" + }, + "metrics": { + "_dd.top_level": 1 } }]] diff --git a/tests/snapshots/tests.integrations.cli.symfony.v5_2.common_scenarios_test.test_silenced_spans_are_dropped.json b/tests/snapshots/tests.integrations.cli.symfony.v5_2.common_scenarios_test.test_silenced_spans_are_dropped.json index 929c34b97a..41d5057443 100644 --- a/tests/snapshots/tests.integrations.cli.symfony.v5_2.common_scenarios_test.test_silenced_spans_are_dropped.json +++ b/tests/snapshots/tests.integrations.cli.symfony.v5_2.common_scenarios_test.test_silenced_spans_are_dropped.json @@ -14,6 +14,7 @@ }, "metrics": { "_dd.agent_psr": 1, + "_dd.top_level": 1, "_sampling_priority_v1": 1 } }, @@ -48,6 +49,9 @@ "_dd.code_origin.frames.4.line": "43", "_dd.code_origin.type": "exit", "component": "symfony" + }, + "metrics": { + "_dd.top_level": 1 } }, { @@ -61,6 +65,9 @@ "meta": { "_dd.base_service": "console", "component": "symfony" + }, + "metrics": { + "_dd.top_level": 1 } }, { @@ -75,6 +82,9 @@ "_dd.base_service": "console", "component": "symfony", "symfony.console.command.class": "App\\Command\\SttyCommand" + }, + "metrics": { + "_dd.top_level": 1 } }, { @@ -88,5 +98,8 @@ "meta": { "_dd.base_service": "console", "component": "symfony" + }, + "metrics": { + "_dd.top_level": 1 } }]] diff --git a/tests/snapshots/tests.integrations.cli.symfony.v6_2.common_scenarios_test.test_silenced_spans_are_dropped.json b/tests/snapshots/tests.integrations.cli.symfony.v6_2.common_scenarios_test.test_silenced_spans_are_dropped.json index 2c72d326a0..09042e94ee 100644 --- a/tests/snapshots/tests.integrations.cli.symfony.v6_2.common_scenarios_test.test_silenced_spans_are_dropped.json +++ b/tests/snapshots/tests.integrations.cli.symfony.v6_2.common_scenarios_test.test_silenced_spans_are_dropped.json @@ -14,6 +14,7 @@ }, "metrics": { "_dd.agent_psr": 1, + "_dd.top_level": 1, "_sampling_priority_v1": 1 } }, @@ -48,6 +49,9 @@ "_dd.code_origin.frames.4.line": "43", "_dd.code_origin.type": "exit", "component": "symfony" + }, + "metrics": { + "_dd.top_level": 1 } }, { @@ -77,6 +81,9 @@ "meta": { "_dd.base_service": "console", "component": "symfony" + }, + "metrics": { + "_dd.top_level": 1 } }, { @@ -91,6 +98,9 @@ "_dd.base_service": "console", "component": "symfony", "symfony.console.command.class": "App\\Command\\SttyCommand" + }, + "metrics": { + "_dd.top_level": 1 } }, { @@ -104,5 +114,8 @@ "meta": { "_dd.base_service": "console", "component": "symfony" + }, + "metrics": { + "_dd.top_level": 1 } }]] diff --git a/tests/snapshots/tests.integrations.cli.symfony.v7_3.common_scenarios_test.test_silenced_spans_are_dropped.json b/tests/snapshots/tests.integrations.cli.symfony.v7_3.common_scenarios_test.test_silenced_spans_are_dropped.json index ab515a7769..e218355e4a 100644 --- a/tests/snapshots/tests.integrations.cli.symfony.v7_3.common_scenarios_test.test_silenced_spans_are_dropped.json +++ b/tests/snapshots/tests.integrations.cli.symfony.v7_3.common_scenarios_test.test_silenced_spans_are_dropped.json @@ -14,6 +14,7 @@ }, "metrics": { "_dd.agent_psr": 1, + "_dd.top_level": 1, "_sampling_priority_v1": 1 } }, @@ -48,6 +49,9 @@ "_dd.code_origin.frames.6.line": "11", "_dd.code_origin.type": "exit", "component": "symfony" + }, + "metrics": { + "_dd.top_level": 1 } }, { @@ -77,6 +81,9 @@ "meta": { "_dd.base_service": "console", "component": "symfony" + }, + "metrics": { + "_dd.top_level": 1 } }, { @@ -91,6 +98,9 @@ "_dd.base_service": "console", "component": "symfony", "symfony.console.command.class": "App\\Command\\SttyCommand" + }, + "metrics": { + "_dd.top_level": 1 } }, { @@ -104,5 +114,8 @@ "meta": { "_dd.base_service": "console", "component": "symfony" + }, + "metrics": { + "_dd.top_level": 1 } }]] diff --git a/tests/snapshots/tests.integrations.code_igniter.v3_1.common_scenarios_test.test_scenario_get_parameterized.json b/tests/snapshots/tests.integrations.code_igniter.v3_1.common_scenarios_test.test_scenario_get_parameterized.json index 1da3301fe8..7f6f2288bf 100644 --- a/tests/snapshots/tests.integrations.code_igniter.v3_1.common_scenarios_test.test_scenario_get_parameterized.json +++ b/tests/snapshots/tests.integrations.code_igniter.v3_1.common_scenarios_test.test_scenario_get_parameterized.json @@ -20,6 +20,7 @@ "span.kind": "server" }, "metrics": { + "_dd.top_level": 1.0, "_sampling_priority_v1": 1.0 } }, diff --git a/tests/snapshots/tests.integrations.code_igniter.v3_1.common_scenarios_test.test_scenario_get_return_string.json b/tests/snapshots/tests.integrations.code_igniter.v3_1.common_scenarios_test.test_scenario_get_return_string.json index 6f87498651..039730f2ec 100644 --- a/tests/snapshots/tests.integrations.code_igniter.v3_1.common_scenarios_test.test_scenario_get_return_string.json +++ b/tests/snapshots/tests.integrations.code_igniter.v3_1.common_scenarios_test.test_scenario_get_return_string.json @@ -20,6 +20,7 @@ "span.kind": "server" }, "metrics": { + "_dd.top_level": 1.0, "_sampling_priority_v1": 1.0 } }, diff --git a/tests/snapshots/tests.integrations.code_igniter.v3_1.common_scenarios_test.test_scenario_get_to_missing_route.json b/tests/snapshots/tests.integrations.code_igniter.v3_1.common_scenarios_test.test_scenario_get_to_missing_route.json index 5170c9dbe3..b688f9898e 100644 --- a/tests/snapshots/tests.integrations.code_igniter.v3_1.common_scenarios_test.test_scenario_get_to_missing_route.json +++ b/tests/snapshots/tests.integrations.code_igniter.v3_1.common_scenarios_test.test_scenario_get_to_missing_route.json @@ -19,6 +19,7 @@ "span.kind": "server" }, "metrics": { + "_dd.top_level": 1.0, "_sampling_priority_v1": 1.0 } }]] diff --git a/tests/snapshots/tests.integrations.code_igniter.v3_1.common_scenarios_test.test_scenario_get_to_missing_route_cgi.json b/tests/snapshots/tests.integrations.code_igniter.v3_1.common_scenarios_test.test_scenario_get_to_missing_route_cgi.json index c50a1bd1bf..5dd7bf7246 100644 --- a/tests/snapshots/tests.integrations.code_igniter.v3_1.common_scenarios_test.test_scenario_get_to_missing_route_cgi.json +++ b/tests/snapshots/tests.integrations.code_igniter.v3_1.common_scenarios_test.test_scenario_get_to_missing_route_cgi.json @@ -19,6 +19,7 @@ "span.kind": "server" }, "metrics": { + "_dd.top_level": 1.0, "_sampling_priority_v1": 1.0 } }]] diff --git a/tests/snapshots/tests.integrations.code_igniter.v3_1.common_scenarios_test.test_scenario_get_with_exception.json b/tests/snapshots/tests.integrations.code_igniter.v3_1.common_scenarios_test.test_scenario_get_with_exception.json index c89ca53ba1..98b8df7f91 100644 --- a/tests/snapshots/tests.integrations.code_igniter.v3_1.common_scenarios_test.test_scenario_get_with_exception.json +++ b/tests/snapshots/tests.integrations.code_igniter.v3_1.common_scenarios_test.test_scenario_get_with_exception.json @@ -24,6 +24,7 @@ "span.kind": "server" }, "metrics": { + "_dd.top_level": 1.0, "_sampling_priority_v1": 1.0 } }, diff --git a/tests/snapshots/tests.integrations.code_igniter.v3_1.common_scenarios_test.test_scenario_get_with_exception_cgi.json b/tests/snapshots/tests.integrations.code_igniter.v3_1.common_scenarios_test.test_scenario_get_with_exception_cgi.json index 49e57af64c..449cde8c08 100644 --- a/tests/snapshots/tests.integrations.code_igniter.v3_1.common_scenarios_test.test_scenario_get_with_exception_cgi.json +++ b/tests/snapshots/tests.integrations.code_igniter.v3_1.common_scenarios_test.test_scenario_get_with_exception_cgi.json @@ -24,6 +24,7 @@ "span.kind": "server" }, "metrics": { + "_dd.top_level": 1.0, "_sampling_priority_v1": 1.0 } }, diff --git a/tests/snapshots/tests.integrations.code_igniter.v3_1.common_scenarios_test.test_scenario_get_with_view.json b/tests/snapshots/tests.integrations.code_igniter.v3_1.common_scenarios_test.test_scenario_get_with_view.json index f1c4002d99..211d522018 100644 --- a/tests/snapshots/tests.integrations.code_igniter.v3_1.common_scenarios_test.test_scenario_get_with_view.json +++ b/tests/snapshots/tests.integrations.code_igniter.v3_1.common_scenarios_test.test_scenario_get_with_view.json @@ -20,6 +20,7 @@ "span.kind": "server" }, "metrics": { + "_dd.top_level": 1.0, "_sampling_priority_v1": 1.0 } }, diff --git a/tests/snapshots/tests.integrations.code_igniter.v3_1.exit_test.test_scenario_exit.json b/tests/snapshots/tests.integrations.code_igniter.v3_1.exit_test.test_scenario_exit.json index fb342972d7..641f60e4f1 100644 --- a/tests/snapshots/tests.integrations.code_igniter.v3_1.exit_test.test_scenario_exit.json +++ b/tests/snapshots/tests.integrations.code_igniter.v3_1.exit_test.test_scenario_exit.json @@ -20,6 +20,7 @@ "span.kind": "server" }, "metrics": { + "_dd.top_level": 1.0, "_sampling_priority_v1": 1.0 } }, diff --git a/tests/snapshots/tests.integrations.drupal.v10_1.common_scenarios_test.test_scenario_get_to_missing_route.json b/tests/snapshots/tests.integrations.drupal.v10_1.common_scenarios_test.test_scenario_get_to_missing_route.json index 18190be1c7..592ca28d22 100644 --- a/tests/snapshots/tests.integrations.drupal.v10_1.common_scenarios_test.test_scenario_get_to_missing_route.json +++ b/tests/snapshots/tests.integrations.drupal.v10_1.common_scenarios_test.test_scenario_get_to_missing_route.json @@ -18,6 +18,7 @@ "symfony.route.action": "Drupal\\system\\Controller\\Http4xxController@on404" }, "metrics": { + "_dd.top_level": 1.0, "_sampling_priority_v1": 1.0 } }, diff --git a/tests/snapshots/tests.integrations.drupal.v10_1.common_scenarios_test.test_scenario_get_with_exception.json b/tests/snapshots/tests.integrations.drupal.v10_1.common_scenarios_test.test_scenario_get_with_exception.json index 4981d83b9b..61df7c2963 100644 --- a/tests/snapshots/tests.integrations.drupal.v10_1.common_scenarios_test.test_scenario_get_with_exception.json +++ b/tests/snapshots/tests.integrations.drupal.v10_1.common_scenarios_test.test_scenario_get_with_exception.json @@ -23,6 +23,7 @@ "symfony.route.name": "error" }, "metrics": { + "_dd.top_level": 1.0, "_sampling_priority_v1": 1.0 } }, diff --git a/tests/snapshots/tests.integrations.drupal.v10_1.common_scenarios_test.test_scenario_get_with_view.json b/tests/snapshots/tests.integrations.drupal.v10_1.common_scenarios_test.test_scenario_get_with_view.json index 16afc5508e..512452ba57 100644 --- a/tests/snapshots/tests.integrations.drupal.v10_1.common_scenarios_test.test_scenario_get_with_view.json +++ b/tests/snapshots/tests.integrations.drupal.v10_1.common_scenarios_test.test_scenario_get_with_view.json @@ -19,6 +19,7 @@ "symfony.route.name": "simple_view" }, "metrics": { + "_dd.top_level": 1.0, "_sampling_priority_v1": 1.0 } }, diff --git a/tests/snapshots/tests.integrations.drupal.v8_9.common_scenarios_test.test_scenario_get_to_missing_route.json b/tests/snapshots/tests.integrations.drupal.v8_9.common_scenarios_test.test_scenario_get_to_missing_route.json index f96ed6fb99..9301f9d053 100644 --- a/tests/snapshots/tests.integrations.drupal.v8_9.common_scenarios_test.test_scenario_get_to_missing_route.json +++ b/tests/snapshots/tests.integrations.drupal.v8_9.common_scenarios_test.test_scenario_get_to_missing_route.json @@ -18,6 +18,7 @@ "symfony.route.action": "Drupal\\system\\Controller\\Http4xxController@on404" }, "metrics": { + "_dd.top_level": 1.0, "_sampling_priority_v1": 1.0 } }, diff --git a/tests/snapshots/tests.integrations.drupal.v8_9.common_scenarios_test.test_scenario_get_with_exception.json b/tests/snapshots/tests.integrations.drupal.v8_9.common_scenarios_test.test_scenario_get_with_exception.json index 18490266bd..90f6bcf189 100644 --- a/tests/snapshots/tests.integrations.drupal.v8_9.common_scenarios_test.test_scenario_get_with_exception.json +++ b/tests/snapshots/tests.integrations.drupal.v8_9.common_scenarios_test.test_scenario_get_with_exception.json @@ -23,6 +23,7 @@ "symfony.route.name": "error" }, "metrics": { + "_dd.top_level": 1.0, "_sampling_priority_v1": 1.0 } }, diff --git a/tests/snapshots/tests.integrations.drupal.v8_9.common_scenarios_test.test_scenario_get_with_view.json b/tests/snapshots/tests.integrations.drupal.v8_9.common_scenarios_test.test_scenario_get_with_view.json index 42eaba32f3..0f51aa908d 100644 --- a/tests/snapshots/tests.integrations.drupal.v8_9.common_scenarios_test.test_scenario_get_with_view.json +++ b/tests/snapshots/tests.integrations.drupal.v8_9.common_scenarios_test.test_scenario_get_with_view.json @@ -19,6 +19,7 @@ "symfony.route.name": "simple_view" }, "metrics": { + "_dd.top_level": 1.0, "_sampling_priority_v1": 1.0 } }, diff --git a/tests/snapshots/tests.integrations.drupal.v9_5.common_scenarios_test.test_scenario_get_to_missing_route.json b/tests/snapshots/tests.integrations.drupal.v9_5.common_scenarios_test.test_scenario_get_to_missing_route.json index 82c03046b6..9983b39cf3 100644 --- a/tests/snapshots/tests.integrations.drupal.v9_5.common_scenarios_test.test_scenario_get_to_missing_route.json +++ b/tests/snapshots/tests.integrations.drupal.v9_5.common_scenarios_test.test_scenario_get_to_missing_route.json @@ -18,6 +18,7 @@ "symfony.route.action": "Drupal\\system\\Controller\\Http4xxController@on404" }, "metrics": { + "_dd.top_level": 1.0, "_sampling_priority_v1": 1.0 } }, diff --git a/tests/snapshots/tests.integrations.drupal.v9_5.common_scenarios_test.test_scenario_get_with_exception.json b/tests/snapshots/tests.integrations.drupal.v9_5.common_scenarios_test.test_scenario_get_with_exception.json index a7b5ee58be..b7286a56a1 100644 --- a/tests/snapshots/tests.integrations.drupal.v9_5.common_scenarios_test.test_scenario_get_with_exception.json +++ b/tests/snapshots/tests.integrations.drupal.v9_5.common_scenarios_test.test_scenario_get_with_exception.json @@ -23,6 +23,7 @@ "symfony.route.name": "error" }, "metrics": { + "_dd.top_level": 1.0, "_sampling_priority_v1": 1.0 } }, diff --git a/tests/snapshots/tests.integrations.drupal.v9_5.common_scenarios_test.test_scenario_get_with_view.json b/tests/snapshots/tests.integrations.drupal.v9_5.common_scenarios_test.test_scenario_get_with_view.json index fbcc57a8a7..a780052f9d 100644 --- a/tests/snapshots/tests.integrations.drupal.v9_5.common_scenarios_test.test_scenario_get_with_view.json +++ b/tests/snapshots/tests.integrations.drupal.v9_5.common_scenarios_test.test_scenario_get_with_view.json @@ -19,6 +19,7 @@ "symfony.route.name": "simple_view" }, "metrics": { + "_dd.top_level": 1.0, "_sampling_priority_v1": 1.0 } }, diff --git a/tests/snapshots/tests.integrations.kafka_test.test_distributed_tracing_high_level_producer.json b/tests/snapshots/tests.integrations.kafka_test.test_distributed_tracing_high_level_producer.json index b56f8a0bdb..abde238ee6 100644 --- a/tests/snapshots/tests.integrations.kafka_test.test_distributed_tracing_high_level_producer.json +++ b/tests/snapshots/tests.integrations.kafka_test.test_distributed_tracing_high_level_producer.json @@ -22,6 +22,7 @@ }, "metrics": { "_dd.agent_psr": 1, + "_dd.top_level": 1, "_sampling_priority_v1": 1, "messaging.kafka.partition": -1, "messaging.message_payload_size_bytes": 11 diff --git a/tests/snapshots/tests.integrations.kafka_test.test_span_links_high_level_consumer.json b/tests/snapshots/tests.integrations.kafka_test.test_span_links_high_level_consumer.json index 54a5a7197c..643301750a 100644 --- a/tests/snapshots/tests.integrations.kafka_test.test_span_links_high_level_consumer.json +++ b/tests/snapshots/tests.integrations.kafka_test.test_span_links_high_level_consumer.json @@ -23,6 +23,7 @@ }, "metrics": { "_dd.agent_psr": 1, + "_dd.top_level": 1, "_sampling_priority_v1": 1, "messaging.kafka.message_offset": 18, "messaging.kafka.partition": 0, @@ -54,6 +55,7 @@ }, "metrics": { "_dd.agent_psr": 1, + "_dd.top_level": 1, "_sampling_priority_v1": 1, "messaging.kafka.message_offset": 19, "messaging.kafka.partition": 0, diff --git a/tests/snapshots/tests.integrations.kafka_test.test_span_links_high_level_producer.json b/tests/snapshots/tests.integrations.kafka_test.test_span_links_high_level_producer.json index 7fe2dab3e1..7859419802 100644 --- a/tests/snapshots/tests.integrations.kafka_test.test_span_links_high_level_producer.json +++ b/tests/snapshots/tests.integrations.kafka_test.test_span_links_high_level_producer.json @@ -22,6 +22,7 @@ }, "metrics": { "_dd.agent_psr": 1, + "_dd.top_level": 1, "_sampling_priority_v1": 1, "messaging.kafka.partition": -1, "messaging.message_payload_size_bytes": 11 diff --git a/tests/snapshots/tests.integrations.kafka_test.test_span_links_low_level_consumer.json b/tests/snapshots/tests.integrations.kafka_test.test_span_links_low_level_consumer.json index 904d2796f9..55529a131c 100644 --- a/tests/snapshots/tests.integrations.kafka_test.test_span_links_low_level_consumer.json +++ b/tests/snapshots/tests.integrations.kafka_test.test_span_links_low_level_consumer.json @@ -23,6 +23,7 @@ }, "metrics": { "_dd.agent_psr": 1, + "_dd.top_level": 1, "_sampling_priority_v1": 1, "messaging.kafka.message_offset": 10, "messaging.kafka.partition": 0, @@ -54,6 +55,7 @@ }, "metrics": { "_dd.agent_psr": 1, + "_dd.top_level": 1, "_sampling_priority_v1": 1, "messaging.kafka.message_offset": 11, "messaging.kafka.partition": 0, @@ -83,6 +85,7 @@ }, "metrics": { "_dd.agent_psr": 1, + "_dd.top_level": 1, "_sampling_priority_v1": 1 } }]] diff --git a/tests/snapshots/tests.integrations.kafka_test.test_span_links_low_level_producer.json b/tests/snapshots/tests.integrations.kafka_test.test_span_links_low_level_producer.json index c85c7b7666..0632de3518 100644 --- a/tests/snapshots/tests.integrations.kafka_test.test_span_links_low_level_producer.json +++ b/tests/snapshots/tests.integrations.kafka_test.test_span_links_low_level_producer.json @@ -22,6 +22,7 @@ }, "metrics": { "_dd.agent_psr": 1, + "_dd.top_level": 1, "_sampling_priority_v1": 1, "messaging.kafka.partition": -1, "messaging.message_payload_size_bytes": 11 diff --git a/tests/snapshots/tests.integrations.laminas.api_tools.latest.rest_test.test_scenario_rest2xx.json b/tests/snapshots/tests.integrations.laminas.api_tools.latest.rest_test.test_scenario_rest2xx.json index 781cebdb29..877807a6fe 100644 --- a/tests/snapshots/tests.integrations.laminas.api_tools.latest.rest_test.test_scenario_rest2xx.json +++ b/tests/snapshots/tests.integrations.laminas.api_tools.latest.rest_test.test_scenario_rest2xx.json @@ -21,6 +21,7 @@ "span.kind": "server" }, "metrics": { + "_dd.top_level": 1.0, "_sampling_priority_v1": 1.0 } }, diff --git a/tests/snapshots/tests.integrations.laminas.api_tools.latest.rest_test.test_scenario_rest4xx.json b/tests/snapshots/tests.integrations.laminas.api_tools.latest.rest_test.test_scenario_rest4xx.json index bcd9fe5695..1912e0b789 100644 --- a/tests/snapshots/tests.integrations.laminas.api_tools.latest.rest_test.test_scenario_rest4xx.json +++ b/tests/snapshots/tests.integrations.laminas.api_tools.latest.rest_test.test_scenario_rest4xx.json @@ -21,6 +21,7 @@ "span.kind": "server" }, "metrics": { + "_dd.top_level": 1.0, "_sampling_priority_v1": 1.0 } }, diff --git a/tests/snapshots/tests.integrations.laminas.api_tools.latest.rest_test.test_scenario_rest5xx.json b/tests/snapshots/tests.integrations.laminas.api_tools.latest.rest_test.test_scenario_rest5xx.json index b12796c239..55ee8be5b2 100644 --- a/tests/snapshots/tests.integrations.laminas.api_tools.latest.rest_test.test_scenario_rest5xx.json +++ b/tests/snapshots/tests.integrations.laminas.api_tools.latest.rest_test.test_scenario_rest5xx.json @@ -25,6 +25,7 @@ "span.kind": "server" }, "metrics": { + "_dd.top_level": 1.0, "_sampling_priority_v1": 1.0 } }, diff --git a/tests/snapshots/tests.integrations.laminas.mvc.latest.common_scenarios_test.test_scenario_get_return_string.json b/tests/snapshots/tests.integrations.laminas.mvc.latest.common_scenarios_test.test_scenario_get_return_string.json index 1bdb15085f..5ecbf47c32 100644 --- a/tests/snapshots/tests.integrations.laminas.mvc.latest.common_scenarios_test.test_scenario_get_return_string.json +++ b/tests/snapshots/tests.integrations.laminas.mvc.latest.common_scenarios_test.test_scenario_get_return_string.json @@ -20,6 +20,7 @@ "span.kind": "server" }, "metrics": { + "_dd.top_level": 1.0, "_sampling_priority_v1": 1.0 } }, diff --git a/tests/snapshots/tests.integrations.laminas.mvc.latest.common_scenarios_test.test_scenario_get_to_missing_route.json b/tests/snapshots/tests.integrations.laminas.mvc.latest.common_scenarios_test.test_scenario_get_to_missing_route.json index cebd2538ca..ccdc06d7ec 100644 --- a/tests/snapshots/tests.integrations.laminas.mvc.latest.common_scenarios_test.test_scenario_get_to_missing_route.json +++ b/tests/snapshots/tests.integrations.laminas.mvc.latest.common_scenarios_test.test_scenario_get_to_missing_route.json @@ -17,6 +17,7 @@ "span.kind": "server" }, "metrics": { + "_dd.top_level": 1.0, "_sampling_priority_v1": 1.0 } }, diff --git a/tests/snapshots/tests.integrations.laminas.mvc.latest.common_scenarios_test.test_scenario_get_with_exception.json b/tests/snapshots/tests.integrations.laminas.mvc.latest.common_scenarios_test.test_scenario_get_with_exception.json index 378a177110..7555d81e76 100644 --- a/tests/snapshots/tests.integrations.laminas.mvc.latest.common_scenarios_test.test_scenario_get_with_exception.json +++ b/tests/snapshots/tests.integrations.laminas.mvc.latest.common_scenarios_test.test_scenario_get_with_exception.json @@ -24,6 +24,7 @@ "span.kind": "server" }, "metrics": { + "_dd.top_level": 1.0, "_sampling_priority_v1": 1.0 } }, diff --git a/tests/snapshots/tests.integrations.laminas.mvc.latest.common_scenarios_test.test_scenario_get_with_view.json b/tests/snapshots/tests.integrations.laminas.mvc.latest.common_scenarios_test.test_scenario_get_with_view.json index 2d16a69aa4..c4837b309c 100644 --- a/tests/snapshots/tests.integrations.laminas.mvc.latest.common_scenarios_test.test_scenario_get_with_view.json +++ b/tests/snapshots/tests.integrations.laminas.mvc.latest.common_scenarios_test.test_scenario_get_with_view.json @@ -20,6 +20,7 @@ "span.kind": "server" }, "metrics": { + "_dd.top_level": 1.0, "_sampling_priority_v1": 1.0 } }, diff --git a/tests/snapshots/tests.integrations.laminas.mvc.v3_3.common_scenarios_test.test_scenario_get_return_string.json b/tests/snapshots/tests.integrations.laminas.mvc.v3_3.common_scenarios_test.test_scenario_get_return_string.json index 1095152bce..c42fe8d432 100644 --- a/tests/snapshots/tests.integrations.laminas.mvc.v3_3.common_scenarios_test.test_scenario_get_return_string.json +++ b/tests/snapshots/tests.integrations.laminas.mvc.v3_3.common_scenarios_test.test_scenario_get_return_string.json @@ -22,6 +22,7 @@ "span.kind": "server" }, "metrics": { + "_dd.top_level": 1.0, "_sampling_priority_v1": 1.0 } }, diff --git a/tests/snapshots/tests.integrations.laminas.mvc.v3_3.common_scenarios_test.test_scenario_get_to_missing_route.json b/tests/snapshots/tests.integrations.laminas.mvc.v3_3.common_scenarios_test.test_scenario_get_to_missing_route.json index 771abe7c6b..bd72765dfc 100644 --- a/tests/snapshots/tests.integrations.laminas.mvc.v3_3.common_scenarios_test.test_scenario_get_to_missing_route.json +++ b/tests/snapshots/tests.integrations.laminas.mvc.v3_3.common_scenarios_test.test_scenario_get_to_missing_route.json @@ -19,6 +19,7 @@ "span.kind": "server" }, "metrics": { + "_dd.top_level": 1.0, "_sampling_priority_v1": 1.0 } }, diff --git a/tests/snapshots/tests.integrations.laminas.mvc.v3_3.common_scenarios_test.test_scenario_get_with_exception.json b/tests/snapshots/tests.integrations.laminas.mvc.v3_3.common_scenarios_test.test_scenario_get_with_exception.json index b7e009b663..79d3208952 100644 --- a/tests/snapshots/tests.integrations.laminas.mvc.v3_3.common_scenarios_test.test_scenario_get_with_exception.json +++ b/tests/snapshots/tests.integrations.laminas.mvc.v3_3.common_scenarios_test.test_scenario_get_with_exception.json @@ -26,6 +26,7 @@ "span.kind": "server" }, "metrics": { + "_dd.top_level": 1.0, "_sampling_priority_v1": 1.0 } }, diff --git a/tests/snapshots/tests.integrations.laminas.mvc.v3_3.common_scenarios_test.test_scenario_get_with_view.json b/tests/snapshots/tests.integrations.laminas.mvc.v3_3.common_scenarios_test.test_scenario_get_with_view.json index 901042e3de..e1305168b8 100644 --- a/tests/snapshots/tests.integrations.laminas.mvc.v3_3.common_scenarios_test.test_scenario_get_with_view.json +++ b/tests/snapshots/tests.integrations.laminas.mvc.v3_3.common_scenarios_test.test_scenario_get_with_view.json @@ -22,6 +22,7 @@ "span.kind": "server" }, "metrics": { + "_dd.top_level": 1.0, "_sampling_priority_v1": 1.0 } }, diff --git a/tests/snapshots/tests.integrations.laravel.apigw_test.test_laravel_inferred_proxy.json b/tests/snapshots/tests.integrations.laravel.apigw_test.test_laravel_inferred_proxy.json index 30a75fbd36..2f435e1cbf 100644 --- a/tests/snapshots/tests.integrations.laravel.apigw_test.test_laravel_inferred_proxy.json +++ b/tests/snapshots/tests.integrations.laravel.apigw_test.test_laravel_inferred_proxy.json @@ -20,6 +20,7 @@ }, "metrics": { "_dd.inferred_span": 1, + "_dd.top_level": 1.0, "_sampling_priority_v1": 1.0 } }, @@ -43,6 +44,9 @@ "runtime-id": "c6544e02-6221-4cb4-8ef7-3539ff93cc34", "span.kind": "server", "version": "1.0" + }, + "metrics": { + "_dd.top_level": 1.0 } }, { diff --git a/tests/snapshots/tests.integrations.laravel.apigw_test.test_laravel_inferred_proxy_exception.json b/tests/snapshots/tests.integrations.laravel.apigw_test.test_laravel_inferred_proxy_exception.json index 1d07dbb615..0b168b113d 100644 --- a/tests/snapshots/tests.integrations.laravel.apigw_test.test_laravel_inferred_proxy_exception.json +++ b/tests/snapshots/tests.integrations.laravel.apigw_test.test_laravel_inferred_proxy_exception.json @@ -24,6 +24,7 @@ }, "metrics": { "_dd.inferred_span": 1, + "_dd.top_level": 1.0, "_sampling_priority_v1": 1.0 } }, @@ -51,6 +52,9 @@ "runtime-id": "c6544e02-6221-4cb4-8ef7-3539ff93cc34", "span.kind": "server", "version": "1.0" + }, + "metrics": { + "_dd.top_level": 1.0 } }, { diff --git a/tests/snapshots/tests.integrations.laravel.latest.common_scenarios_test.test_scenario_get_dynamic_route.json b/tests/snapshots/tests.integrations.laravel.latest.common_scenarios_test.test_scenario_get_dynamic_route.json index a259ccb31a..3ba2e8e3a0 100644 --- a/tests/snapshots/tests.integrations.laravel.latest.common_scenarios_test.test_scenario_get_dynamic_route.json +++ b/tests/snapshots/tests.integrations.laravel.latest.common_scenarios_test.test_scenario_get_dynamic_route.json @@ -18,6 +18,7 @@ "span.kind": "server" }, "metrics": { + "_dd.top_level": 1.0, "_sampling_priority_v1": 1.0 } }, diff --git a/tests/snapshots/tests.integrations.laravel.latest.common_scenarios_test.test_scenario_get_return_string.json b/tests/snapshots/tests.integrations.laravel.latest.common_scenarios_test.test_scenario_get_return_string.json index 8a232b9230..b1b107fff1 100644 --- a/tests/snapshots/tests.integrations.laravel.latest.common_scenarios_test.test_scenario_get_return_string.json +++ b/tests/snapshots/tests.integrations.laravel.latest.common_scenarios_test.test_scenario_get_return_string.json @@ -21,6 +21,7 @@ "span.kind": "server" }, "metrics": { + "_dd.top_level": 1.0, "_sampling_priority_v1": 1.0 } }, diff --git a/tests/snapshots/tests.integrations.laravel.latest.common_scenarios_test.test_scenario_get_to_missing_route.json b/tests/snapshots/tests.integrations.laravel.latest.common_scenarios_test.test_scenario_get_to_missing_route.json index cba33f84cd..4715375689 100644 --- a/tests/snapshots/tests.integrations.laravel.latest.common_scenarios_test.test_scenario_get_to_missing_route.json +++ b/tests/snapshots/tests.integrations.laravel.latest.common_scenarios_test.test_scenario_get_to_missing_route.json @@ -18,6 +18,7 @@ "span.kind": "server" }, "metrics": { + "_dd.top_level": 1.0, "_sampling_priority_v1": 1.0 } }, diff --git a/tests/snapshots/tests.integrations.laravel.latest.common_scenarios_test.test_scenario_get_with_exception.json b/tests/snapshots/tests.integrations.laravel.latest.common_scenarios_test.test_scenario_get_with_exception.json index 8f1d421bec..96df301cdb 100644 --- a/tests/snapshots/tests.integrations.laravel.latest.common_scenarios_test.test_scenario_get_with_exception.json +++ b/tests/snapshots/tests.integrations.laravel.latest.common_scenarios_test.test_scenario_get_with_exception.json @@ -25,6 +25,7 @@ "span.kind": "server" }, "metrics": { + "_dd.top_level": 1.0, "_sampling_priority_v1": 1.0 } }, diff --git a/tests/snapshots/tests.integrations.laravel.latest.common_scenarios_test.test_scenario_get_with_ignored_exception.json b/tests/snapshots/tests.integrations.laravel.latest.common_scenarios_test.test_scenario_get_with_ignored_exception.json index ac0e27db47..f37c60706f 100644 --- a/tests/snapshots/tests.integrations.laravel.latest.common_scenarios_test.test_scenario_get_with_ignored_exception.json +++ b/tests/snapshots/tests.integrations.laravel.latest.common_scenarios_test.test_scenario_get_with_ignored_exception.json @@ -21,6 +21,7 @@ "span.kind": "server" }, "metrics": { + "_dd.top_level": 1.0, "_sampling_priority_v1": 1.0 } }, diff --git a/tests/snapshots/tests.integrations.laravel.latest.common_scenarios_test.test_scenario_get_with_view.json b/tests/snapshots/tests.integrations.laravel.latest.common_scenarios_test.test_scenario_get_with_view.json index 2f0e9cc11a..aed6453256 100644 --- a/tests/snapshots/tests.integrations.laravel.latest.common_scenarios_test.test_scenario_get_with_view.json +++ b/tests/snapshots/tests.integrations.laravel.latest.common_scenarios_test.test_scenario_get_with_view.json @@ -21,6 +21,7 @@ "span.kind": "server" }, "metrics": { + "_dd.top_level": 1.0, "_sampling_priority_v1": 1.0 } }, diff --git a/tests/snapshots/tests.integrations.laravel.octane.apigw_test.test_inferred_proxy.json b/tests/snapshots/tests.integrations.laravel.octane.apigw_test.test_inferred_proxy.json index b272893f43..c82fbc8f52 100644 --- a/tests/snapshots/tests.integrations.laravel.octane.apigw_test.test_inferred_proxy.json +++ b/tests/snapshots/tests.integrations.laravel.octane.apigw_test.test_inferred_proxy.json @@ -19,6 +19,7 @@ }, "metrics": { "_dd.inferred_span": 1, + "_dd.top_level": 1, "_sampling_priority_v1": 1 } }, @@ -48,6 +49,9 @@ "runtime-id": "3cbb2740-e2da-426b-8029-a79481b8378d", "span.kind": "server", "version": "1.0" + }, + "metrics": { + "_dd.top_level": 1 } }, { diff --git a/tests/snapshots/tests.integrations.laravel.octane.apigw_test.test_inferred_proxy_exception.json b/tests/snapshots/tests.integrations.laravel.octane.apigw_test.test_inferred_proxy_exception.json index 419fe5954d..1ff452d6e5 100644 --- a/tests/snapshots/tests.integrations.laravel.octane.apigw_test.test_inferred_proxy_exception.json +++ b/tests/snapshots/tests.integrations.laravel.octane.apigw_test.test_inferred_proxy_exception.json @@ -23,6 +23,7 @@ }, "metrics": { "_dd.inferred_span": 1, + "_dd.top_level": 1, "_sampling_priority_v1": 1 } }, @@ -56,6 +57,9 @@ "runtime-id": "a84b7cbb-5525-4317-a319-a9a2ac251625", "span.kind": "server", "version": "1.0" + }, + "metrics": { + "_dd.top_level": 1 } }, { diff --git a/tests/snapshots/tests.integrations.laravel.v10_x.common_scenarios_test.test_scenario_get_dynamic_route.json b/tests/snapshots/tests.integrations.laravel.v10_x.common_scenarios_test.test_scenario_get_dynamic_route.json index 61f9f360c1..7fa90af88a 100644 --- a/tests/snapshots/tests.integrations.laravel.v10_x.common_scenarios_test.test_scenario_get_dynamic_route.json +++ b/tests/snapshots/tests.integrations.laravel.v10_x.common_scenarios_test.test_scenario_get_dynamic_route.json @@ -18,6 +18,7 @@ "span.kind": "server" }, "metrics": { + "_dd.top_level": 1.0, "_sampling_priority_v1": 1.0 } }, diff --git a/tests/snapshots/tests.integrations.laravel.v10_x.common_scenarios_test.test_scenario_get_return_string.json b/tests/snapshots/tests.integrations.laravel.v10_x.common_scenarios_test.test_scenario_get_return_string.json index 4f0313c6f4..63a30ba855 100644 --- a/tests/snapshots/tests.integrations.laravel.v10_x.common_scenarios_test.test_scenario_get_return_string.json +++ b/tests/snapshots/tests.integrations.laravel.v10_x.common_scenarios_test.test_scenario_get_return_string.json @@ -21,6 +21,7 @@ "span.kind": "server" }, "metrics": { + "_dd.top_level": 1.0, "_sampling_priority_v1": 1.0 } }, diff --git a/tests/snapshots/tests.integrations.laravel.v10_x.common_scenarios_test.test_scenario_get_to_missing_route.json b/tests/snapshots/tests.integrations.laravel.v10_x.common_scenarios_test.test_scenario_get_to_missing_route.json index 078498389a..8134f303cf 100644 --- a/tests/snapshots/tests.integrations.laravel.v10_x.common_scenarios_test.test_scenario_get_to_missing_route.json +++ b/tests/snapshots/tests.integrations.laravel.v10_x.common_scenarios_test.test_scenario_get_to_missing_route.json @@ -18,6 +18,7 @@ "span.kind": "server" }, "metrics": { + "_dd.top_level": 1.0, "_sampling_priority_v1": 1.0 } }, diff --git a/tests/snapshots/tests.integrations.laravel.v10_x.common_scenarios_test.test_scenario_get_with_exception.json b/tests/snapshots/tests.integrations.laravel.v10_x.common_scenarios_test.test_scenario_get_with_exception.json index 83bad2e3d5..3ab1bcd474 100644 --- a/tests/snapshots/tests.integrations.laravel.v10_x.common_scenarios_test.test_scenario_get_with_exception.json +++ b/tests/snapshots/tests.integrations.laravel.v10_x.common_scenarios_test.test_scenario_get_with_exception.json @@ -25,6 +25,7 @@ "span.kind": "server" }, "metrics": { + "_dd.top_level": 1.0, "_sampling_priority_v1": 1.0 } }, diff --git a/tests/snapshots/tests.integrations.laravel.v10_x.common_scenarios_test.test_scenario_get_with_ignored_exception.json b/tests/snapshots/tests.integrations.laravel.v10_x.common_scenarios_test.test_scenario_get_with_ignored_exception.json index 3233a40a35..6f1a0d09b3 100644 --- a/tests/snapshots/tests.integrations.laravel.v10_x.common_scenarios_test.test_scenario_get_with_ignored_exception.json +++ b/tests/snapshots/tests.integrations.laravel.v10_x.common_scenarios_test.test_scenario_get_with_ignored_exception.json @@ -21,6 +21,7 @@ "span.kind": "server" }, "metrics": { + "_dd.top_level": 1.0, "_sampling_priority_v1": 1.0 } }, diff --git a/tests/snapshots/tests.integrations.laravel.v10_x.common_scenarios_test.test_scenario_get_with_view.json b/tests/snapshots/tests.integrations.laravel.v10_x.common_scenarios_test.test_scenario_get_with_view.json index 112ac020a3..1322a09af2 100644 --- a/tests/snapshots/tests.integrations.laravel.v10_x.common_scenarios_test.test_scenario_get_with_view.json +++ b/tests/snapshots/tests.integrations.laravel.v10_x.common_scenarios_test.test_scenario_get_with_view.json @@ -21,6 +21,7 @@ "span.kind": "server" }, "metrics": { + "_dd.top_level": 1.0, "_sampling_priority_v1": 1.0 } }, diff --git a/tests/snapshots/tests.integrations.laravel.v11_x.common_scenarios_test.test_scenario_get_dynamic_route.json b/tests/snapshots/tests.integrations.laravel.v11_x.common_scenarios_test.test_scenario_get_dynamic_route.json index 173019f7ad..c1e7863e1a 100644 --- a/tests/snapshots/tests.integrations.laravel.v11_x.common_scenarios_test.test_scenario_get_dynamic_route.json +++ b/tests/snapshots/tests.integrations.laravel.v11_x.common_scenarios_test.test_scenario_get_dynamic_route.json @@ -18,6 +18,7 @@ "span.kind": "server" }, "metrics": { + "_dd.top_level": 1.0, "_sampling_priority_v1": 1.0 } }, diff --git a/tests/snapshots/tests.integrations.laravel.v11_x.common_scenarios_test.test_scenario_get_return_string.json b/tests/snapshots/tests.integrations.laravel.v11_x.common_scenarios_test.test_scenario_get_return_string.json index 129eb9bf54..932c674cbe 100644 --- a/tests/snapshots/tests.integrations.laravel.v11_x.common_scenarios_test.test_scenario_get_return_string.json +++ b/tests/snapshots/tests.integrations.laravel.v11_x.common_scenarios_test.test_scenario_get_return_string.json @@ -21,6 +21,7 @@ "span.kind": "server" }, "metrics": { + "_dd.top_level": 1.0, "_sampling_priority_v1": 1.0 } }, diff --git a/tests/snapshots/tests.integrations.laravel.v11_x.common_scenarios_test.test_scenario_get_to_missing_route.json b/tests/snapshots/tests.integrations.laravel.v11_x.common_scenarios_test.test_scenario_get_to_missing_route.json index 75ca1fa3f6..419a9973da 100644 --- a/tests/snapshots/tests.integrations.laravel.v11_x.common_scenarios_test.test_scenario_get_to_missing_route.json +++ b/tests/snapshots/tests.integrations.laravel.v11_x.common_scenarios_test.test_scenario_get_to_missing_route.json @@ -18,6 +18,7 @@ "span.kind": "server" }, "metrics": { + "_dd.top_level": 1.0, "_sampling_priority_v1": 1.0 } }, diff --git a/tests/snapshots/tests.integrations.laravel.v11_x.common_scenarios_test.test_scenario_get_with_exception.json b/tests/snapshots/tests.integrations.laravel.v11_x.common_scenarios_test.test_scenario_get_with_exception.json index 2099de6018..5ba9310532 100644 --- a/tests/snapshots/tests.integrations.laravel.v11_x.common_scenarios_test.test_scenario_get_with_exception.json +++ b/tests/snapshots/tests.integrations.laravel.v11_x.common_scenarios_test.test_scenario_get_with_exception.json @@ -25,6 +25,7 @@ "span.kind": "server" }, "metrics": { + "_dd.top_level": 1.0, "_sampling_priority_v1": 1.0 } }, diff --git a/tests/snapshots/tests.integrations.laravel.v11_x.common_scenarios_test.test_scenario_get_with_view.json b/tests/snapshots/tests.integrations.laravel.v11_x.common_scenarios_test.test_scenario_get_with_view.json index 680f92fc80..982c472192 100644 --- a/tests/snapshots/tests.integrations.laravel.v11_x.common_scenarios_test.test_scenario_get_with_view.json +++ b/tests/snapshots/tests.integrations.laravel.v11_x.common_scenarios_test.test_scenario_get_with_view.json @@ -21,6 +21,7 @@ "span.kind": "server" }, "metrics": { + "_dd.top_level": 1.0, "_sampling_priority_v1": 1.0 } }, diff --git a/tests/snapshots/tests.integrations.laravel.v5_7.common_scenarios_test.test_scenario_get_dynamic_route.json b/tests/snapshots/tests.integrations.laravel.v5_7.common_scenarios_test.test_scenario_get_dynamic_route.json index 22efd53562..14cca27eef 100644 --- a/tests/snapshots/tests.integrations.laravel.v5_7.common_scenarios_test.test_scenario_get_dynamic_route.json +++ b/tests/snapshots/tests.integrations.laravel.v5_7.common_scenarios_test.test_scenario_get_dynamic_route.json @@ -21,6 +21,7 @@ "span.kind": "server" }, "metrics": { + "_dd.top_level": 1.0, "_sampling_priority_v1": 1.0 } }, @@ -35,6 +36,9 @@ "meta": { "_dd.base_service": "laravel_test_app", "component": "laravel" + }, + "metrics": { + "_dd.top_level": 1.0 } }, { @@ -48,6 +52,9 @@ "meta": { "_dd.base_service": "laravel_test_app", "component": "laravel" + }, + "metrics": { + "_dd.top_level": 1.0 } }, { @@ -61,6 +68,9 @@ "meta": { "_dd.base_service": "laravel_test_app", "component": "laravel" + }, + "metrics": { + "_dd.top_level": 1.0 } }, { diff --git a/tests/snapshots/tests.integrations.laravel.v5_7.common_scenarios_test.test_scenario_get_return_string.json b/tests/snapshots/tests.integrations.laravel.v5_7.common_scenarios_test.test_scenario_get_return_string.json index 70b03dbba7..8266c058d3 100644 --- a/tests/snapshots/tests.integrations.laravel.v5_7.common_scenarios_test.test_scenario_get_return_string.json +++ b/tests/snapshots/tests.integrations.laravel.v5_7.common_scenarios_test.test_scenario_get_return_string.json @@ -21,6 +21,7 @@ "span.kind": "server" }, "metrics": { + "_dd.top_level": 1.0, "_sampling_priority_v1": 1.0 } }, @@ -35,6 +36,9 @@ "meta": { "_dd.base_service": "laravel_test_app", "component": "laravel" + }, + "metrics": { + "_dd.top_level": 1.0 } }, { @@ -48,6 +52,9 @@ "meta": { "_dd.base_service": "laravel_test_app", "component": "laravel" + }, + "metrics": { + "_dd.top_level": 1.0 } }, { @@ -61,6 +68,9 @@ "meta": { "_dd.base_service": "laravel_test_app", "component": "laravel" + }, + "metrics": { + "_dd.top_level": 1.0 } }, { diff --git a/tests/snapshots/tests.integrations.laravel.v5_7.common_scenarios_test.test_scenario_get_to_missing_route.json b/tests/snapshots/tests.integrations.laravel.v5_7.common_scenarios_test.test_scenario_get_to_missing_route.json index e311fa2b00..9b836b3f0d 100644 --- a/tests/snapshots/tests.integrations.laravel.v5_7.common_scenarios_test.test_scenario_get_to_missing_route.json +++ b/tests/snapshots/tests.integrations.laravel.v5_7.common_scenarios_test.test_scenario_get_to_missing_route.json @@ -18,6 +18,7 @@ "span.kind": "server" }, "metrics": { + "_dd.top_level": 1.0, "_sampling_priority_v1": 1.0 } }, @@ -32,6 +33,9 @@ "meta": { "_dd.base_service": "laravel_test_app", "component": "laravel" + }, + "metrics": { + "_dd.top_level": 1.0 } }, { @@ -45,6 +49,9 @@ "meta": { "_dd.base_service": "laravel_test_app", "component": "laravel" + }, + "metrics": { + "_dd.top_level": 1.0 } }, { @@ -58,6 +65,9 @@ "meta": { "_dd.base_service": "laravel_test_app", "component": "laravel" + }, + "metrics": { + "_dd.top_level": 1.0 } }, { diff --git a/tests/snapshots/tests.integrations.laravel.v5_7.common_scenarios_test.test_scenario_get_with_exception.json b/tests/snapshots/tests.integrations.laravel.v5_7.common_scenarios_test.test_scenario_get_with_exception.json index 2934d7bfe6..cc6f2e3164 100644 --- a/tests/snapshots/tests.integrations.laravel.v5_7.common_scenarios_test.test_scenario_get_with_exception.json +++ b/tests/snapshots/tests.integrations.laravel.v5_7.common_scenarios_test.test_scenario_get_with_exception.json @@ -25,6 +25,7 @@ "span.kind": "server" }, "metrics": { + "_dd.top_level": 1.0, "_sampling_priority_v1": 1.0 } }, @@ -39,6 +40,9 @@ "meta": { "_dd.base_service": "laravel_test_app", "component": "laravel" + }, + "metrics": { + "_dd.top_level": 1.0 } }, { @@ -52,6 +56,9 @@ "meta": { "_dd.base_service": "laravel_test_app", "component": "laravel" + }, + "metrics": { + "_dd.top_level": 1.0 } }, { @@ -65,6 +72,9 @@ "meta": { "_dd.base_service": "laravel_test_app", "component": "laravel" + }, + "metrics": { + "_dd.top_level": 1.0 } }, { diff --git a/tests/snapshots/tests.integrations.laravel.v5_7.common_scenarios_test.test_scenario_get_with_view.json b/tests/snapshots/tests.integrations.laravel.v5_7.common_scenarios_test.test_scenario_get_with_view.json index 20a7a2d853..b9fa3364fb 100644 --- a/tests/snapshots/tests.integrations.laravel.v5_7.common_scenarios_test.test_scenario_get_with_view.json +++ b/tests/snapshots/tests.integrations.laravel.v5_7.common_scenarios_test.test_scenario_get_with_view.json @@ -21,6 +21,7 @@ "span.kind": "server" }, "metrics": { + "_dd.top_level": 1.0, "_sampling_priority_v1": 1.0 } }, @@ -35,6 +36,9 @@ "meta": { "_dd.base_service": "laravel_test_app", "component": "laravel" + }, + "metrics": { + "_dd.top_level": 1.0 } }, { @@ -48,6 +52,9 @@ "meta": { "_dd.base_service": "laravel_test_app", "component": "laravel" + }, + "metrics": { + "_dd.top_level": 1.0 } }, { @@ -61,6 +68,9 @@ "meta": { "_dd.base_service": "laravel_test_app", "component": "laravel" + }, + "metrics": { + "_dd.top_level": 1.0 } }, { diff --git a/tests/snapshots/tests.integrations.laravel.v5_8.common_scenarios_test.test_scenario_get_dynamic_route.json b/tests/snapshots/tests.integrations.laravel.v5_8.common_scenarios_test.test_scenario_get_dynamic_route.json index 3e1774ade8..6bddedff1c 100644 --- a/tests/snapshots/tests.integrations.laravel.v5_8.common_scenarios_test.test_scenario_get_dynamic_route.json +++ b/tests/snapshots/tests.integrations.laravel.v5_8.common_scenarios_test.test_scenario_get_dynamic_route.json @@ -21,6 +21,7 @@ "span.kind": "server" }, "metrics": { + "_dd.top_level": 1.0, "_sampling_priority_v1": 1.0 } }, diff --git a/tests/snapshots/tests.integrations.laravel.v5_8.common_scenarios_test.test_scenario_get_return_string.json b/tests/snapshots/tests.integrations.laravel.v5_8.common_scenarios_test.test_scenario_get_return_string.json index ede2a71d26..2c84358d40 100644 --- a/tests/snapshots/tests.integrations.laravel.v5_8.common_scenarios_test.test_scenario_get_return_string.json +++ b/tests/snapshots/tests.integrations.laravel.v5_8.common_scenarios_test.test_scenario_get_return_string.json @@ -21,6 +21,7 @@ "span.kind": "server" }, "metrics": { + "_dd.top_level": 1.0, "_sampling_priority_v1": 1.0 } }, diff --git a/tests/snapshots/tests.integrations.laravel.v5_8.common_scenarios_test.test_scenario_get_to_missing_route.json b/tests/snapshots/tests.integrations.laravel.v5_8.common_scenarios_test.test_scenario_get_to_missing_route.json index f8a3c1d0e0..05add0c60b 100644 --- a/tests/snapshots/tests.integrations.laravel.v5_8.common_scenarios_test.test_scenario_get_to_missing_route.json +++ b/tests/snapshots/tests.integrations.laravel.v5_8.common_scenarios_test.test_scenario_get_to_missing_route.json @@ -18,6 +18,7 @@ "span.kind": "server" }, "metrics": { + "_dd.top_level": 1.0, "_sampling_priority_v1": 1.0 } }, diff --git a/tests/snapshots/tests.integrations.laravel.v5_8.common_scenarios_test.test_scenario_get_with_exception.json b/tests/snapshots/tests.integrations.laravel.v5_8.common_scenarios_test.test_scenario_get_with_exception.json index bd6e68a2a2..7f29380f5b 100644 --- a/tests/snapshots/tests.integrations.laravel.v5_8.common_scenarios_test.test_scenario_get_with_exception.json +++ b/tests/snapshots/tests.integrations.laravel.v5_8.common_scenarios_test.test_scenario_get_with_exception.json @@ -25,6 +25,7 @@ "span.kind": "server" }, "metrics": { + "_dd.top_level": 1.0, "_sampling_priority_v1": 1.0 } }, diff --git a/tests/snapshots/tests.integrations.laravel.v5_8.common_scenarios_test.test_scenario_get_with_view.json b/tests/snapshots/tests.integrations.laravel.v5_8.common_scenarios_test.test_scenario_get_with_view.json index e6dd0b6f68..dc1c35643d 100644 --- a/tests/snapshots/tests.integrations.laravel.v5_8.common_scenarios_test.test_scenario_get_with_view.json +++ b/tests/snapshots/tests.integrations.laravel.v5_8.common_scenarios_test.test_scenario_get_with_view.json @@ -21,6 +21,7 @@ "span.kind": "server" }, "metrics": { + "_dd.top_level": 1.0, "_sampling_priority_v1": 1.0 } }, diff --git a/tests/snapshots/tests.integrations.laravel.v8_x.common_scenarios_test.test_scenario_get_dynamic_route.json b/tests/snapshots/tests.integrations.laravel.v8_x.common_scenarios_test.test_scenario_get_dynamic_route.json index e2ee39ae9c..6201910099 100644 --- a/tests/snapshots/tests.integrations.laravel.v8_x.common_scenarios_test.test_scenario_get_dynamic_route.json +++ b/tests/snapshots/tests.integrations.laravel.v8_x.common_scenarios_test.test_scenario_get_dynamic_route.json @@ -21,6 +21,7 @@ "span.kind": "server" }, "metrics": { + "_dd.top_level": 1.0, "_sampling_priority_v1": 1.0 } }, diff --git a/tests/snapshots/tests.integrations.laravel.v8_x.common_scenarios_test.test_scenario_get_return_string.json b/tests/snapshots/tests.integrations.laravel.v8_x.common_scenarios_test.test_scenario_get_return_string.json index 1ad5cb004a..9ad7139cec 100644 --- a/tests/snapshots/tests.integrations.laravel.v8_x.common_scenarios_test.test_scenario_get_return_string.json +++ b/tests/snapshots/tests.integrations.laravel.v8_x.common_scenarios_test.test_scenario_get_return_string.json @@ -21,6 +21,7 @@ "span.kind": "server" }, "metrics": { + "_dd.top_level": 1.0, "_sampling_priority_v1": 1.0 } }, diff --git a/tests/snapshots/tests.integrations.laravel.v8_x.common_scenarios_test.test_scenario_get_to_missing_route.json b/tests/snapshots/tests.integrations.laravel.v8_x.common_scenarios_test.test_scenario_get_to_missing_route.json index 884e59bdbc..22fea5b1a8 100644 --- a/tests/snapshots/tests.integrations.laravel.v8_x.common_scenarios_test.test_scenario_get_to_missing_route.json +++ b/tests/snapshots/tests.integrations.laravel.v8_x.common_scenarios_test.test_scenario_get_to_missing_route.json @@ -18,6 +18,7 @@ "span.kind": "server" }, "metrics": { + "_dd.top_level": 1.0, "_sampling_priority_v1": 1.0 } }, diff --git a/tests/snapshots/tests.integrations.laravel.v8_x.common_scenarios_test.test_scenario_get_with_exception.json b/tests/snapshots/tests.integrations.laravel.v8_x.common_scenarios_test.test_scenario_get_with_exception.json index 0d1c1ee654..6e9645c95a 100644 --- a/tests/snapshots/tests.integrations.laravel.v8_x.common_scenarios_test.test_scenario_get_with_exception.json +++ b/tests/snapshots/tests.integrations.laravel.v8_x.common_scenarios_test.test_scenario_get_with_exception.json @@ -25,6 +25,7 @@ "span.kind": "server" }, "metrics": { + "_dd.top_level": 1.0, "_sampling_priority_v1": 1.0 } }, diff --git a/tests/snapshots/tests.integrations.laravel.v8_x.common_scenarios_test.test_scenario_get_with_view.json b/tests/snapshots/tests.integrations.laravel.v8_x.common_scenarios_test.test_scenario_get_with_view.json index de7b4288e7..d4d83260a7 100644 --- a/tests/snapshots/tests.integrations.laravel.v8_x.common_scenarios_test.test_scenario_get_with_view.json +++ b/tests/snapshots/tests.integrations.laravel.v8_x.common_scenarios_test.test_scenario_get_with_view.json @@ -21,6 +21,7 @@ "span.kind": "server" }, "metrics": { + "_dd.top_level": 1.0, "_sampling_priority_v1": 1.0 } }, diff --git a/tests/snapshots/tests.integrations.laravel.v8_x.queue_test.test_broadcast.json b/tests/snapshots/tests.integrations.laravel.v8_x.queue_test.test_broadcast.json index 66ee49f491..971f75b6c5 100644 --- a/tests/snapshots/tests.integrations.laravel.v8_x.queue_test.test_broadcast.json +++ b/tests/snapshots/tests.integrations.laravel.v8_x.queue_test.test_broadcast.json @@ -21,6 +21,7 @@ "span.kind": "server" }, "metrics": { + "_dd.top_level": 1.0, "_sampling_priority_v1": 1.0 } }, diff --git a/tests/snapshots/tests.integrations.laravel.v9_x.common_scenarios_test.test_scenario_get_dynamic_route.json b/tests/snapshots/tests.integrations.laravel.v9_x.common_scenarios_test.test_scenario_get_dynamic_route.json index 6c2bed6035..325172bd86 100644 --- a/tests/snapshots/tests.integrations.laravel.v9_x.common_scenarios_test.test_scenario_get_dynamic_route.json +++ b/tests/snapshots/tests.integrations.laravel.v9_x.common_scenarios_test.test_scenario_get_dynamic_route.json @@ -18,6 +18,7 @@ "span.kind": "server" }, "metrics": { + "_dd.top_level": 1.0, "_sampling_priority_v1": 1.0 } }, diff --git a/tests/snapshots/tests.integrations.laravel.v9_x.common_scenarios_test.test_scenario_get_return_string.json b/tests/snapshots/tests.integrations.laravel.v9_x.common_scenarios_test.test_scenario_get_return_string.json index 01e28d6b43..365e5b484a 100644 --- a/tests/snapshots/tests.integrations.laravel.v9_x.common_scenarios_test.test_scenario_get_return_string.json +++ b/tests/snapshots/tests.integrations.laravel.v9_x.common_scenarios_test.test_scenario_get_return_string.json @@ -21,6 +21,7 @@ "span.kind": "server" }, "metrics": { + "_dd.top_level": 1.0, "_sampling_priority_v1": 1.0 } }, diff --git a/tests/snapshots/tests.integrations.laravel.v9_x.common_scenarios_test.test_scenario_get_to_missing_route.json b/tests/snapshots/tests.integrations.laravel.v9_x.common_scenarios_test.test_scenario_get_to_missing_route.json index eea5cc8a4b..4a8df66216 100644 --- a/tests/snapshots/tests.integrations.laravel.v9_x.common_scenarios_test.test_scenario_get_to_missing_route.json +++ b/tests/snapshots/tests.integrations.laravel.v9_x.common_scenarios_test.test_scenario_get_to_missing_route.json @@ -18,6 +18,7 @@ "span.kind": "server" }, "metrics": { + "_dd.top_level": 1.0, "_sampling_priority_v1": 1.0 } }, diff --git a/tests/snapshots/tests.integrations.laravel.v9_x.common_scenarios_test.test_scenario_get_with_exception.json b/tests/snapshots/tests.integrations.laravel.v9_x.common_scenarios_test.test_scenario_get_with_exception.json index c822b1957a..54ecdda91d 100644 --- a/tests/snapshots/tests.integrations.laravel.v9_x.common_scenarios_test.test_scenario_get_with_exception.json +++ b/tests/snapshots/tests.integrations.laravel.v9_x.common_scenarios_test.test_scenario_get_with_exception.json @@ -25,6 +25,7 @@ "span.kind": "server" }, "metrics": { + "_dd.top_level": 1.0, "_sampling_priority_v1": 1.0 } }, diff --git a/tests/snapshots/tests.integrations.laravel.v9_x.common_scenarios_test.test_scenario_get_with_view.json b/tests/snapshots/tests.integrations.laravel.v9_x.common_scenarios_test.test_scenario_get_with_view.json index 34138c0c85..34e088e269 100644 --- a/tests/snapshots/tests.integrations.laravel.v9_x.common_scenarios_test.test_scenario_get_with_view.json +++ b/tests/snapshots/tests.integrations.laravel.v9_x.common_scenarios_test.test_scenario_get_with_view.json @@ -21,6 +21,7 @@ "span.kind": "server" }, "metrics": { + "_dd.top_level": 1.0, "_sampling_priority_v1": 1.0 } }, diff --git a/tests/snapshots/tests.integrations.magento.v2_3.common_scenarios_test.test_scenario_get_return_string.json b/tests/snapshots/tests.integrations.magento.v2_3.common_scenarios_test.test_scenario_get_return_string.json index 2997d6ac17..7e8e4c01c9 100644 --- a/tests/snapshots/tests.integrations.magento.v2_3.common_scenarios_test.test_scenario_get_return_string.json +++ b/tests/snapshots/tests.integrations.magento.v2_3.common_scenarios_test.test_scenario_get_return_string.json @@ -22,6 +22,7 @@ "span.kind": "server" }, "metrics": { + "_dd.top_level": 1.0, "_sampling_priority_v1": 1.0 } }, diff --git a/tests/snapshots/tests.integrations.magento.v2_3.common_scenarios_test.test_scenario_get_to_missing_route.json b/tests/snapshots/tests.integrations.magento.v2_3.common_scenarios_test.test_scenario_get_to_missing_route.json index 19ee5e01bd..6298572174 100644 --- a/tests/snapshots/tests.integrations.magento.v2_3.common_scenarios_test.test_scenario_get_to_missing_route.json +++ b/tests/snapshots/tests.integrations.magento.v2_3.common_scenarios_test.test_scenario_get_to_missing_route.json @@ -22,6 +22,7 @@ "span.kind": "server" }, "metrics": { + "_dd.top_level": 1.0, "_sampling_priority_v1": 1.0 } }, diff --git a/tests/snapshots/tests.integrations.magento.v2_3.common_scenarios_test.test_scenario_get_with_exception.json b/tests/snapshots/tests.integrations.magento.v2_3.common_scenarios_test.test_scenario_get_with_exception.json index bf66290873..ef08bad4c6 100644 --- a/tests/snapshots/tests.integrations.magento.v2_3.common_scenarios_test.test_scenario_get_with_exception.json +++ b/tests/snapshots/tests.integrations.magento.v2_3.common_scenarios_test.test_scenario_get_with_exception.json @@ -26,6 +26,7 @@ "span.kind": "server" }, "metrics": { + "_dd.top_level": 1.0, "_sampling_priority_v1": 1.0 } }, diff --git a/tests/snapshots/tests.integrations.magento.v2_3.common_scenarios_test.test_scenario_get_with_view.json b/tests/snapshots/tests.integrations.magento.v2_3.common_scenarios_test.test_scenario_get_with_view.json index 61fc7ee450..9f749be8df 100644 --- a/tests/snapshots/tests.integrations.magento.v2_3.common_scenarios_test.test_scenario_get_with_view.json +++ b/tests/snapshots/tests.integrations.magento.v2_3.common_scenarios_test.test_scenario_get_with_view.json @@ -22,6 +22,7 @@ "span.kind": "server" }, "metrics": { + "_dd.top_level": 1.0, "_sampling_priority_v1": 1.0 } }, diff --git a/tests/snapshots/tests.integrations.magento.v2_4.common_scenarios_test.test_scenario_get_return_string.json b/tests/snapshots/tests.integrations.magento.v2_4.common_scenarios_test.test_scenario_get_return_string.json index 72c71d68a0..68dc912b0b 100644 --- a/tests/snapshots/tests.integrations.magento.v2_4.common_scenarios_test.test_scenario_get_return_string.json +++ b/tests/snapshots/tests.integrations.magento.v2_4.common_scenarios_test.test_scenario_get_return_string.json @@ -22,6 +22,7 @@ "span.kind": "server" }, "metrics": { + "_dd.top_level": 1.0, "_sampling_priority_v1": 1.0 } }, diff --git a/tests/snapshots/tests.integrations.magento.v2_4.common_scenarios_test.test_scenario_get_to_missing_route.json b/tests/snapshots/tests.integrations.magento.v2_4.common_scenarios_test.test_scenario_get_to_missing_route.json index b953f93fb2..9ea121f0ea 100644 --- a/tests/snapshots/tests.integrations.magento.v2_4.common_scenarios_test.test_scenario_get_to_missing_route.json +++ b/tests/snapshots/tests.integrations.magento.v2_4.common_scenarios_test.test_scenario_get_to_missing_route.json @@ -22,6 +22,7 @@ "span.kind": "server" }, "metrics": { + "_dd.top_level": 1.0, "_sampling_priority_v1": 1.0 } }, diff --git a/tests/snapshots/tests.integrations.magento.v2_4.common_scenarios_test.test_scenario_get_with_exception.json b/tests/snapshots/tests.integrations.magento.v2_4.common_scenarios_test.test_scenario_get_with_exception.json index 76190413d6..fe0454314f 100644 --- a/tests/snapshots/tests.integrations.magento.v2_4.common_scenarios_test.test_scenario_get_with_exception.json +++ b/tests/snapshots/tests.integrations.magento.v2_4.common_scenarios_test.test_scenario_get_with_exception.json @@ -26,6 +26,7 @@ "span.kind": "server" }, "metrics": { + "_dd.top_level": 1.0, "_sampling_priority_v1": 1.0 } }, diff --git a/tests/snapshots/tests.integrations.magento.v2_4.common_scenarios_test.test_scenario_get_with_view.json b/tests/snapshots/tests.integrations.magento.v2_4.common_scenarios_test.test_scenario_get_with_view.json index eb115310c0..dae272177b 100644 --- a/tests/snapshots/tests.integrations.magento.v2_4.common_scenarios_test.test_scenario_get_with_view.json +++ b/tests/snapshots/tests.integrations.magento.v2_4.common_scenarios_test.test_scenario_get_with_view.json @@ -22,6 +22,7 @@ "span.kind": "server" }, "metrics": { + "_dd.top_level": 1.0, "_sampling_priority_v1": 1.0 } }, diff --git a/tests/snapshots/tests.integrations.roadrunner.apigw_test.test_inferred_proxy.json b/tests/snapshots/tests.integrations.roadrunner.apigw_test.test_inferred_proxy.json index d5425bb8d1..c43646f220 100644 --- a/tests/snapshots/tests.integrations.roadrunner.apigw_test.test_inferred_proxy.json +++ b/tests/snapshots/tests.integrations.roadrunner.apigw_test.test_inferred_proxy.json @@ -19,6 +19,7 @@ }, "metrics": { "_dd.inferred_span": 1, + "_dd.top_level": 1, "_sampling_priority_v1": 1 } }, @@ -45,5 +46,8 @@ "runtime-id": "fd6e51db-bf2d-40fe-aa43-ae7c29474411", "span.kind": "server", "version": "1.0" + }, + "metrics": { + "_dd.top_level": 1 } }]] diff --git a/tests/snapshots/tests.integrations.roadrunner.apigw_test.test_inferred_proxy_exception.json b/tests/snapshots/tests.integrations.roadrunner.apigw_test.test_inferred_proxy_exception.json index d39002c24b..9d423e45d7 100644 --- a/tests/snapshots/tests.integrations.roadrunner.apigw_test.test_inferred_proxy_exception.json +++ b/tests/snapshots/tests.integrations.roadrunner.apigw_test.test_inferred_proxy_exception.json @@ -23,6 +23,7 @@ }, "metrics": { "_dd.inferred_span": 1, + "_dd.top_level": 1, "_sampling_priority_v1": 1 } }, @@ -53,5 +54,8 @@ "runtime-id": "fd6e51db-bf2d-40fe-aa43-ae7c29474411", "span.kind": "server", "version": "1.0" + }, + "metrics": { + "_dd.top_level": 1 } }]] diff --git a/tests/snapshots/tests.integrations.symfony.latest.common_scenarios_test.test_scenario_get_to_missing_route.json b/tests/snapshots/tests.integrations.symfony.latest.common_scenarios_test.test_scenario_get_to_missing_route.json index 5b560f719a..8a2e40557d 100644 --- a/tests/snapshots/tests.integrations.symfony.latest.common_scenarios_test.test_scenario_get_to_missing_route.json +++ b/tests/snapshots/tests.integrations.symfony.latest.common_scenarios_test.test_scenario_get_to_missing_route.json @@ -18,6 +18,7 @@ "span.kind": "server" }, "metrics": { + "_dd.top_level": 1.0, "_sampling_priority_v1": 1.0 } }, diff --git a/tests/snapshots/tests.integrations.symfony.latest.messenger_test.test_async_success_consumer.json b/tests/snapshots/tests.integrations.symfony.latest.messenger_test.test_async_success_consumer.json index 462f84f9e8..4272fd7d6b 100644 --- a/tests/snapshots/tests.integrations.symfony.latest.messenger_test.test_async_success_consumer.json +++ b/tests/snapshots/tests.integrations.symfony.latest.messenger_test.test_async_success_consumer.json @@ -25,6 +25,7 @@ "span.kind": "consumer" }, "metrics": { + "_dd.top_level": 1, "_sampling_priority_v1": 1 } }, @@ -294,6 +295,9 @@ "out.host": "mysql-integration", "out.port": "3306", "span.kind": "client" + }, + "metrics": { + "_dd.top_level": 1 } }, { @@ -321,6 +325,7 @@ "span.kind": "client" }, "metrics": { + "_dd.top_level": 1, "db.row_count": 1 } }]] diff --git a/tests/snapshots/tests.integrations.symfony.v2_3.common_scenarios_test.test_scenario_get_return_string.json b/tests/snapshots/tests.integrations.symfony.v2_3.common_scenarios_test.test_scenario_get_return_string.json index 82348173bb..0cb1cfa7cc 100644 --- a/tests/snapshots/tests.integrations.symfony.v2_3.common_scenarios_test.test_scenario_get_return_string.json +++ b/tests/snapshots/tests.integrations.symfony.v2_3.common_scenarios_test.test_scenario_get_return_string.json @@ -20,6 +20,7 @@ "symfony.route.name": "simple" }, "metrics": { + "_dd.top_level": 1.0, "_sampling_priority_v1": 1.0 } }, diff --git a/tests/snapshots/tests.integrations.symfony.v2_3.common_scenarios_test.test_scenario_get_to_missing_route.json b/tests/snapshots/tests.integrations.symfony.v2_3.common_scenarios_test.test_scenario_get_to_missing_route.json index e8d995e047..62c2259e3e 100644 --- a/tests/snapshots/tests.integrations.symfony.v2_3.common_scenarios_test.test_scenario_get_to_missing_route.json +++ b/tests/snapshots/tests.integrations.symfony.v2_3.common_scenarios_test.test_scenario_get_to_missing_route.json @@ -19,6 +19,7 @@ "symfony.route.action": "Symfony\\Bundle\\TwigBundle\\Controller\\ExceptionController@showAction" }, "metrics": { + "_dd.top_level": 1.0, "_sampling_priority_v1": 1.0 } }, diff --git a/tests/snapshots/tests.integrations.symfony.v2_3.common_scenarios_test.test_scenario_get_with_exception.json b/tests/snapshots/tests.integrations.symfony.v2_3.common_scenarios_test.test_scenario_get_with_exception.json index 201954f0c1..4e48a91ae9 100644 --- a/tests/snapshots/tests.integrations.symfony.v2_3.common_scenarios_test.test_scenario_get_with_exception.json +++ b/tests/snapshots/tests.integrations.symfony.v2_3.common_scenarios_test.test_scenario_get_with_exception.json @@ -24,6 +24,7 @@ "symfony.route.name": "error" }, "metrics": { + "_dd.top_level": 1.0, "_sampling_priority_v1": 1.0 } }, diff --git a/tests/snapshots/tests.integrations.symfony.v2_3.common_scenarios_test.test_scenario_get_with_view.json b/tests/snapshots/tests.integrations.symfony.v2_3.common_scenarios_test.test_scenario_get_with_view.json index 02531a7ac6..48fe18f313 100644 --- a/tests/snapshots/tests.integrations.symfony.v2_3.common_scenarios_test.test_scenario_get_with_view.json +++ b/tests/snapshots/tests.integrations.symfony.v2_3.common_scenarios_test.test_scenario_get_with_view.json @@ -20,6 +20,7 @@ "symfony.route.name": "simple_view" }, "metrics": { + "_dd.top_level": 1.0, "_sampling_priority_v1": 1.0 } }, diff --git a/tests/snapshots/tests.integrations.symfony.v2_3.route_name_test.test_resource_to_uri_mapping.json b/tests/snapshots/tests.integrations.symfony.v2_3.route_name_test.test_resource_to_uri_mapping.json index 420610342c..d4f1d5e20f 100644 --- a/tests/snapshots/tests.integrations.symfony.v2_3.route_name_test.test_resource_to_uri_mapping.json +++ b/tests/snapshots/tests.integrations.symfony.v2_3.route_name_test.test_resource_to_uri_mapping.json @@ -20,6 +20,7 @@ "symfony.route.name": "homepage" }, "metrics": { + "_dd.top_level": 1.0, "_sampling_priority_v1": 1.0 } }, diff --git a/tests/snapshots/tests.integrations.symfony.v2_8.common_scenarios_test.test_scenario_get_return_string.json b/tests/snapshots/tests.integrations.symfony.v2_8.common_scenarios_test.test_scenario_get_return_string.json index a0a9c47464..c15e1da0b3 100644 --- a/tests/snapshots/tests.integrations.symfony.v2_8.common_scenarios_test.test_scenario_get_return_string.json +++ b/tests/snapshots/tests.integrations.symfony.v2_8.common_scenarios_test.test_scenario_get_return_string.json @@ -20,6 +20,7 @@ "symfony.route.name": "simple" }, "metrics": { + "_dd.top_level": 1.0, "_sampling_priority_v1": 1.0 } }, diff --git a/tests/snapshots/tests.integrations.symfony.v2_8.common_scenarios_test.test_scenario_get_to_missing_route.json b/tests/snapshots/tests.integrations.symfony.v2_8.common_scenarios_test.test_scenario_get_to_missing_route.json index 62625f3580..9d96bd5655 100644 --- a/tests/snapshots/tests.integrations.symfony.v2_8.common_scenarios_test.test_scenario_get_to_missing_route.json +++ b/tests/snapshots/tests.integrations.symfony.v2_8.common_scenarios_test.test_scenario_get_to_missing_route.json @@ -19,6 +19,7 @@ "symfony.route.action": "Symfony\\Bundle\\TwigBundle\\Controller\\ExceptionController@showAction" }, "metrics": { + "_dd.top_level": 1.0, "_sampling_priority_v1": 1.0 } }, diff --git a/tests/snapshots/tests.integrations.symfony.v2_8.common_scenarios_test.test_scenario_get_with_exception.json b/tests/snapshots/tests.integrations.symfony.v2_8.common_scenarios_test.test_scenario_get_with_exception.json index ae304477a0..ef36dad8b7 100644 --- a/tests/snapshots/tests.integrations.symfony.v2_8.common_scenarios_test.test_scenario_get_with_exception.json +++ b/tests/snapshots/tests.integrations.symfony.v2_8.common_scenarios_test.test_scenario_get_with_exception.json @@ -24,6 +24,7 @@ "symfony.route.name": "error" }, "metrics": { + "_dd.top_level": 1.0, "_sampling_priority_v1": 1.0 } }, diff --git a/tests/snapshots/tests.integrations.symfony.v2_8.common_scenarios_test.test_scenario_get_with_view.json b/tests/snapshots/tests.integrations.symfony.v2_8.common_scenarios_test.test_scenario_get_with_view.json index 37bea1d81a..9820815941 100644 --- a/tests/snapshots/tests.integrations.symfony.v2_8.common_scenarios_test.test_scenario_get_with_view.json +++ b/tests/snapshots/tests.integrations.symfony.v2_8.common_scenarios_test.test_scenario_get_with_view.json @@ -20,6 +20,7 @@ "symfony.route.name": "simple_view" }, "metrics": { + "_dd.top_level": 1.0, "_sampling_priority_v1": 1.0 } }, diff --git a/tests/snapshots/tests.integrations.symfony.v2_8.route_name_test.test_resource_to_uri_mapping.json b/tests/snapshots/tests.integrations.symfony.v2_8.route_name_test.test_resource_to_uri_mapping.json index f6586cf06a..0dd4c90ea1 100644 --- a/tests/snapshots/tests.integrations.symfony.v2_8.route_name_test.test_resource_to_uri_mapping.json +++ b/tests/snapshots/tests.integrations.symfony.v2_8.route_name_test.test_resource_to_uri_mapping.json @@ -20,6 +20,7 @@ "symfony.route.name": "homepage" }, "metrics": { + "_dd.top_level": 1.0, "_sampling_priority_v1": 1.0 } }, diff --git a/tests/snapshots/tests.integrations.symfony.v7_3.common_scenarios_test.test_scenario_get_to_missing_route.json b/tests/snapshots/tests.integrations.symfony.v7_3.common_scenarios_test.test_scenario_get_to_missing_route.json index cbebb8fe4e..19a6a3fe29 100644 --- a/tests/snapshots/tests.integrations.symfony.v7_3.common_scenarios_test.test_scenario_get_to_missing_route.json +++ b/tests/snapshots/tests.integrations.symfony.v7_3.common_scenarios_test.test_scenario_get_to_missing_route.json @@ -18,6 +18,7 @@ "span.kind": "server" }, "metrics": { + "_dd.top_level": 1.0, "_sampling_priority_v1": 1.0 } }, diff --git a/tests/snapshots/tests.integrations.symfony.v7_3.messenger_test.test_async_success_consumer.json b/tests/snapshots/tests.integrations.symfony.v7_3.messenger_test.test_async_success_consumer.json index 91884722f8..48dd448141 100644 --- a/tests/snapshots/tests.integrations.symfony.v7_3.messenger_test.test_async_success_consumer.json +++ b/tests/snapshots/tests.integrations.symfony.v7_3.messenger_test.test_async_success_consumer.json @@ -25,6 +25,7 @@ "span.kind": "consumer" }, "metrics": { + "_dd.top_level": 1, "_sampling_priority_v1": 1 } }, @@ -275,6 +276,9 @@ "out.host": "mysql-integration", "out.port": "3306", "span.kind": "client" + }, + "metrics": { + "_dd.top_level": 1 } }, { @@ -302,6 +306,7 @@ "span.kind": "client" }, "metrics": { + "_dd.top_level": 1, "db.row_count": 1 } }]] diff --git a/tests/snapshots/tests.integrations.word_press.v4_8.common_scenarios_callbacks_test.test_scenario_get_return_string.json b/tests/snapshots/tests.integrations.word_press.v4_8.common_scenarios_callbacks_test.test_scenario_get_return_string.json index a94467e5ad..c52c1e95d4 100644 --- a/tests/snapshots/tests.integrations.word_press.v4_8.common_scenarios_callbacks_test.test_scenario_get_return_string.json +++ b/tests/snapshots/tests.integrations.word_press.v4_8.common_scenarios_callbacks_test.test_scenario_get_return_string.json @@ -19,6 +19,7 @@ "span.kind": "server" }, "metrics": { + "_dd.top_level": 1.0, "_sampling_priority_v1": 1.0 } }, diff --git a/tests/snapshots/tests.integrations.word_press.v4_8.common_scenarios_callbacks_test.test_scenario_get_with_exception.json b/tests/snapshots/tests.integrations.word_press.v4_8.common_scenarios_callbacks_test.test_scenario_get_with_exception.json index 942275e999..df402ca4e8 100644 --- a/tests/snapshots/tests.integrations.word_press.v4_8.common_scenarios_callbacks_test.test_scenario_get_with_exception.json +++ b/tests/snapshots/tests.integrations.word_press.v4_8.common_scenarios_callbacks_test.test_scenario_get_with_exception.json @@ -23,6 +23,7 @@ "span.kind": "server" }, "metrics": { + "_dd.top_level": 1.0, "_sampling_priority_v1": 1.0 } }, diff --git a/tests/snapshots/tests.integrations.word_press.v4_8.common_scenarios_callbacks_test.test_scenario_get_with_view.json b/tests/snapshots/tests.integrations.word_press.v4_8.common_scenarios_callbacks_test.test_scenario_get_with_view.json index 4cea0bce0d..10973e8ec5 100644 --- a/tests/snapshots/tests.integrations.word_press.v4_8.common_scenarios_callbacks_test.test_scenario_get_with_view.json +++ b/tests/snapshots/tests.integrations.word_press.v4_8.common_scenarios_callbacks_test.test_scenario_get_with_view.json @@ -19,6 +19,7 @@ "span.kind": "server" }, "metrics": { + "_dd.top_level": 1.0, "_sampling_priority_v1": 1.0 } }, diff --git a/tests/snapshots/tests.integrations.word_press.v4_8.common_scenarios_test.test_scenario_get_return_string.json b/tests/snapshots/tests.integrations.word_press.v4_8.common_scenarios_test.test_scenario_get_return_string.json index 34e87afcbd..a5cc6c32ea 100644 --- a/tests/snapshots/tests.integrations.word_press.v4_8.common_scenarios_test.test_scenario_get_return_string.json +++ b/tests/snapshots/tests.integrations.word_press.v4_8.common_scenarios_test.test_scenario_get_return_string.json @@ -19,6 +19,7 @@ "span.kind": "server" }, "metrics": { + "_dd.top_level": 1.0, "_sampling_priority_v1": 1.0 } }, diff --git a/tests/snapshots/tests.integrations.word_press.v4_8.common_scenarios_test.test_scenario_get_with_exception.json b/tests/snapshots/tests.integrations.word_press.v4_8.common_scenarios_test.test_scenario_get_with_exception.json index ad6b699998..d1fa968638 100644 --- a/tests/snapshots/tests.integrations.word_press.v4_8.common_scenarios_test.test_scenario_get_with_exception.json +++ b/tests/snapshots/tests.integrations.word_press.v4_8.common_scenarios_test.test_scenario_get_with_exception.json @@ -23,6 +23,7 @@ "span.kind": "server" }, "metrics": { + "_dd.top_level": 1.0, "_sampling_priority_v1": 1.0 } }, diff --git a/tests/snapshots/tests.integrations.word_press.v4_8.common_scenarios_test.test_scenario_get_with_view.json b/tests/snapshots/tests.integrations.word_press.v4_8.common_scenarios_test.test_scenario_get_with_view.json index 3da297ba27..2e742dc1a3 100644 --- a/tests/snapshots/tests.integrations.word_press.v4_8.common_scenarios_test.test_scenario_get_with_view.json +++ b/tests/snapshots/tests.integrations.word_press.v4_8.common_scenarios_test.test_scenario_get_with_view.json @@ -19,6 +19,7 @@ "span.kind": "server" }, "metrics": { + "_dd.top_level": 1.0, "_sampling_priority_v1": 1.0 } }, diff --git a/tests/snapshots/tests.integrations.word_press.v5_5.common_scenarios_callbacks_test.test_scenario_get_return_string.json b/tests/snapshots/tests.integrations.word_press.v5_5.common_scenarios_callbacks_test.test_scenario_get_return_string.json index 5fe007192c..3dcd49d072 100644 --- a/tests/snapshots/tests.integrations.word_press.v5_5.common_scenarios_callbacks_test.test_scenario_get_return_string.json +++ b/tests/snapshots/tests.integrations.word_press.v5_5.common_scenarios_callbacks_test.test_scenario_get_return_string.json @@ -19,6 +19,7 @@ "span.kind": "server" }, "metrics": { + "_dd.top_level": 1.0, "_sampling_priority_v1": 1.0 } }, diff --git a/tests/snapshots/tests.integrations.word_press.v5_5.common_scenarios_callbacks_test.test_scenario_get_to_missing_route.json b/tests/snapshots/tests.integrations.word_press.v5_5.common_scenarios_callbacks_test.test_scenario_get_to_missing_route.json index 2f1cd43bf7..71457ff117 100644 --- a/tests/snapshots/tests.integrations.word_press.v5_5.common_scenarios_callbacks_test.test_scenario_get_to_missing_route.json +++ b/tests/snapshots/tests.integrations.word_press.v5_5.common_scenarios_callbacks_test.test_scenario_get_to_missing_route.json @@ -18,6 +18,7 @@ "span.kind": "server" }, "metrics": { + "_dd.top_level": 1.0, "_sampling_priority_v1": 1.0 } }, diff --git a/tests/snapshots/tests.integrations.word_press.v5_5.common_scenarios_callbacks_test.test_scenario_get_with_exception.json b/tests/snapshots/tests.integrations.word_press.v5_5.common_scenarios_callbacks_test.test_scenario_get_with_exception.json index 323e0bbfd2..fa19089685 100644 --- a/tests/snapshots/tests.integrations.word_press.v5_5.common_scenarios_callbacks_test.test_scenario_get_with_exception.json +++ b/tests/snapshots/tests.integrations.word_press.v5_5.common_scenarios_callbacks_test.test_scenario_get_with_exception.json @@ -23,6 +23,7 @@ "span.kind": "server" }, "metrics": { + "_dd.top_level": 1.0, "_sampling_priority_v1": 1.0 } }, diff --git a/tests/snapshots/tests.integrations.word_press.v5_5.common_scenarios_callbacks_test.test_scenario_get_with_view.json b/tests/snapshots/tests.integrations.word_press.v5_5.common_scenarios_callbacks_test.test_scenario_get_with_view.json index f74b08cfaf..e88095a347 100644 --- a/tests/snapshots/tests.integrations.word_press.v5_5.common_scenarios_callbacks_test.test_scenario_get_with_view.json +++ b/tests/snapshots/tests.integrations.word_press.v5_5.common_scenarios_callbacks_test.test_scenario_get_with_view.json @@ -19,6 +19,7 @@ "span.kind": "server" }, "metrics": { + "_dd.top_level": 1.0, "_sampling_priority_v1": 1.0 } }, diff --git a/tests/snapshots/tests.integrations.word_press.v5_5.common_scenarios_test.test_scenario_get_return_string.json b/tests/snapshots/tests.integrations.word_press.v5_5.common_scenarios_test.test_scenario_get_return_string.json index b2cc305f4f..d53181a322 100644 --- a/tests/snapshots/tests.integrations.word_press.v5_5.common_scenarios_test.test_scenario_get_return_string.json +++ b/tests/snapshots/tests.integrations.word_press.v5_5.common_scenarios_test.test_scenario_get_return_string.json @@ -19,6 +19,7 @@ "span.kind": "server" }, "metrics": { + "_dd.top_level": 1.0, "_sampling_priority_v1": 1.0 } }, diff --git a/tests/snapshots/tests.integrations.word_press.v5_5.common_scenarios_test.test_scenario_get_to_missing_route.json b/tests/snapshots/tests.integrations.word_press.v5_5.common_scenarios_test.test_scenario_get_to_missing_route.json index 80cf347caa..655799c0e5 100644 --- a/tests/snapshots/tests.integrations.word_press.v5_5.common_scenarios_test.test_scenario_get_to_missing_route.json +++ b/tests/snapshots/tests.integrations.word_press.v5_5.common_scenarios_test.test_scenario_get_to_missing_route.json @@ -18,6 +18,7 @@ "span.kind": "server" }, "metrics": { + "_dd.top_level": 1.0, "_sampling_priority_v1": 1.0 } }, diff --git a/tests/snapshots/tests.integrations.word_press.v5_5.common_scenarios_test.test_scenario_get_with_exception.json b/tests/snapshots/tests.integrations.word_press.v5_5.common_scenarios_test.test_scenario_get_with_exception.json index 310b142ac5..d40c587ac1 100644 --- a/tests/snapshots/tests.integrations.word_press.v5_5.common_scenarios_test.test_scenario_get_with_exception.json +++ b/tests/snapshots/tests.integrations.word_press.v5_5.common_scenarios_test.test_scenario_get_with_exception.json @@ -23,6 +23,7 @@ "span.kind": "server" }, "metrics": { + "_dd.top_level": 1.0, "_sampling_priority_v1": 1.0 } }, diff --git a/tests/snapshots/tests.integrations.word_press.v5_5.common_scenarios_test.test_scenario_get_with_view.json b/tests/snapshots/tests.integrations.word_press.v5_5.common_scenarios_test.test_scenario_get_with_view.json index ca8d5fe134..f306df4b01 100644 --- a/tests/snapshots/tests.integrations.word_press.v5_5.common_scenarios_test.test_scenario_get_with_view.json +++ b/tests/snapshots/tests.integrations.word_press.v5_5.common_scenarios_test.test_scenario_get_with_view.json @@ -19,6 +19,7 @@ "span.kind": "server" }, "metrics": { + "_dd.top_level": 1.0, "_sampling_priority_v1": 1.0 } }, diff --git a/tests/snapshots/tests.integrations.word_press.v5_9.common_scenarios_callbacks_test.test_scenario_get_return_string.json b/tests/snapshots/tests.integrations.word_press.v5_9.common_scenarios_callbacks_test.test_scenario_get_return_string.json index ebfef74a26..364428dd2f 100644 --- a/tests/snapshots/tests.integrations.word_press.v5_9.common_scenarios_callbacks_test.test_scenario_get_return_string.json +++ b/tests/snapshots/tests.integrations.word_press.v5_9.common_scenarios_callbacks_test.test_scenario_get_return_string.json @@ -19,6 +19,7 @@ "span.kind": "server" }, "metrics": { + "_dd.top_level": 1.0, "_sampling_priority_v1": 1.0 } }, diff --git a/tests/snapshots/tests.integrations.word_press.v5_9.common_scenarios_callbacks_test.test_scenario_get_to_missing_route.json b/tests/snapshots/tests.integrations.word_press.v5_9.common_scenarios_callbacks_test.test_scenario_get_to_missing_route.json index 9aecdba4a4..fcbfbed2a6 100644 --- a/tests/snapshots/tests.integrations.word_press.v5_9.common_scenarios_callbacks_test.test_scenario_get_to_missing_route.json +++ b/tests/snapshots/tests.integrations.word_press.v5_9.common_scenarios_callbacks_test.test_scenario_get_to_missing_route.json @@ -18,6 +18,7 @@ "span.kind": "server" }, "metrics": { + "_dd.top_level": 1.0, "_sampling_priority_v1": 1.0 } }, diff --git a/tests/snapshots/tests.integrations.word_press.v5_9.common_scenarios_callbacks_test.test_scenario_get_with_exception.json b/tests/snapshots/tests.integrations.word_press.v5_9.common_scenarios_callbacks_test.test_scenario_get_with_exception.json index 27319620a3..c75d2591f7 100644 --- a/tests/snapshots/tests.integrations.word_press.v5_9.common_scenarios_callbacks_test.test_scenario_get_with_exception.json +++ b/tests/snapshots/tests.integrations.word_press.v5_9.common_scenarios_callbacks_test.test_scenario_get_with_exception.json @@ -23,6 +23,7 @@ "span.kind": "server" }, "metrics": { + "_dd.top_level": 1.0, "_sampling_priority_v1": 1.0 } }, diff --git a/tests/snapshots/tests.integrations.word_press.v5_9.common_scenarios_callbacks_test.test_scenario_get_with_view.json b/tests/snapshots/tests.integrations.word_press.v5_9.common_scenarios_callbacks_test.test_scenario_get_with_view.json index 683d022d4e..4cebcc1c97 100644 --- a/tests/snapshots/tests.integrations.word_press.v5_9.common_scenarios_callbacks_test.test_scenario_get_with_view.json +++ b/tests/snapshots/tests.integrations.word_press.v5_9.common_scenarios_callbacks_test.test_scenario_get_with_view.json @@ -19,6 +19,7 @@ "span.kind": "server" }, "metrics": { + "_dd.top_level": 1.0, "_sampling_priority_v1": 1.0 } }, diff --git a/tests/snapshots/tests.integrations.word_press.v5_9.common_scenarios_test.test_scenario_get_return_string.json b/tests/snapshots/tests.integrations.word_press.v5_9.common_scenarios_test.test_scenario_get_return_string.json index a2f281d70d..c770960965 100644 --- a/tests/snapshots/tests.integrations.word_press.v5_9.common_scenarios_test.test_scenario_get_return_string.json +++ b/tests/snapshots/tests.integrations.word_press.v5_9.common_scenarios_test.test_scenario_get_return_string.json @@ -19,6 +19,7 @@ "span.kind": "server" }, "metrics": { + "_dd.top_level": 1.0, "_sampling_priority_v1": 1.0 } }, diff --git a/tests/snapshots/tests.integrations.word_press.v5_9.common_scenarios_test.test_scenario_get_to_missing_route.json b/tests/snapshots/tests.integrations.word_press.v5_9.common_scenarios_test.test_scenario_get_to_missing_route.json index 29e5c09037..30aa12bb9d 100644 --- a/tests/snapshots/tests.integrations.word_press.v5_9.common_scenarios_test.test_scenario_get_to_missing_route.json +++ b/tests/snapshots/tests.integrations.word_press.v5_9.common_scenarios_test.test_scenario_get_to_missing_route.json @@ -18,6 +18,7 @@ "span.kind": "server" }, "metrics": { + "_dd.top_level": 1.0, "_sampling_priority_v1": 1.0 } }, diff --git a/tests/snapshots/tests.integrations.word_press.v5_9.common_scenarios_test.test_scenario_get_with_exception.json b/tests/snapshots/tests.integrations.word_press.v5_9.common_scenarios_test.test_scenario_get_with_exception.json index c982920760..25c068123f 100644 --- a/tests/snapshots/tests.integrations.word_press.v5_9.common_scenarios_test.test_scenario_get_with_exception.json +++ b/tests/snapshots/tests.integrations.word_press.v5_9.common_scenarios_test.test_scenario_get_with_exception.json @@ -23,6 +23,7 @@ "span.kind": "server" }, "metrics": { + "_dd.top_level": 1.0, "_sampling_priority_v1": 1.0 } }, diff --git a/tests/snapshots/tests.integrations.word_press.v5_9.common_scenarios_test.test_scenario_get_with_view.json b/tests/snapshots/tests.integrations.word_press.v5_9.common_scenarios_test.test_scenario_get_with_view.json index 671eb3f7d1..646e2faeb8 100644 --- a/tests/snapshots/tests.integrations.word_press.v5_9.common_scenarios_test.test_scenario_get_with_view.json +++ b/tests/snapshots/tests.integrations.word_press.v5_9.common_scenarios_test.test_scenario_get_with_view.json @@ -19,6 +19,7 @@ "span.kind": "server" }, "metrics": { + "_dd.top_level": 1.0, "_sampling_priority_v1": 1.0 } }, diff --git a/tests/snapshots/tests.integrations.word_press.v6_1.common_scenarios_callbacks_test.test_scenario_get_return_string.json b/tests/snapshots/tests.integrations.word_press.v6_1.common_scenarios_callbacks_test.test_scenario_get_return_string.json index d965665100..dd042c501f 100644 --- a/tests/snapshots/tests.integrations.word_press.v6_1.common_scenarios_callbacks_test.test_scenario_get_return_string.json +++ b/tests/snapshots/tests.integrations.word_press.v6_1.common_scenarios_callbacks_test.test_scenario_get_return_string.json @@ -19,6 +19,7 @@ "span.kind": "server" }, "metrics": { + "_dd.top_level": 1.0, "_sampling_priority_v1": 1.0 } }, diff --git a/tests/snapshots/tests.integrations.word_press.v6_1.common_scenarios_callbacks_test.test_scenario_get_with_exception.json b/tests/snapshots/tests.integrations.word_press.v6_1.common_scenarios_callbacks_test.test_scenario_get_with_exception.json index 10673208e8..05a84d8a3a 100644 --- a/tests/snapshots/tests.integrations.word_press.v6_1.common_scenarios_callbacks_test.test_scenario_get_with_exception.json +++ b/tests/snapshots/tests.integrations.word_press.v6_1.common_scenarios_callbacks_test.test_scenario_get_with_exception.json @@ -23,6 +23,7 @@ "span.kind": "server" }, "metrics": { + "_dd.top_level": 1.0, "_sampling_priority_v1": 1.0 } }, diff --git a/tests/snapshots/tests.integrations.word_press.v6_1.common_scenarios_callbacks_test.test_scenario_get_with_view.json b/tests/snapshots/tests.integrations.word_press.v6_1.common_scenarios_callbacks_test.test_scenario_get_with_view.json index e055001b0c..991fad422c 100644 --- a/tests/snapshots/tests.integrations.word_press.v6_1.common_scenarios_callbacks_test.test_scenario_get_with_view.json +++ b/tests/snapshots/tests.integrations.word_press.v6_1.common_scenarios_callbacks_test.test_scenario_get_with_view.json @@ -19,6 +19,7 @@ "span.kind": "server" }, "metrics": { + "_dd.top_level": 1.0, "_sampling_priority_v1": 1.0 } }, diff --git a/tests/snapshots/tests.integrations.word_press.v6_1.common_scenarios_test.test_scenario_get_return_string.json b/tests/snapshots/tests.integrations.word_press.v6_1.common_scenarios_test.test_scenario_get_return_string.json index cfbeb419d9..256570c379 100644 --- a/tests/snapshots/tests.integrations.word_press.v6_1.common_scenarios_test.test_scenario_get_return_string.json +++ b/tests/snapshots/tests.integrations.word_press.v6_1.common_scenarios_test.test_scenario_get_return_string.json @@ -19,6 +19,7 @@ "span.kind": "server" }, "metrics": { + "_dd.top_level": 1.0, "_sampling_priority_v1": 1.0 } }, diff --git a/tests/snapshots/tests.integrations.word_press.v6_1.common_scenarios_test.test_scenario_get_with_exception.json b/tests/snapshots/tests.integrations.word_press.v6_1.common_scenarios_test.test_scenario_get_with_exception.json index 76919c4227..2f3d6240e0 100644 --- a/tests/snapshots/tests.integrations.word_press.v6_1.common_scenarios_test.test_scenario_get_with_exception.json +++ b/tests/snapshots/tests.integrations.word_press.v6_1.common_scenarios_test.test_scenario_get_with_exception.json @@ -23,6 +23,7 @@ "span.kind": "server" }, "metrics": { + "_dd.top_level": 1.0, "_sampling_priority_v1": 1.0 } }, diff --git a/tests/snapshots/tests.integrations.word_press.v6_1.common_scenarios_test.test_scenario_get_with_view.json b/tests/snapshots/tests.integrations.word_press.v6_1.common_scenarios_test.test_scenario_get_with_view.json index 4b9c200068..a884b778df 100644 --- a/tests/snapshots/tests.integrations.word_press.v6_1.common_scenarios_test.test_scenario_get_with_view.json +++ b/tests/snapshots/tests.integrations.word_press.v6_1.common_scenarios_test.test_scenario_get_with_view.json @@ -19,6 +19,7 @@ "span.kind": "server" }, "metrics": { + "_dd.top_level": 1.0, "_sampling_priority_v1": 1.0 } }, From 2849dd3b769b70b5727e39262cbc7c512aabaa5c Mon Sep 17 00:00:00 2001 From: Alexandre Rulleau Date: Thu, 1 Oct 2026 18:02:52 +0200 Subject: [PATCH 4/5] ci(request-replayer): decode the V1 trace payload Add a msgpack V1 decoder to the request-replayer and advertise /v1.0/traces in its /info, so the PHP test suite can inspect V1 payloads. Move the CI service to the 5.0 image and force-pull the Windows service images so a runner with a stale cached digest does not skip a rebuilt image. --- .gitlab/generate-common.php | 2 +- .gitlab/generate-tracer.php | 4 +- dockerfiles/services/.env | 2 +- .../services/request-replayer/src/index.php | 31 +- .../src/msgpack_v1_decoder.php | 620 ++++++++++++++++++ 5 files changed, 652 insertions(+), 7 deletions(-) create mode 100644 dockerfiles/services/request-replayer/src/msgpack_v1_decoder.php diff --git a/.gitlab/generate-common.php b/.gitlab/generate-common.php index 82a79c8e7d..b31ac4309b 100644 --- a/.gitlab/generate-common.php +++ b/.gitlab/generate-common.php @@ -230,7 +230,7 @@ function windows_git_setup_with_packages() { KUBERNETES_SERVICE_MEMORY_LIMIT: 1Gi request-replayer: - name: registry.ddbuild.io/ci/dd-trace-php/request-replayer:4.0 + name: registry.ddbuild.io/ci/dd-trace-php/request-replayer:5.0 alias: request-replayer command: ["php", "-S", ":80", "index.php"] variables: diff --git a/.gitlab/generate-tracer.php b/.gitlab/generate-tracer.php index 8d9e2c6cc6..b7d27347c7 100644 --- a/.gitlab/generate-tracer.php +++ b/.gitlab/generate-tracer.php @@ -137,7 +137,10 @@ function windows_test_c_job($job_name, $thread_safety, $targets) { # Start the container network and services docker network create -d "nat" -o com.docker.network.windowsshim.dnsservers="1.1.1.1" net + # Force a pull so a runner with a stale cached digest doesn't skip the rebuilt image. + docker pull registry.ddbuild.io/images/mirror/datadog/dd-trace-ci:httpbin-windows docker run --network net -d --name httpbin-integration registry.ddbuild.io/images/mirror/datadog/dd-trace-ci:httpbin-windows + docker pull registry.ddbuild.io/ci/dd-trace-php/dd-trace-ci:php-request-replayer-3.0_windows docker run --network net -d --name request-replayer registry.ddbuild.io/ci/dd-trace-php/dd-trace-ci:php-request-replayer-3.0_windows docker run --env GITLAB_CI=$env:GITLAB_CI -v ${pwd}:C:\Users\ContainerAdministrator\app --network net -d --name ${CONTAINER_NAME} ${IMAGE} ping -t localhost @@ -681,7 +684,6 @@ function windows_test_c_job($job_name, $thread_safety, $targets) { ARCH: "amd64" DD_TRACE_STARTUP_LOGS: "0" DD_TRACE_WARN_CALL_STACK_DEPTH: "0" - DD_TRACE_WARN_LEGACY_DD_TRACE: "0" DD_TRACE_GIT_METADATA_ENABLED: "0" REPORT_EXIT_STATUS: "1" TEST_PHP_JUNIT: "${CI_PROJECT_DIR}/artifacts/tests/php-tests.xml" diff --git a/dockerfiles/services/.env b/dockerfiles/services/.env index d8351f3882..0821a222f0 100644 --- a/dockerfiles/services/.env +++ b/dockerfiles/services/.env @@ -1 +1 @@ -REQUEST_REPLAYER_VERSION=4.0 +REQUEST_REPLAYER_VERSION=5.0 diff --git a/dockerfiles/services/request-replayer/src/index.php b/dockerfiles/services/request-replayer/src/index.php index 257403b9af..55bc865278 100644 --- a/dockerfiles/services/request-replayer/src/index.php +++ b/dockerfiles/services/request-replayer/src/index.php @@ -48,6 +48,9 @@ function decodeDogStatsDMetrics($metrics) return $decodedMetrics; } +// v1 (`/v1.0/traces`) msgpack decoder, normalizing to the v0.4 per-span view. +require __DIR__ . '/msgpack_v1_decoder.php'; + $uri = explode("?", $_SERVER['REQUEST_URI'])[0]; $temp_location = sys_get_temp_dir(); @@ -337,8 +340,22 @@ function logRequest($message, $data = '') }); break; case '/info': - $file = withRequestReplayerStateLock(REQUEST_STATE_LOCK_FILE, function () { - return @file_get_contents(REQUEST_AGENT_INFO_FILE) ?: "{}"; + // Default advertises /v1.0/traces so both senders negotiate the v1 wire. Tests needing a + // specific /info override it via /set-agent-info (that file is served verbatim). + $default_info = json_encode([ + "endpoints" => [ + "/v0.4/traces", + "/v0.6/stats", + "/v0.7/config", + "/v1.0/traces", + "/telemetry/proxy/", + "/evp_proxy/v2/", + ], + "client_drop_p0s" => false, + "version" => "7.66.0", + ], JSON_UNESCAPED_SLASHES); + $file = withRequestReplayerStateLock(REQUEST_STATE_LOCK_FILE, function () use ($default_info) { + return @file_get_contents(REQUEST_AGENT_INFO_FILE) ?: $default_info; }); logRequest('Requested /info endpoint, returning ' . $file); header("datadog-agent-state: " . sha1($file)); @@ -394,8 +411,14 @@ function logRequest($message, $data = '') } } else { $raw = file_get_contents('php://input'); - if ((isset($headers['Content-Type']) && $headers['Content-Type'] === 'application/msgpack') - || (isset($headers['content-type']) && $headers['content-type'] === 'application/msgpack')) { + $isMsgpack = (isset($headers['Content-Type']) && $headers['Content-Type'] === 'application/msgpack') + || (isset($headers['content-type']) && $headers['content-type'] === 'application/msgpack'); + if ($isMsgpack && substr($uri, -strlen('/v1.0/traces')) === '/v1.0/traces') { + // v1 (`/v1.0/traces`) wire: integer keys, streaming string table, typed AnyValue. + // Normalize it back to the canonical v0.4 per-span view the PHPUnit tests read. + $decoder = new V1TraceDecoder($raw); + $body = json_encode($decoder->decode()); + } elseif ($isMsgpack) { // We unpack in two phases: // 1) using UnpackOptions::BIGINT_AS_GMP and only asserting that trace_id, span_id and parent_id are either // integers (when <= PHP_INT_MAX) or GMP (when > PHP_INT_MAX); diff --git a/dockerfiles/services/request-replayer/src/msgpack_v1_decoder.php b/dockerfiles/services/request-replayer/src/msgpack_v1_decoder.php new file mode 100644 index 0000000000..fe9191e0bb --- /dev/null +++ b/dockerfiles/services/request-replayer/src/msgpack_v1_decoder.php @@ -0,0 +1,620 @@ +buf = $buf; + $this->len = strlen($buf); + } + + /** Decodes the whole payload into the v0.4-shaped `{"chunks":[...]}` PHP array. */ + public function decode() + { + $chunks = []; + $payloadAttributes = []; + $mapLen = $this->readMapLen(); + for ($i = 0; $i < $mapLen; $i++) { + $key = $this->readUint(); + switch ($key) { + case self::TRACE_CHUNKS: + $count = $this->readArrayLen(); + for ($c = 0; $c < $count; $c++) { + $chunks[] = $this->decodeChunk(); + } + break; + case self::TRACE_ATTRIBUTES: + // Payload-level attributes (e.g. _dd.apm_mode) are not part of the per-span view, + // except process tags, which v0.4 carries on each trace's first span. + $payloadAttributes = $this->readAttributesMap(); + break; + default: + // container_id/language/version/runtime_id/env/hostname/app_version and any + // future/unknown key: interned string or arbitrary value, skip it. + $this->skipValue(); + break; + } + } + if (isset($payloadAttributes['_dd.tags.process'])) { + foreach ($chunks as &$chunk) { + if (!empty($chunk['spans'])) { + $chunk['spans'][0]['meta']['_dd.tags.process'] = $payloadAttributes['_dd.tags.process']; + } + } + unset($chunk); + } + return ['chunks' => $chunks]; + } + + private function decodeChunk() + { + $traceIdBytes = null; + $origin = null; + $priority = null; + $samplingMechanism = null; + $spans = []; + + $mapLen = $this->readMapLen(); + for ($i = 0; $i < $mapLen; $i++) { + $key = $this->readUint(); + switch ($key) { + case self::CHUNK_TRACE_ID: + $traceIdBytes = $this->readBin(); + break; + case self::CHUNK_SPANS: + $count = $this->readArrayLen(); + for ($s = 0; $s < $count; $s++) { + $spans[] = $this->decodeSpan(); + } + break; + case self::CHUNK_ORIGIN: + $origin = $this->readInterned(); + break; + case self::CHUNK_PRIORITY: + $priority = $this->readInt(); + break; + case self::CHUNK_SAMPLING_MECHANISM: + $samplingMechanism = $this->readUint(); + break; + case self::CHUNK_ATTRIBUTES: + // Chunk-level attributes have no per-span v0.4 home; drain them. + $this->readAttributesMap(); + break; + case self::CHUNK_DROPPED_TRACE: + $this->readBool(); + break; + default: + $this->skipValue(); + break; + } + } + + // Reconstruct the 128-bit trace id. The low 64 bits go on every span; the high 64 bits, when + // non-zero, become meta['_dd.p.tid'] (hex) on the local-root span, mirroring the v0.4 wire. + $traceIdLow = "0"; + $traceIdTidHex = null; + if ($traceIdBytes !== null && strlen($traceIdBytes) === 16) { + $high = substr($traceIdBytes, 0, 8); + $low = substr($traceIdBytes, 8, 8); + $traceIdLow = $this->bytesToDecimal($low); + if ($high !== "\0\0\0\0\0\0\0\0") { + $traceIdTidHex = bin2hex($high); + } + } + + foreach ($spans as &$span) { + $span['trace_id'] = $traceIdLow; + } + unset($span); + + // Place the chunk-level, root-scoped propagation fields on the local-root span (the span with + // no parent, else the one flagged _dd.top_level, else the first span) — the v0.4 layout. + if (!empty($spans)) { + $rootIdx = $this->findRootSpanIndex($spans); + if ($traceIdTidHex !== null) { + $spans[$rootIdx]['meta']['_dd.p.tid'] = $traceIdTidHex; + } + if ($origin !== null) { + $spans[$rootIdx]['meta']['_dd.origin'] = $origin; + } + if ($samplingMechanism !== null) { + // v0.4 stores the decision maker as "-". + $spans[$rootIdx]['meta']['_dd.p.dm'] = "-" . $samplingMechanism; + } + if ($priority !== null) { + $spans[$rootIdx]['metrics']['_sampling_priority_v1'] = $priority; + } + } + + // Drop empty meta/metrics/meta_struct so json_encode matches the v0.4 shape (absent, not {}). + foreach ($spans as &$span) { + foreach (['meta', 'metrics', 'meta_struct'] as $k) { + if (isset($span[$k]) && count($span[$k]) === 0) { + unset($span[$k]); + } + } + } + unset($span); + + return ['spans' => $spans]; + } + + private function findRootSpanIndex(array $spans) + { + foreach ($spans as $idx => $span) { + if (!isset($span['parent_id']) || $span['parent_id'] === "0") { + return $idx; + } + } + foreach ($spans as $idx => $span) { + if (isset($span['metrics']['_dd.top_level']) && (float)$span['metrics']['_dd.top_level'] == 1.0) { + return $idx; + } + } + return 0; + } + + private function decodeSpan() + { + $span = [ + 'trace_id' => "0", + 'span_id' => "0", + 'parent_id' => "0", + 'name' => "", + 'resource' => "", + 'service' => "", + 'error' => 0, + 'meta' => [], + 'metrics' => [], + ]; + $metaStruct = []; + $kind = null; + $links = null; + $events = null; + + $mapLen = $this->readMapLen(); + for ($i = 0; $i < $mapLen; $i++) { + $key = $this->readUint(); + switch ($key) { + case self::SPAN_SERVICE: $span['service'] = $this->readInterned(); break; + case self::SPAN_NAME: $span['name'] = $this->readInterned(); break; + case self::SPAN_RESOURCE: $span['resource'] = $this->readInterned(); break; + case self::SPAN_SPAN_ID: $span['span_id'] = (string)$this->readUint(); break; + case self::SPAN_PARENT_ID:$span['parent_id'] = (string)$this->readUint(); break; + case self::SPAN_START: $span['start'] = $this->readUint(); break; + case self::SPAN_DURATION: $span['duration'] = $this->readUint(); break; + case self::SPAN_ERROR: $span['error'] = $this->readBool() ? 1 : 0; break; + case self::SPAN_TYPE: $span['type'] = $this->readInterned(); break; + case self::SPAN_ATTRIBUTES: + $this->readSpanAttributes($span['meta'], $span['metrics'], $metaStruct); + break; + case self::SPAN_LINKS: $links = $this->readSpanLinks(); break; + case self::SPAN_EVENTS: $events = $this->readSpanEvents(); break; + case self::SPAN_ENV: $span['meta']['env'] = $this->readInterned(); break; + case self::SPAN_VERSION: $span['meta']['version'] = $this->readInterned(); break; + case self::SPAN_COMPONENT:$span['meta']['component'] = $this->readInterned(); break; + case self::SPAN_KIND: $kind = $this->readUint(); break; + default: $this->skipValue(); break; + } + } + + // span.kind (uint) -> meta['span.kind'], as the v0.4 downgrade does; Unspecified (0, or the + // field absent) leaves no meta entry. + if ($kind !== null) { + $kindStr = $this->spanKindToStr($kind); + if ($kindStr !== null) { + $span['meta']['span.kind'] = $kindStr; + } + } + + if ($links !== null && !empty($links)) { + $span['meta']['_dd.span_links'] = json_encode($links, JSON_UNESCAPED_SLASHES); + } + if ($events !== null && !empty($events)) { + $span['meta']['events'] = json_encode($events, JSON_UNESCAPED_SLASHES); + } + + if (!empty($metaStruct)) { + $span['meta_struct'] = $metaStruct; + } + + return $span; + } + + private function spanKindToStr($kind) + { + switch ($kind) { + case 1: return "internal"; + case 2: return "server"; + case 3: return "client"; + case 4: return "producer"; + case 5: return "consumer"; + // 0 (Unspecified): no v0.4 meta entry. + default: return null; + } + } + + /** Splits the unified v1 attributes map into v0.4 meta (String), metrics (Int/Double) and + * meta_struct (Bytes). Bool/Array/KeyValueList (not emitted by the PHP tracer) fall back to a + * JSON string in meta so nothing is silently dropped. */ + private function readSpanAttributes(&$meta, &$metrics, &$metaStruct) + { + $n = $this->readArrayLen(); + if ($n % 3 !== 0) { + throw new \RuntimeException("v1 attributes flat array length $n is not a multiple of 3"); + } + $entries = intdiv($n, 3); + for ($i = 0; $i < $entries; $i++) { + $key = $this->readInterned(); + list($type, $value) = $this->readTypedValue(); + switch ($type) { + case self::ANY_STRING: + $meta[$key] = $value; + break; + case self::ANY_INT64: + case self::ANY_DOUBLE: + $metrics[$key] = $value; + break; + case self::ANY_BYTES: + $metaStruct[$key] = $value; + break; + case self::ANY_BOOL: + case self::ANY_ARRAY: + case self::ANY_KEY_VALUE_LIST: + default: + $meta[$key] = is_scalar($value) ? (string)$value : json_encode($value, JSON_UNESCAPED_SLASHES); + break; + } + } + } + + /** Reads a v1 attributes map into a plain associative array (used for link/event attributes). */ + private function readAttributesMap() + { + $out = []; + $n = $this->readArrayLen(); + if ($n % 3 !== 0) { + throw new \RuntimeException("v1 attributes flat array length $n is not a multiple of 3"); + } + $entries = intdiv($n, 3); + for ($i = 0; $i < $entries; $i++) { + $key = $this->readInterned(); + list(, $value) = $this->readTypedValue(); + $out[$key] = $value; + } + return $out; + } + + /** Reads `[type_uint8, value]`, returning [$type, $phpValue]. */ + private function readTypedValue() + { + $type = $this->readUint(); + switch ($type) { + case self::ANY_STRING: return [$type, $this->readInterned()]; + case self::ANY_BOOL: return [$type, $this->readBool()]; + case self::ANY_DOUBLE: return [$type, $this->readDouble()]; + case self::ANY_INT64: return [$type, $this->readInt()]; + case self::ANY_BYTES: return [$type, $this->readBin()]; + case self::ANY_ARRAY: + $n = $this->readArrayLen(); + if ($n % 2 !== 0) { + throw new \RuntimeException("v1 typed array length $n is not a multiple of 2"); + } + $items = []; + for ($i = 0, $c = intdiv($n, 2); $i < $c; $i++) { + list(, $v) = $this->readTypedValue(); + $items[] = $v; + } + return [$type, $items]; + case self::ANY_KEY_VALUE_LIST: + return [$type, $this->readAttributesMap()]; + default: + throw new \RuntimeException("Unknown v1 AnyValue type discriminant: $type"); + } + } + + /** Native v1 span links -> the v0.4 `_dd.span_links` JSON element shape (trace_id 32-hex, + * span_id 16-hex, trace_state, attributes). */ + private function readSpanLinks() + { + $out = []; + $count = $this->readArrayLen(); + for ($i = 0; $i < $count; $i++) { + $link = []; + $traceIdHex = str_repeat("0", 32); + $spanIdHex = str_repeat("0", 16); + $traceState = ""; + $attributes = []; + $mapLen = $this->readMapLen(); + for ($j = 0; $j < $mapLen; $j++) { + $key = $this->readUint(); + switch ($key) { + case self::LINK_TRACE_ID: + $b = $this->readBin(); + $traceIdHex = str_pad(bin2hex($b), 32, "0", STR_PAD_LEFT); + break; + case self::LINK_SPAN_ID: + $spanIdHex = str_pad(dechex_gmp($this->readUint()), 16, "0", STR_PAD_LEFT); + break; + case self::LINK_ATTRIBUTES: + $attributes = $this->readAttributesMap(); + break; + case self::LINK_TRACE_STATE: + $traceState = $this->readInterned(); + break; + case self::LINK_FLAGS: + $this->readUint(); + break; + default: + $this->skipValue(); + break; + } + } + $link['trace_id'] = $traceIdHex; + $link['span_id'] = $spanIdHex; + if ($traceState !== "") { + $link['trace_state'] = $traceState; + } + if (!empty($attributes)) { + $link['attributes'] = $attributes; + } + $out[] = $link; + } + return $out; + } + + /** Native v1 span events -> the v0.4 `events` JSON element shape (name, time_unix_nano, + * attributes). */ + private function readSpanEvents() + { + $out = []; + $count = $this->readArrayLen(); + for ($i = 0; $i < $count; $i++) { + $event = []; + $mapLen = $this->readMapLen(); + for ($j = 0; $j < $mapLen; $j++) { + $key = $this->readUint(); + switch ($key) { + case self::EVENT_TIME: $event['time_unix_nano'] = $this->readUint(); break; + case self::EVENT_NAME: $event['name'] = $this->readInterned(); break; + case self::EVENT_ATTRIBUTES: $event['attributes'] = $this->readAttributesMap(); break; + default: $this->skipValue(); break; + } + } + $out[] = $event; + } + return $out; + } + + // --- streaming msgpack primitives ------------------------------------------------------------- + + private function peek() + { + if ($this->pos >= $this->len) { + throw new \RuntimeException("v1 decode: unexpected end of buffer"); + } + return ord($this->buf[$this->pos]); + } + + private function take($n) + { + if ($this->pos + $n > $this->len) { + throw new \RuntimeException("v1 decode: buffer truncated"); + } + $s = substr($this->buf, $this->pos, $n); + $this->pos += $n; + return $s; + } + + private function readMapLen() + { + $m = ord($this->take(1)); + if ($m >= 0x80 && $m <= 0x8f) return $m & 0x0f; + if ($m === 0xde) return $this->beUint($this->take(2)); + if ($m === 0xdf) return $this->beUint($this->take(4)); + throw new \RuntimeException(sprintf("v1 decode: expected map marker, got 0x%02x", $m)); + } + + private function readArrayLen() + { + $m = ord($this->take(1)); + if ($m >= 0x90 && $m <= 0x9f) return $m & 0x0f; + if ($m === 0xdc) return $this->beUint($this->take(2)); + if ($m === 0xdd) return $this->beUint($this->take(4)); + throw new \RuntimeException(sprintf("v1 decode: expected array marker, got 0x%02x", $m)); + } + + /** Reads an unsigned integer; returns an int when it fits in PHP_INT, else a decimal string. */ + private function readUint() + { + $m = ord($this->take(1)); + if ($m <= 0x7f) return $m; // positive fixint + if ($m === 0xcc) return $this->beUint($this->take(1)); + if ($m === 0xcd) return $this->beUint($this->take(2)); + if ($m === 0xce) return $this->beUint($this->take(4)); + if ($m === 0xcf) return $this->beUint($this->take(8)); + throw new \RuntimeException(sprintf("v1 decode: expected uint marker, got 0x%02x", $m)); + } + + /** Reads a signed integer (any int marker). */ + private function readInt() + { + $m = $this->peek(); + if ($m <= 0x7f || ($m >= 0xcc && $m <= 0xcf)) { + return $this->readUint(); + } + $this->take(1); + if ($m >= 0xe0) return $m - 0x100; // negative fixint + switch ($m) { + case 0xd0: $v = ord($this->take(1)); return $v < 0x80 ? $v : $v - 0x100; + case 0xd1: $v = $this->beUint($this->take(2)); return $v < 0x8000 ? $v : $v - 0x10000; + case 0xd2: $v = $this->beUint($this->take(4)); return $v < 0x80000000 ? $v : $v - 0x100000000; + case 0xd3: + $bytes = $this->take(8); + $u = gmp_import($bytes, 1, GMP_MSW_FIRST | GMP_BIG_ENDIAN); + if (gmp_testbit($u, 63)) { + $u = gmp_sub($u, gmp_pow(2, 64)); + } + return $this->gmpToScalar($u); + } + throw new \RuntimeException(sprintf("v1 decode: expected int marker, got 0x%02x", $m)); + } + + private function readDouble() + { + $m = ord($this->take(1)); + if ($m === 0xcb) { + $v = unpack("E", $this->take(8)); + return $v[1]; + } + if ($m === 0xca) { + $v = unpack("G", $this->take(4)); + return $v[1]; + } + throw new \RuntimeException(sprintf("v1 decode: expected float marker, got 0x%02x", $m)); + } + + private function readBool() + { + $m = ord($this->take(1)); + if ($m === 0xc3) return true; + if ($m === 0xc2) return false; + throw new \RuntimeException(sprintf("v1 decode: expected bool marker, got 0x%02x", $m)); + } + + private function readStr() + { + $m = ord($this->take(1)); + if ($m >= 0xa0 && $m <= 0xbf) return $this->take($m & 0x1f); + if ($m === 0xd9) return $this->take(ord($this->take(1))); + if ($m === 0xda) return $this->take($this->beUint($this->take(2))); + if ($m === 0xdb) return $this->take($this->beUint($this->take(4))); + throw new \RuntimeException(sprintf("v1 decode: expected str marker, got 0x%02x", $m)); + } + + private function readBin() + { + $m = ord($this->take(1)); + if ($m === 0xc4) return $this->take(ord($this->take(1))); + if ($m === 0xc5) return $this->take($this->beUint($this->take(2))); + if ($m === 0xc6) return $this->take($this->beUint($this->take(4))); + throw new \RuntimeException(sprintf("v1 decode: expected bin marker, got 0x%02x", $m)); + } + + /** Reads a string-or-reference: inline `str` (recorded into the table) or a `uint` table index. */ + private function readInterned() + { + $m = $this->peek(); + if (($m >= 0xa0 && $m <= 0xbf) || $m === 0xd9 || $m === 0xda || $m === 0xdb) { + $s = $this->readStr(); + $this->table[] = $s; + return $s; + } + if ($m <= 0x7f || ($m >= 0xcc && $m <= 0xcf)) { + $id = $this->readUint(); + if (!isset($this->table[$id])) { + throw new \RuntimeException("v1 decode: string table reference out of range: $id"); + } + return $this->table[$id]; + } + throw new \RuntimeException(sprintf("v1 decode: unexpected marker 0x%02x for interned string", $m)); + } + + /** Skips one arbitrary msgpack value, recording any inline string it contains into the table + * (so back-references in later known fields stay in sync). */ + private function skipValue() + { + $m = $this->peek(); + // str: record into the table + if (($m >= 0xa0 && $m <= 0xbf) || $m === 0xd9 || $m === 0xda || $m === 0xdb) { + $s = $this->readStr(); + $this->table[] = $s; + return; + } + if ($m >= 0x80 && $m <= 0x8f || $m === 0xde || $m === 0xdf) { + $n = $this->readMapLen(); + for ($i = 0; $i < $n; $i++) { $this->skipValue(); $this->skipValue(); } + return; + } + if ($m >= 0x90 && $m <= 0x9f || $m === 0xdc || $m === 0xdd) { + $n = $this->readArrayLen(); + for ($i = 0; $i < $n; $i++) { $this->skipValue(); } + return; + } + if ($m === 0xc4 || $m === 0xc5 || $m === 0xc6) { $this->readBin(); return; } + if ($m === 0xc0) { $this->take(1); return; } // nil + if ($m === 0xc2 || $m === 0xc3) { $this->take(1); return; } // bool + if ($m === 0xca) { $this->take(5); return; } // float32 + if ($m === 0xcb) { $this->take(9); return; } // float64 + if ($m <= 0x7f || $m >= 0xe0) { $this->take(1); return; } // fixint + if ($m >= 0xcc && $m <= 0xcf) { $this->readUint(); return; } // uint + if ($m >= 0xd0 && $m <= 0xd3) { $this->readInt(); return; } // int + throw new \RuntimeException(sprintf("v1 decode: cannot skip marker 0x%02x", $m)); + } + + /** Big-endian unsigned from up to 8 bytes; returns int when it fits, else a decimal string. */ + private function beUint($bytes) + { + $n = strlen($bytes); + if ($n <= 4) { + $v = 0; + for ($i = 0; $i < $n; $i++) { $v = ($v << 8) | ord($bytes[$i]); } + return $v; + } + return $this->gmpToScalar(gmp_import($bytes, 1, GMP_MSW_FIRST | GMP_BIG_ENDIAN)); + } + + private function bytesToDecimal($bytes) + { + return gmp_strval(gmp_import($bytes, 1, GMP_MSW_FIRST | GMP_BIG_ENDIAN)); + } + + private function gmpToScalar($g) + { + // Keep small values as native ints (so json_encode emits `1`, not `"1"`); overflow -> string. + if (gmp_cmp($g, PHP_INT_MAX) <= 0 && gmp_cmp($g, PHP_INT_MIN) >= 0) { + return gmp_intval($g); + } + return gmp_strval($g); + } +} + +/** dechex() that also handles values returned as decimal strings (uint64 > PHP_INT_MAX). */ +function dechex_gmp($v) +{ + if (is_int($v)) { + return dechex($v); + } + return gmp_strval(gmp_init((string)$v, 10), 16); +} From 61c85ee4b7d9506d4301a0ecbae53b9531841087 Mon Sep 17 00:00:00 2001 From: Alexandre Rulleau Date: Thu, 1 Oct 2026 18:03:05 +0200 Subject: [PATCH 5/5] ci(temp): run system-tests from leiyks/php-v1-payload, revert before merge Clone system-tests at SYSTEM_TESTS_REF (default leiyks/php-v1-payload, DataDog/system-tests#7843) from SYSTEM_TESTS_REPO, and add APM_TRACING_EFFICIENT_PAYLOAD to the System Tests matrix. --- .gitlab/generate-package.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.gitlab/generate-package.php b/.gitlab/generate-package.php index 2d860b2bdd..179c59b40c 100644 --- a/.gitlab/generate-package.php +++ b/.gitlab/generate-package.php @@ -1421,6 +1421,10 @@ function package_extension_jobs(array $platform, string $kind = "all"): array PIP_CACHE_DIR: $CI_PROJECT_DIR/.cache/pip APT_CACHE: $CI_PROJECT_DIR/.cache/apt DOCKER_DEFAULT_PLATFORM: linux/amd64 + # Override these to point at a fork/branch of system-tests without touching this file. + SYSTEM_TESTS_REPO: "https://github.com/DataDog/system-tests.git" + # TODO: point back at "main" once DataDog/system-tests#7843 (leiyks/php-v1-payload) is merged. + SYSTEM_TESTS_REF: "leiyks/php-v1-payload" # TODO DD_API_KEY; SYSTEM_TESTS_AWS_ACCESS_KEY_ID; SYSTEM_TESTS_AWS_SECRET_ACCESS_KEY needs: - job: "package extension (bundles): [amd64, x86_64-unknown-linux-gnu]" @@ -1450,7 +1454,7 @@ function package_extension_jobs(array $platform, string $kind = "all"): array pip install -U pip virtualenv - /tmp/vault kv get --format=json "kv/k8s/gitlab-runner/dd-trace-php/datadoghq-api-key" 2>/dev/null | python3 -c "import sys,json;print(json.load(sys.stdin)['data']['data']['key'])" > /tmp/.dd-api-key 2>/dev/null || true - - git clone https://github.com/DataDog/system-tests.git + - git clone --branch "$SYSTEM_TESTS_REF" --depth 1 "$SYSTEM_TESTS_REPO" system-tests - mv packages/{datadog-setup.php,dd-library-php-*x86_64-linux-gnu.tar.gz} system-tests/binaries - cd system-tests - ./build.sh $BUILD_SH_ARGS @@ -1478,6 +1482,7 @@ function package_extension_jobs(array $platform, string $kind = "all"): array parallel: matrix: - TESTSUITE: + - APM_TRACING_EFFICIENT_PAYLOAD - APPSEC_API_SECURITY - APPSEC_API_SECURITY_RC - APPSEC_API_SECURITY_NO_RESPONSE_BODY