diff --git a/.gitlab/generate-common.php b/.gitlab/generate-common.php index 82a79c8e7d9..b31ac4309b6 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-package.php b/.gitlab/generate-package.php index 2d860b2bddf..179c59b40c7 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 diff --git a/.gitlab/generate-tracer.php b/.gitlab/generate-tracer.php index 8d9e2c6cc61..b7d27347c78 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/Cargo.lock b/Cargo.lock index 08e4cb595f0..89d12e71560 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 e547c261681..be47eae2e9e 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 ad3e24d8d8e..0b0a8d52a2d 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 5a009ffc1ec..f38d8e6c2a3 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 632837a4d90..4552ad48cc6 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/appsec/tests/extension/api_security_telemetry_missing_route.phpt b/appsec/tests/extension/api_security_telemetry_missing_route.phpt index ee15a5c136a..c7fc6d3bd34 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 cac10102fe8..b96e69d0fa0 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 3562a1d81c0..6af3eb9b138 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 144575c8478..ec798f7c8fb 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 06db245c719..3a87dfc12a2 100644 Binary files a/appsec/tests/extension/rinit_rshutdown_basic.phpt and b/appsec/tests/extension/rinit_rshutdown_basic.phpt differ diff --git a/appsec/tests/extension/root_span_add_tag.phpt b/appsec/tests/extension/root_span_add_tag.phpt index 3d1b8b72c52..bf3be9f7cc6 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 c8c73394f3c..b7670d1ad92 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/components-rs/bytes.rs b/components-rs/bytes.rs index 01e46de90b8..c3a67b8b516 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 76a53619ba0..6a81e55ab67 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 494df3b29e4..8caf667db9e 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 f0c04aa09a9..7e2879037d6 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 eae5a193575..dfbe83d67cf 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 7aa29ce311b..b5776ac4cb9 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 ee7fb4237c7..5cbfea5c247 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/dockerfiles/services/.env b/dockerfiles/services/.env index d8351f38823..0821a222f03 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 257403b9afd..55bc8652781 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 00000000000..fe9191e0bb9 --- /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); +} diff --git a/ext/agent_info.h b/ext/agent_info.h index 476248ef587..abf9a3e7770 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 048cf5e4938..afc2d515106 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 667c9c49766..8e572f0e260 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 5ee2c166e76..7893c77402b 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 ee6f5745b57..f2b3bd29099 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 d120c1090a0..89d5b1fac3f 160000 --- a/libdatadog +++ b/libdatadog @@ -1 +1 @@ -Subproject commit d120c1090a03fa7274fed4121344d25660081895 +Subproject commit 89d5b1fac3f42516d15e2576b325896e1334eace diff --git a/loader/tests/functional/test_ddtrace_is_fully_loaded.php b/loader/tests/functional/test_ddtrace_is_fully_loaded.php index e5105cdbdb7..72a2e9e312d 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/metadata/supported-configurations.json b/metadata/supported-configurations.json index b36ce1f4782..f9be651082f 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/src/DDTrace/Integrations/AMQP/AMQPIntegration.php b/src/DDTrace/Integrations/AMQP/AMQPIntegration.php index 4a6c8a95616..7e5861d9fd0 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 9adf7691128..4ea47027515 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 0d6b6744aea..732030ae3ee 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 77a681baf4f..acb36e83ae1 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 15c8f684f67..c92a90f1370 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 e9880db1864..d4aba6ee826 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 2362f063f65..dad67703467 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 76b57861428..cd4f1423fa1 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 aead9d43e22..2e9d95c0907 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 46ba22ca831..bd9eeff386d 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 17630f1801e..6d94c164129 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 74fb17c2184..17753f0d515 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 afa11fb83d8..1d73d6f1bfd 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 5dbfcbf2e82..3618f33e65a 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 2fe53f82c21..61c06f79469 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 8f72520fd4d..d148f4af9d9 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 bfbf6815a34..aaa393a9937 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 aff0751cb2a..0e8045defa7 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 a797e72ad49..89073e57ccd 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 2fd20dcd8dd..0706a599099 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 cff131d05e8..2e431a51f63 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 e4b3952ca4b..5bc2c000f54 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 27f715a2881..42b8be9fc65 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 bc5db373c90..389d2ad808c 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 620ecaf9b7c..6a774b58d1e 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 7172089a8a5..e44bf851ca3 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 f7c3e358b5f..de7c0d50a49 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 b971b57ca7b..1c14c812715 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 727d6e0fa1f..c1ce8eb702c 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 2b1fcc30e68..c7feb8c6f5d 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 314d17f9db1..e03033bec7a 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 929a860c005..48694ad984b 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 d135e66d810..a6a20fab08e 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 e83d329c7a5..dcd95f38aaa 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 2ac324ec74b..2e8c7fc9ba2 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 8a3774dc260..6643abf5ae8 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 72413204c93..a407df5771b 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 91fa862d5f9..6bbb54c95b6 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 cf4aa4a07a3..38b3487241f 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 89744136740..25c27e606c0 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 47efb029ae0..be653be3a6a 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 3ba0d21880e..95121cbc156 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 d298013ca49..1b5317d39db 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 86c6b735bb1..cd78b9bafdf 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 82cba27474b..a928f23e0bc 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 a3bd94eb18a..339535b453e 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 f2cb6b7c1e4..4bfdecd1846 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 6b32afbcc78..16c79106d15 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'; diff --git a/tests/Benchmarks/API/MessagePackSerializationBench.php b/tests/Benchmarks/API/MessagePackSerializationBench.php deleted file mode 100644 index 43220a80c93..00000000000 --- 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 e7cbf691c62..a48bcdfaddf 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 be61583431b..e39be05fc2b 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 96fd3388cfc..489b22df13d 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 20dd5b22ab5..3a6e321f978 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 9515d79ebb7..be51045449d 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 a5ddf820202..24468d824f7 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 995f4e9bef1..f379128f5db 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 b4c239d76b2..68b6b4c378d 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 ea557f8da06..d0e3b7c985f 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 58896f2e061..8e5b1053661 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 377561d5499..27be186cadb 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 e01c76154ae..867fe9761d5 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 d53be6143fe..5102883537c 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 cad7a21dca9..4078e731b2e 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 717b6ddbc26..00000000000 --- 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 4e95479b97f..7e33955d87d 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 135b17939c9..49c5ba56d8d 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 b9684547b88..5d7251fcad3 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 b9237a54ed2..4cf99aff87e 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 8504ee23c4a..3faddda75ec 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 ea7942cae4a..494fcf4449b 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 3109b07ddeb..00000000000 --- 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 402c38eab84..00000000000 --- 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 89e0c8a79ca..b98993a42da 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 3d8fd4681ef..00000000000 --- 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 14a0f0d04a3..be831f7f63f 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 0d76259fbcf..00000000000 --- 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 bee744eaa16..00000000000 --- 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 962f268fbbb..00000000000 --- 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 8ed82832ffd..00000000000 --- 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 dcefdc8bad3..00000000000 --- 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 5f2f141ed21..00000000000 --- 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 87675daa158..00000000000 --- 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 d4805c64328..f06ef682878 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 525a795f629..fc532c77b28 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 b2abb86e49d..ae7e5f68fe7 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 ea8edf96e2c..16008833ce1 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 e7171106a9b..64389b726cd 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 cca875d9a12..8fbf9dfb165 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 70b85ff515d..cad76a91463 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 9d36b4f5778..00000000000 --- 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 5483d95fb44..00000000000 --- 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 e8691e90edc..00000000000 --- 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 c92a93e9242..00000000000 --- 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 3e24e5bd015..00000000000 --- 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 ccf749e2c2b..00000000000 --- 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 7c9cbfee07a..00000000000 --- 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 5044eafd656..00000000000 --- 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 1a622ae42b4..00000000000 --- 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 aaf2f4acc85..00000000000 --- 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 369f46a587e..00000000000 --- 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 d2dc2c12f05..00000000000 --- 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 3ac84f07060..7e1dc5bb87a 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 fcb598201bf..b56a7bc76fd 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 96d4d6e3ab8..58a16797a01 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 3c91add91a8..7ed3e6ff13c 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 f3129e5087b..520dddcbf08 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 1b8fd98cbca..57d6f898502 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 f06e8902e63..d874b5c0491 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 5652ad48538..57c0a5c3acc 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 e08a13ea52b..dea587bfc5c 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 9018f175f47..d62abff2683 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 00000000000..07ddd7720ee --- /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 c05c7d9f547..f999e4d7611 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 bf86e43f422..a40262b3fd6 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 a6454617206..94de72c536e 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 b77c513da8b..e36e7bf9716 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 1e5f7a8826f..905c079ea41 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 75c4120b047..a5c8ca510d7 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 6442f0c7bfa..8251c40442e 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 c54653abee0..cce106108da 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 fa4fccffb7e..f4dc2817feb 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 224fcd64655..00000000000 --- 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 040b4d15b2f..816a9516786 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 fe32799f15a..d6f9194f757 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 81e76907ce8..00000000000 --- 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 9ebd6e70bb3..00000000000 --- 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 a775ec2358f..146041e8b8b 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 36f4b38ba60..3f00ce01ed3 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 f2247f99c5b..591cfd918d8 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 085096d1c82..00000000000 --- 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 71fe798761f..00000000000 --- 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 f8e548765aa..2a83dc5dbb9 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 f47738f2347..00000000000 --- 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 871f5776d05..00000000000 --- 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 a4aae4b3e8d..00000000000 --- 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 4b1a4306967..00000000000 --- 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 de41d8f90ef..c577a332173 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 9edbb95974f..2740be69277 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 00000000000..2c6e2409470 --- /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 db324e84c9d..7a55657c358 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 98300bf291d..4fbf2826724 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 30ea476e07c..df4a71554c1 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 1a589559b3e..86700f64ac8 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 70046cb2b2e..eb5f2c44dea 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 2b75385f956..cb92e2e7921 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 e9285c55484..25a2bd7a14e 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 acb15dea0dd..96e9fb8ad4d 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 e02e2fef6a1..9dec29edb76 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 b5b61f87fce..b8070bee42a 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 433d4c1ef84..dba77a081c7 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 10bc4e9a015..61b4a9eb80d 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 f094385b51c..fe26a0e6855 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 4362f7ecae9..435145953da 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 69d8ad24e0a..f503b5beb53 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 277de4a684c..244566b792d 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 5c2118eccee..189e9a1d118 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 e890e936475..a7595aa10a0 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 252758568b3..e3b5d8bd43b 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 ccad1e18a0c..f0246e5adfa 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 475f420dd3b..b4e38dc14f9 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 745924ce7ea..90632a5089e 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 e9a98bf25b5..a3f080ee955 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 419335cf093..710e509a4cd 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 b8fc62939ff..331851110d6 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 4023bf9f6b2..f6da750f554 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 be481d60c10..eb29334b900 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 7d7c98d39b4..59c066fbad1 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 8b9cfe1d244..970b47ce63e 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 2ca50170b25..900be82425e 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 8038c2de489..85f9bb78285 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 60bca935664..c9ddbba259f 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 4ec56b8f433..598989147f9 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 ec95d80ce1a..90be2db7999 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 bb960336295..e901d01e4c4 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 23d77530908..e8e1de6e0a6 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 46db2d7ef06..d49fd52fe98 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 3484ebedcf6..bc2ae49254b 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 8214b7c9f61..85f876fcee9 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 f3e19fc36e0..10cc6280b8c 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 e39edbc762e..4adb416e777 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 2f7b20fb70e..508bd9faa93 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 2509206ca49..b8927bf9d01 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 134d2b895b2..cd5f6f99a24 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 5d6ac75c126..011dab40ecf 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 79b4472761b..b1534007226 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 253fb227705..63f0c6bad51 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 83312123873..da8389ef5b3 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 c8597de99b4..8e1c77dc6ca 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 da71329a71f..1e185300c9f 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 3fdf84c3860..9c58e95ee65 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 e065e051666..55e48eb018c 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 f4024575b61..001c4a758f7 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 21323d191d0..8676b380170 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 cfa41ac6309..c8267cd2e96 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 98cb4604ab6..7da44b660c4 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 a2acac25e60..2f485057ed7 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 7bfdb7b9f2c..01943f8d28c 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 de22c60be6d..3a41aa29f6b 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 907bf033afe..5b8534a25c3 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 d420f7f4b7b..ea9e02e4c07 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 f7a0669b129..d5057ea5445 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 6e735807c4a..7357f811ffb 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 b7f4fa91086..638bcf947aa 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 a92a5d91e8a..80efa5465c4 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 b73dca0798e..0ad7dea2256 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 3c55dc4be12..22462f9fd41 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 33d734344ae..699d0bd462f 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 33d734344ae..699d0bd462f 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 b26685d4031..aa95978352f 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 95997cccb52..5923e9b7419 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 f5278b29a5d..6055175ee17 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 cf79fb27e80..e8d11dcddac 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 88b2d3cb5ae..f571b7c9905 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 386ef0492e7..b8f5f8f3e21 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 4b3886711ef..b6646d4695a 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 2431d43fa11..2650487d0bc 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 c4252574948..8bab4d83118 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 9551bda918c..f1ef0d76015 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 ab7e0e6b5a6..9d7483846ca 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 aa21c183cff..08fb6c0837d 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 c9b3ea26d3a..4024a2bc699 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 06999a9cc80..def02e5d2e3 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 fda0ae4ec8d..840373fd8e5 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 4614f26881f..f098415b9fa 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 11192c42235..6778267391f 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 7e532482c0f..23be23085a5 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 6d41422406f..ab6c26a1c5f 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 ce4817172a8..eb70044f44b 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 2a0f673213f..a7cbf5c5c18 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 181a7684919..f14c33a5003 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 edb0b56b5b2..e2569f33b5f 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 00000000000..9196d71fdb1 --- /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 00000000000..98b0ac8d73f --- /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 00000000000..200b7860d81 --- /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 44d538e596f..a4d0c5e2dca 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 9516074caf1..0e9c1a62243 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 6dbbca8840b..9795c149b99 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 00000000000..1c3aff755f1 --- /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 00000000000..b49a8d67009 --- /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 00000000000..09653ef7ec4 --- /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 00000000000..8d70aeabf4a --- /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 00000000000..6e594290002 --- /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 00000000000..360a958287f --- /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 00000000000..2150b976dc0 --- /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 00000000000..e98e70adf9a --- /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 00000000000..b3f02644863 --- /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 00000000000..1efb1ce9543 --- /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 00000000000..3fa007b0219 --- /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 00000000000..c1e92530f01 --- /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 8789981f693..e9bd1cd3ac6 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 3182c9aa6f2..1c3aee84f20 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 26155009606..c2ba58361d1 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 f368665db62..6bd647289c4 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 4c60e34cde4..73fc5bcc1e6 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 2f8a9a9cc09..911e8834d78 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 c80ae66215d..160a09909b2 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 6ea6f960276..4224d657dfb 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 e7aaa05caf1..780267e7812 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 61b849504af..4f2d37532d9 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 b8d925b89a9..10c6d72861f 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 b38e1745b5a..32653c2cd0b 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 e73150fc9ef..9feba6f17ac 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 ee48fa4a2a0..b50f7f317cc 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 2472ca28fdb..db1a56f9d0d 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 1fe141ced9e..0e9383bf4f6 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 c294d2741e0..a488f11d1e9 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 33f86a772bb..1331fd27b37 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 db6133a6db6..7f66e030a9e 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 fd83693e72c..7075915fe88 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 00d83c900c6..edcc9425b0b 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 94ee21e5944..087a9326c58 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 00000000000..4dc9ad334f6 --- /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 e7ea5c45418..5668afcb1a0 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 d7aded0ecc8..9b7cb226fa7 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 ac99ec932b1..07750c9d578 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 35251dd8993..b3c7149deb7 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 ab6883b1770..48ffd2fc75d 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 8a52ce75161..bdf7cc982be 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 399b57d7551..085bc7b65ae 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 146c5f22bba..3c95454513c 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 762675d7d3a..cb8ca1e7d8d 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 33a1771d804..ae0edd7b6c1 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 d74f8562373..3bd840abccb 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 07812fc0cdd..3a43828a1eb 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 add87210a25..e9789bece26 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 c1930fcd475..3e93ca1402c 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 2de41a7c64c..d83c7229fc0 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 f7af2063f72..cd207cca443 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 4995090b888..8cb397114cb 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 16762177c00..388e2a789de 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 931b038444a..66a074eed7b 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 47ff97370f6..a2ff04faf69 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 0fd4226144a..0a63f431dde 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 1d2c442da52..0048f1e73b2 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 dea8d53cc7c..d91c341475e 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 9839c6dc576..6abce1e1aa9 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 6da3f0d707e..c86e8a636cd 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 1984f816f1a..e132c514600 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 87eb037f2e0..41d88ebc614 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 1b0e458bec2..d1ff9421f33 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 4bafe494a93..30c1e5b09bc 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 d1cd2259f03..ba7f5ee028b 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 32b43000e19..1be3557dc21 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 71c6c5d8eee..c8280926148 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 facb68382c9..885df67cca9 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 069bf90c60a..2555674c1e9 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 f60eeabc176..d8944d0042b 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 7561b0f1534..b1b3d85020f 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 7d3e2f56cd7..2acb184131b 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 886b2d8f4fa..db6036d6805 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 2ecb9930d21..5a42c8b606b 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 bc2bc069910..14886e2aebb 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 cd26d5d5238..519039c3cb9 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 ebc2ecd55a7..84b2afd37d2 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 1b345fcfde8..399b3e5910c 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 5b07a34fea6..2b4533a6bf8 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 c4eca6d7586..028ed204988 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 b643afd6661..18096f11ffc 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 2f47e493ca9..82657699976 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 aa1f72f0bb2..ca4e45c2274 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 b206252922a..c6edb3f1572 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 8560f29d75b..4e8163a710a 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 cad41da9e1b..44ce172c86a 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 f2936e1074a..c2e0695a6ae 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 805ebd8bd44..d4002c46ebc 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 671c9ddb026..c0dcede6bed 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 079728fa30a..ff5f05b47a7 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 fbf920b9dfb..bb3ad57b5a5 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 382f4531e42..101c89ad005 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 664e0a6494a..ac8e4cb34ab 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 d1223a0204c..b9fd082052f 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 8954f507ab7..44d3c41ed26 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 ba000554ff8..ff6ad4d6320 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 be69b90dbb6..50cf0c568b7 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 58efbfa21b2..97dab3a5469 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 db07b28e3a9..900eb8dc58f 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 fbec543abc2..fd811fb96e7 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 c3f1ee325b8..723ba500515 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 0ce6e5ee728..44d2d29fc6a 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 a7061957653..07d092f1c08 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 1c04645c8fb..0a9fb54f4b3 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 85f3f5014f1..a101cf2f429 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 569ff40bc7b..03104991a16 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 20df9b9f211..1efa9984856 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 fae36301037..1c2dacae456 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 713dd552a2d..0b93c97006e 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 235bb2cdf80..4c9d625460e 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 00000000000..aa75f194f89 --- /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 00000000000..60b4f712f77 --- /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 00000000000..bacd6de58ac --- /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 00000000000..c86802fa5b1 --- /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 00000000000..3b45f92effc --- /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 00000000000..513c8c6190a --- /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 00000000000..b764dc426e5 --- /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 00000000000..9363a9061eb --- /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 a58461fa4e3..7267d0e6fb1 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 0fac818cd88..09fb6a70892 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 6265967c55a..13583bca433 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 8906df1d6ca..45bb78d1a16 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 92283b61b4e..03a54c0d0e6 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 c7378ee6337..8d584b80cfa 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 8975ff2d70d..12eb653bd3a 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 39ee073d445..77a08041bb2 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 4552b54f28f..b52ef5cf99d 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 a4bf52232f0..f09f177e2ca 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 4ce1682c97a..c264bafd55a 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 b0d3a73e8ad..eca8c28fab7 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 a0d14033fed..338eefdb7dd 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 a46ee44b268..bffef820c92 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 7c05ce2ff5e..a5b19cf02ff 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 7a06cbf7a08..244049d066f 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 0e339b5a4a9..c330b7c7d4e 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 07527277bfe..f27a58c91ca 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 cd673e65e31..e5641d1101a 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 9bd666c7b43..73ab1163d6c 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 1539e37ff7e..2f010af5034 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 d08ff85c7bf..d0486fc96a6 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 cbc2dfafd50..99e6e1b45d6 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 d14f68bdd00..fb704e74eca 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 00000000000..276de719d5d --- /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 08e02f7387f..7f36e2485bb 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 116999116fd..f456a6060ed 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 4502567e329..4436c1efffc 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 ebd5f4b0137..00000000000 --- 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 00000000000..28143ffff0c --- /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 94f4baa2036..4b434afcdae 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 b70090a34de..41edfa5f224 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 33cae852b2d..5158782ea4a 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 929c34b97aa..41d50574433 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 2c72d326a01..09042e94eee 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 ab515a77696..e218355e4aa 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 1da3301fe8b..7f6f2288bfc 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 6f874986516..039730f2ece 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 5170c9dbe32..b688f9898e8 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 c50a1bd1bf6..5dd7bf72465 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 c89ca53ba12..98b8df7f91c 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 49e57af64c0..449cde8c08b 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 f1c4002d99b..211d5220188 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 fb342972d71..641f60e4f12 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 18190be1c79..592ca28d228 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 4981d83b9ba..61df7c29636 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 16afc5508e4..512452ba570 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 f96ed6fb99a..9301f9d053a 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 18490266bdc..90f6bcf189b 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 42eaba32f3e..0f51aa908d0 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 82c03046b6f..9983b39cf3c 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 a7b5ee58bef..b7286a56a12 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 fbcc57a8a7f..a780052f9da 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 b56f8a0bdbc..abde238ee69 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 54a5a7197cc..643301750a4 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 7fe2dab3e1a..78594198028 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 904d2796f9b..55529a131c9 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 c85c7b76669..0632de35181 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 781cebdb29d..877807a6fef 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 bcd9fe56956..1912e0b7897 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 b12796c2391..55ee8be5b2e 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 1bdb15085fc..5ecbf47c32e 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 cebd2538ca6..ccdc06d7ec3 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 378a177110c..7555d81e765 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 2d16a69aa4d..c4837b309cf 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 1095152bcea..c42fe8d4320 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 771abe7c6b1..bd72765dfcc 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 b7e009b6638..79d3208952d 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 901042e3de5..e1305168b82 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 30a75fbd360..2f435e1cbf4 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 1d07dbb6152..0b168b113d1 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 a259ccb31a7..3ba2e8e3a04 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 8a232b92304..b1b107fff1b 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 cba33f84cdc..47153756895 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 8f1d421becd..96df301cdbf 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 ac0e27db473..f37c60706fe 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 2f0e9cc11a9..aed64532564 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 b272893f432..c82fbc8f52d 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 419fe5954d0..1ff452d6e5f 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 61f9f360c1c..7fa90af88ab 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 4f0313c6f4d..63a30ba8553 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 078498389ad..8134f303cf7 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 83bad2e3d5f..3ab1bcd474f 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 3233a40a359..6f1a0d09b38 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 112ac020a34..1322a09af26 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 173019f7ad9..c1e7863e1ab 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 129eb9bf54e..932c674cbe0 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 75ca1fa3f67..419a9973dab 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 2099de60186..5ba93105324 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 680f92fc800..982c4721926 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 22efd535627..14cca27eef4 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 70b03dbba75..8266c058d35 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 e311fa2b009..9b836b3f0dd 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 2934d7bfe6e..cc6f2e3164f 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 20a7a2d853e..b9fa3364fba 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 3e1774ade87..6bddedff1cf 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 ede2a71d263..2c84358d40b 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 f8a3c1d0e0f..05add0c60b7 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 bd6e68a2a27..7f29380f5b7 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 e6dd0b6f683..dc1c35643da 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 e2ee39ae9c5..62019100993 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 1ad5cb004a7..9ad7139cec4 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 884e59bdbc7..22fea5b1a87 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 0d1c1ee654c..6e9645c95ad 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 de7b4288e70..d4d83260a77 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 66ee49f491e..971f75b6c50 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 6c2bed6035b..325172bd86a 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 01e28d6b433..365e5b484a2 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 eea5cc8a4bb..4a8df662160 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 c822b1957aa..54ecdda91d4 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 34138c0c85d..34e088e269c 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 2997d6ac172..7e8e4c01c9c 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 19ee5e01bdf..62985721749 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 bf66290873e..ef08bad4c65 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 61fc7ee4502..9f749be8df6 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 72c71d68a02..68dc912b0b6 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 b953f93fb26..9ea121f0eac 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 76190413d61..fe0454314f7 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 eb115310c09..dae272177b5 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 d5425bb8d1f..c43646f2204 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 d39002c24b3..9d423e45d71 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 5b560f719a5..8a2e40557d4 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 462f84f9e88..4272fd7d6b8 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 82348173bb7..0cb1cfa7cc5 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 e8d995e047b..62c2259e3e0 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 201954f0c1c..4e48a91ae98 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 02531a7ac64..48fe18f313d 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 420610342cd..d4f1d5e20f9 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 a0a9c474648..c15e1da0b35 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 62625f35801..9d96bd56556 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 ae304477a08..ef36dad8b79 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 37bea1d81a8..98208159413 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 f6586cf06a2..0dd4c90ea12 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 cbebb8fe4ea..19a6a3fe293 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 91884722f8c..48dd4481412 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 a94467e5ad4..c52c1e95d43 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 942275e9995..df402ca4e83 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 4cea0bce0da..10973e8ec51 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 34e87afcbd1..a5cc6c32ea6 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 ad6b6999981..d1fa9686386 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 3da297ba272..2e742dc1a32 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 5fe007192cb..3dcd49d0728 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 2f1cd43bf7f..71457ff117b 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 323e0bbfd23..fa190896854 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 f74b08cfaf3..e88095a347d 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 b2cc305f4fe..d53181a322c 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 80cf347caa3..655799c0e5a 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 310b142ac51..d40c587ac13 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 ca8d5fe1348..f306df4b012 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 ebfef74a265..364428dd2f9 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 9aecdba4a4e..fcbfbed2a68 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 27319620a33..c75d2591f79 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 683d022d4e2..4cebcc1c975 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 a2f281d70d4..c7709609650 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 29e5c09037b..30aa12bb9d5 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 c982920760e..25c068123fb 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 671eb3f7d1a..646e2faeb8d 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 d965665100a..dd042c501ff 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 10673208e8e..05a84d8a3a0 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 e055001b0cc..991fad422c0 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 cfbeb419d9c..256570c3791 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 76919c42279..2f3d6240e08 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 4b9c2000682..a884b778df1 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 } }, diff --git a/tooling/generate-supported-configurations.sh b/tooling/generate-supported-configurations.sh index 0a70d2c2614..c95651382c5 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 e0985f2c116..ce86fdaa624 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 44977c41b2b..0b91c93e700 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 d241fd2c343..f0e2a6d1079 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 892cdce0715..21de4fc3afb 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 4518e2c5836..bc662c47ac1 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 3a3bf90f9c3..7f24c17dbf5 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 adac5b1f10c..6f483cf590d 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 afa0f62d9f7..ddfe7a6dd71 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 f6eef1b68f1..40940d53adf 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 a4db744bb3f..d1ccee3710a 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 738dd4e9174..2bb2e246d20 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 38f1a1fb3f0..345106e5613 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 f0fa8a57d7e..0ec30f44446 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 82ebffbf7f8..f5a78b6ee79 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 23617d2eb1f..6e8a7f7e078 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 405adb5c506..8494e369b38 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 8de53fa675c..92e26a3bab5 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 ea74864954e..cc0ad0d6ef3 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 b10c071d060..52bffb6ab5d 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 5e6ae61ffb5..fd0a3ee2fac 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 0bb42c31d5a..1bfcdf3c7e1 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 0040514971b..1d52dc3897f 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 7733b855355..f9d5f5be9f1 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 2e0750a40ef..c90bedbf0a6 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 b33e068672c..f1fa07e17aa 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 00000000000..9596d74eba2 --- /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 00000000000..1b4e9e0982f --- /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 4479a2da530..fc6178a825f 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 4873ae766ff..994c1104909 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 5998d6a64d4..c783ce7fcc8 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 a296fbcd297..e27fcd7be85 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 eea6724ef1c..b95846c5ef9 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);