diff --git a/.claude/ci/compile-artifacts.md b/.claude/ci/compile-artifacts.md index e39b9fb7d9b..8660a34b3ba 100644 --- a/.claude/ci/compile-artifacts.md +++ b/.claude/ci/compile-artifacts.md @@ -191,10 +191,10 @@ prepare code cache cargo deps: [{arch}, {triplet}] `GIT_STRATEGY: none` variable means the runner does not clone the repo -- instead the job script manually clones via `git clone` + `git checkout`. -- `ddtrace.sym` (repo root) is the export list for the final `ddtrace.so`. All symbols +- `datadog.sym` (repo root) is the export list for the final `ddtrace.so`. All symbols not listed are hidden via `--retain-symbols-file` + `-fvisibility=hidden`. If you add a new function that must be callable from appsec, profiler, or the SSI loader, add it - to `ddtrace.sym` or the linker will drop it. + to `datadog.sym` or the linker will drop it. - `CARGO_TARGET_DIR` must not be set explicitly for `compile_rust.sh`. The default (`target`) is resolved relative to the workspace root by Cargo. An explicit value diff --git a/.gitignore b/.gitignore index a65d7b8e746..126b15ae1f3 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,5 @@ **/vendor -!/ext/vendor +!/tracer/vendor tmp/ composer.lock* **/core* diff --git a/.gitlab/compile_extension.sh b/.gitlab/compile_extension.sh index c3d38d16ba8..668bef63e63 100755 --- a/.gitlab/compile_extension.sh +++ b/.gitlab/compile_extension.sh @@ -25,5 +25,5 @@ make -j static & wait # Link extension -sed -i 's/-export-symbols .*\/ddtrace\.sym/-Wl,--retain-symbols-file=ddtrace.sym/g' ${EXTENSION_DIR}/ddtrace.ldflags +sed -i 's/-export-symbols .*\/datadog\.sym/-Wl,--retain-symbols-file=datadog.sym/g' ${EXTENSION_DIR}/ddtrace.ldflags cc -shared -Wl,-whole-archive ${MODULES_DIR}/ddtrace.a -Wl,-no-whole-archive $(cat ${EXTENSION_DIR}/ddtrace.ldflags) ${CARGO_TARGET_DIR}/debug/libddtrace_php.a -Wl,-soname -Wl,ddtrace.so -o ${MODULES_DIR}/ddtrace.so diff --git a/.gitlab/link-tracing-extension.sh b/.gitlab/link-tracing-extension.sh index f84f943cca4..8f6c83841f3 100755 --- a/.gitlab/link-tracing-extension.sh +++ b/.gitlab/link-tracing-extension.sh @@ -3,7 +3,7 @@ set -e -o pipefail suffix="${1:-}" -sed -i 's/-export-symbols .*\/ddtrace\.sym/-Wl,--retain-symbols-file=ddtrace.sym/g' "ddtrace_$(uname -m)${suffix}.ldflags" +sed -i 's/-export-symbols .*\/datadog\.sym/-Wl,--retain-symbols-file=datadog.sym/g' "ddtrace_$(uname -m)${suffix}.ldflags" pids=() for archive in extensions_$(uname -m)/*.a; do ( diff --git a/Makefile b/Makefile index 1d017c7308b..5716222575c 100644 --- a/Makefile +++ b/Makefile @@ -46,7 +46,7 @@ RUN_TESTS_IS_PARALLEL ?= $(shell test $(PHP_MAJOR_MINOR) -ge 74 && echo 1) # shuffle parallel tests to evenly distribute test load, avoiding a batch of 32 tests being request-replayer tests RUN_TESTS_CMD := DD_SERVICE= DD_ENV= REPORT_EXIT_STATUS=1 TEST_PHP_SRCDIR=$(PROJECT_ROOT) USE_TRACKED_ALLOC=1 php -n -d 'memory_limit=-1' $(BUILD_DIR)/run-tests.php $(if $(QUIET_TESTS),,-g FAIL,XFAIL,BORK,WARN,LEAK,XLEAK,SKIP) $(if $(ASAN), --asan) --show-diff -n -p $(shell which php) -q $(if $(RUN_TESTS_IS_PARALLEL), --shuffle -j$(MAX_TEST_PARALLELISM)) -C_FILES = $(shell find components components-rs ext src/dogstatsd zend_abstract_interface -name '*.c' -o -name '*.h' | awk '{ printf "$(BUILD_DIR)/%s\n", $$1 }' ) +C_FILES = $(shell find components components-rs ext src/dogstatsd tracer zend_abstract_interface -name '*.c' -o -name '*.h' | awk '{ printf "$(BUILD_DIR)/%s\n", $$1 }' ) TEST_FILES = $(shell find tests/ext -name '*.php*' -o -name '*.inc' -o -name '*.json' -o -name '*.yaml' -o -name 'CONFLICTS' | awk '{ printf "$(BUILD_DIR)/%s\n", $$1 }' ) RUST_FILES = $(BUILD_DIR)/Cargo.toml $(BUILD_DIR)/Cargo.lock $(shell find components-rs -name '*.c' -o -name '*.rs' -o -name 'Cargo.toml' | awk '{ printf "$(BUILD_DIR)/%s\n", $$1 }' ) $(shell find libdatadog/{build-common,datadog-ffe,datadog-ipc,datadog-ipc-macros,datadog-live-debugger,datadog-live-debugger-ffi,datadog-remote-config,datadog-sidecar,datadog-sidecar-ffi,datadog-sidecar-macros,libdd-alloc,libdd-capabilities,libdd-capabilities-impl,libdd-common,libdd-common-ffi,libdd-crashtracker,libdd-crashtracker-ffi,libdd-data-pipeline,libdd-ddsketch,libdd-dogstatsd-client,libdd-library-config,libdd-library-config-ffi,libdd-log,libdd-shared-runtime,libdd-telemetry,libdd-telemetry-ffi,libdd-tinybytes,libdd-trace-*,spawn_worker,tools/{cc_utils,sidecar_mockgen},libdd-trace-*,Cargo.toml} \( -type l -o -type f \) \( -path "*/src*" -o -path "*/examples*" -o -path "*Cargo.toml" -o -path "*/build.rs" -o -path "*/tests/dataservice.rs" -o -path "*/tests/service_functional.rs" \) -not -path "*/datadog-ipc/build.rs" -not -path "*/datadog-sidecar-ffi/build.rs") ALL_OBJECT_FILES = $(C_FILES) $(RUST_FILES) $(BUILD_DIR)/Makefile @@ -106,7 +106,7 @@ JUNIT_RESULTS_DIR := $(shell pwd) all: $(BUILD_DIR)/configure $(SO_FILE) -$(BUILD_DIR)/configure: $(M4_FILES) $(BUILD_DIR)/ddtrace.sym $(BUILD_DIR)/VERSION +$(BUILD_DIR)/configure: $(M4_FILES) $(BUILD_DIR)/datadog.sym $(BUILD_DIR)/VERSION $(Q) (cd $(BUILD_DIR); phpize && $(SED_I) 's/\/FAILED/\/\\bFAILED/' $(BUILD_DIR)/run-tests.php) # Fix PHP 5.4 exit code bug when running selected tests (FAILED vs XFAILED) $(BUILD_DIR)/run-tests.php: $(if $(ASSUME_COMPILED),, $(BUILD_DIR)/configure) diff --git a/appsec/cmake/ddtrace.cmake b/appsec/cmake/ddtrace.cmake index 24e3a093549..45d0a3dcfe9 100644 --- a/appsec/cmake/ddtrace.cmake +++ b/appsec/cmake/ddtrace.cmake @@ -26,17 +26,17 @@ add_custom_target(libdatadog_stamp if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux") set(EXPORTS_FILE "${CMAKE_BINARY_DIR}/ddtrace_exports.version") add_custom_target(ddtrace_exports - COMMAND bash -c "{ echo -e '{\\nglobal:'; sed 's/$/;/' '${CMAKE_SOURCE_DIR}'/../ddtrace.sym; echo -e 'local:\\n*;\\n};'; } > '${EXPORTS_FILE}'" + COMMAND bash -c "{ echo -e '{\\nglobal:'; sed 's/$/;/' '${CMAKE_SOURCE_DIR}'/../datadog.sym; echo -e 'local:\\n*;\\n};'; } > '${EXPORTS_FILE}'" BYPRODUCT ${EXPORTS_FILE} - DEPENDS ${CMAKE_SOURCE_DIR}/../ddtrace.sym + DEPENDS ${CMAKE_SOURCE_DIR}/../datadog.sym VERBATIM ) elseif(APPLE) -set(EXPORTS_FILE "${CMAKE_BINARY_DIR}/ddtrace_exports.sym") +set(EXPORTS_FILE "${CMAKE_BINARY_DIR}/datadog_exports.sym") add_custom_target(ddtrace_exports - COMMAND sed "s/^/_/" "${CMAKE_SOURCE_DIR}/../ddtrace.sym" > "${EXPORTS_FILE}" + COMMAND sed "s/^/_/" "${CMAKE_SOURCE_DIR}/../datadog.sym" > "${EXPORTS_FILE}" BYPRODUCT ${EXPORTS_FILE} - DEPENDS ${CMAKE_SOURCE_DIR}/../ddtrace.sym + DEPENDS ${CMAKE_SOURCE_DIR}/../datadog.sym ) endif() @@ -98,7 +98,6 @@ file(GLOB_RECURSE FILES_DDTRACE list(APPEND FILES_DDTRACE "${CMAKE_SOURCE_DIR}/../src/dogstatsd/client.c" - "${CMAKE_SOURCE_DIR}/../components/container_id/container_id.c" "${CMAKE_SOURCE_DIR}/../components/log/log.c" "${CMAKE_SOURCE_DIR}/../components/sapi/sapi.c" "${CMAKE_SOURCE_DIR}/../components/string_view/string_view.c" diff --git a/appsec/src/extension/ddtrace.c b/appsec/src/extension/ddtrace.c index 4b578164843..5a89d9c5e8d 100644 --- a/appsec/src/extension/ddtrace.c +++ b/appsec/src/extension/ddtrace.c @@ -17,9 +17,9 @@ #include "string_helpers.h" #include -void (*nullable ddtrace_metric_register_buffer)( +void (*nullable datadog_metric_register_buffer)( zend_string *nonnull name, ddtrace_metric_type type, ddtrace_metric_ns ns); -bool (*nullable ddtrace_metric_add_point)( +bool (*nullable datadog_metric_add_point)( zend_string *nonnull name, double value, zend_string *nonnull tags); static int (*_orig_ddtrace_shutdown)(SHUTDOWN_FUNC_ARGS); @@ -32,7 +32,7 @@ static zend_string *_meta_propname; static zend_string *_metrics_propname; static zend_string *_meta_struct_propname; static THREAD_LOCAL_ON_ZTS bool _suppress_ddtrace_rshutdown; -static uint8_t *_ddtrace_runtime_id; +static uint8_t *_datadog_runtime_id; static THREAD_LOCAL_ON_ZTS bool _asm_event_emitted; static void _setup_testing_telemetry_functions(void); @@ -40,8 +40,8 @@ static zend_module_entry *_find_ddtrace_module(void); static int _ddtrace_rshutdown_testing(SHUTDOWN_FUNC_ARGS); static void _register_testing_objects(void); -static const uint8_t *(*nullable _ddtrace_get_formatted_session_id)(void); -static uint64_t (*nullable _ddtrace_get_sidecar_queue_id)(void); +static const uint8_t *(*nullable _datadog_get_formatted_session_id)(void); +static uint64_t (*nullable _datadog_get_sidecar_queue_id)(void); static zend_object *(*nullable _ddtrace_get_root_span)(void); static void (*nullable _ddtrace_close_all_spans_and_flush)(void); static void (*nullable _ddtrace_set_priority_sampling_on_span_zobj)( @@ -57,14 +57,14 @@ static bool (*nullable _ddtrace_user_req_add_listeners)( static zend_string *(*_ddtrace_ip_extraction_find)(zval *server); -static struct telemetry_rc_info (*_ddtrace_get_telemetry_rc_info)(void); +static struct telemetry_rc_info (*_datadog_get_telemetry_rc_info)(void); static void *(*nullable _ddtrace_emit_asm_event)(void); static zend_string *(*nullable _ddtrace_guess_endpoint_from_url)( const char *nonnull url, size_t url_len); -static void _test_ddtrace_metric_register_buffer( +static void _test_datadog_metric_register_buffer( zend_string *nonnull name, ddtrace_metric_type type, ddtrace_metric_ns ns); -static bool _test_ddtrace_metric_add_point( +static bool _test_datadog_metric_add_point( zend_string *nonnull name, double value, zend_string *nonnull tags); static void dd_trace_load_symbols(zend_module_entry *module) @@ -89,10 +89,10 @@ static void dd_trace_load_symbols(zend_module_entry *module) ASSIGN_DLSYM(_ddtrace_close_all_spans_and_flush, "ddtrace_close_all_spans_and_flush"); ASSIGN_DLSYM(_ddtrace_get_root_span, "ddtrace_get_root_span"); - ASSIGN_DLSYM(_ddtrace_runtime_id, "ddtrace_runtime_id"); + ASSIGN_DLSYM(_datadog_runtime_id, "datadog_runtime_id"); ASSIGN_DLSYM( - _ddtrace_get_formatted_session_id, "ddtrace_get_formatted_session_id"); - ASSIGN_DLSYM(_ddtrace_get_sidecar_queue_id, "ddtrace_get_sidecar_queue_id"); + _datadog_get_formatted_session_id, "datadog_get_formatted_session_id"); + ASSIGN_DLSYM(_datadog_get_sidecar_queue_id, "datadog_get_sidecar_queue_id"); ASSIGN_DLSYM(_ddtrace_set_priority_sampling_on_span_zobj, "ddtrace_set_priority_sampling_on_span_zobj"); ASSIGN_DLSYM(_ddtrace_get_priority_sampling_on_span_zobj, @@ -103,10 +103,10 @@ static void dd_trace_load_symbols(zend_module_entry *module) _ddtrace_user_req_add_listeners, "ddtrace_user_req_add_listeners"); ASSIGN_DLSYM(_ddtrace_ip_extraction_find, "ddtrace_ip_extraction_find"); ASSIGN_DLSYM( - _ddtrace_get_telemetry_rc_info, "ddtrace_get_telemetry_rc_info"); + _datadog_get_telemetry_rc_info, "datadog_get_telemetry_rc_info"); ASSIGN_DLSYM( - ddtrace_metric_register_buffer, "ddtrace_metric_register_buffer"); - ASSIGN_DLSYM(ddtrace_metric_add_point, "ddtrace_metric_add_point"); + datadog_metric_register_buffer, "datadog_metric_register_buffer"); + ASSIGN_DLSYM(datadog_metric_add_point, "datadog_metric_add_point"); ASSIGN_DLSYM(_ddtrace_emit_asm_event, "ddtrace_emit_asm_event"); ASSIGN_DLSYM( _ddtrace_guess_endpoint_from_url, "ddtrace_guess_endpoint_from_url"); @@ -150,11 +150,11 @@ void dd_trace_rinit(void) { _asm_event_emitted = false; } static void _setup_testing_telemetry_functions(void) { - if (ddtrace_metric_register_buffer == NULL) { - ddtrace_metric_register_buffer = _test_ddtrace_metric_register_buffer; + if (datadog_metric_register_buffer == NULL) { + datadog_metric_register_buffer = _test_datadog_metric_register_buffer; } - if (ddtrace_metric_add_point == NULL) { - ddtrace_metric_add_point = _test_ddtrace_metric_add_point; + if (datadog_metric_add_point == NULL) { + datadog_metric_add_point = _test_datadog_metric_add_point; } } @@ -323,7 +323,7 @@ zval *nullable dd_trace_span_get_meta_struct(zend_object *nonnull zobj) // NOLINTBEGIN(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers) zend_string *nullable dd_trace_get_formatted_runtime_id(bool persistent) { - if (_ddtrace_runtime_id == NULL) { + if (_datadog_runtime_id == NULL) { return NULL; } @@ -331,13 +331,13 @@ zend_string *nullable dd_trace_get_formatted_runtime_id(bool persistent) size_t length = sprintf(ZSTR_VAL(encoded_id), "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x", - _ddtrace_runtime_id[0], _ddtrace_runtime_id[1], _ddtrace_runtime_id[2], - _ddtrace_runtime_id[3], _ddtrace_runtime_id[4], _ddtrace_runtime_id[5], - _ddtrace_runtime_id[6], _ddtrace_runtime_id[7], _ddtrace_runtime_id[8], - _ddtrace_runtime_id[9], _ddtrace_runtime_id[10], - _ddtrace_runtime_id[11], _ddtrace_runtime_id[12], - _ddtrace_runtime_id[13], _ddtrace_runtime_id[14], - _ddtrace_runtime_id[15]); + _datadog_runtime_id[0], _datadog_runtime_id[1], _datadog_runtime_id[2], + _datadog_runtime_id[3], _datadog_runtime_id[4], _datadog_runtime_id[5], + _datadog_runtime_id[6], _datadog_runtime_id[7], _datadog_runtime_id[8], + _datadog_runtime_id[9], _datadog_runtime_id[10], + _datadog_runtime_id[11], _datadog_runtime_id[12], + _datadog_runtime_id[13], _datadog_runtime_id[14], + _datadog_runtime_id[15]); if (length != 36) { zend_string_free(encoded_id); @@ -350,18 +350,18 @@ zend_string *nullable dd_trace_get_formatted_runtime_id(bool persistent) const uint8_t *nullable dd_trace_get_formatted_session_id(void) { - if (_ddtrace_get_formatted_session_id == NULL) { + if (_datadog_get_formatted_session_id == NULL) { return NULL; } - return _ddtrace_get_formatted_session_id(); + return _datadog_get_formatted_session_id(); } uint64_t dd_trace_get_sidecar_queue_id(void) { - if (_ddtrace_get_sidecar_queue_id == NULL) { + if (_datadog_get_sidecar_queue_id == NULL) { return 0; } - return _ddtrace_get_sidecar_queue_id(); + return _datadog_get_sidecar_queue_id(); } void dd_trace_set_priority_sampling_on_span_zobj(zend_object *nonnull root_span, @@ -413,10 +413,10 @@ zend_string *nullable dd_ip_extraction_find(zval *nonnull server) struct telemetry_rc_info dd_trace_get_telemetry_rc_info(void) { - if (!_ddtrace_get_telemetry_rc_info) { + if (!_datadog_get_telemetry_rc_info) { return (struct telemetry_rc_info){0}; } - __auto_type tel_rc_info = _ddtrace_get_telemetry_rc_info(); + __auto_type tel_rc_info = _datadog_get_telemetry_rc_info(); mlog(dd_log_trace, "Remote config path: %s, service name: %.*s, env name: %.*s", @@ -601,19 +601,19 @@ static const zend_function_entry functions[] = { static void _register_testing_objects(void) { dd_phpobj_reg_funcs(functions); } -static void _test_ddtrace_metric_register_buffer( +static void _test_datadog_metric_register_buffer( zend_string *nonnull name, ddtrace_metric_type type, ddtrace_metric_ns ns) { php_error_docref(NULL, E_NOTICE, - "Would call ddtrace_metric_register_buffer with name=%.*s " + "Would call datadog_metric_register_buffer with name=%.*s " "type=%d ns=%d", (int)ZSTR_LEN(name), ZSTR_VAL(name), type, ns); } -static bool _test_ddtrace_metric_add_point( +static bool _test_datadog_metric_add_point( zend_string *nonnull name, double value, zend_string *nonnull tags) { php_error_docref(NULL, E_NOTICE, - "Would call to ddtrace_metric_add_point with name=%.*s value=%f " + "Would call to datadog_metric_add_point with name=%.*s value=%f " "tags=%.*s", (int)ZSTR_LEN(name), ZSTR_VAL(name), value, (int)ZSTR_LEN(tags), ZSTR_VAL(tags)); diff --git a/appsec/src/extension/ddtrace.h b/appsec/src/extension/ddtrace.h index 4b845bf0432..40cf764a6ce 100644 --- a/appsec/src/extension/ddtrace.h +++ b/appsec/src/extension/ddtrace.h @@ -121,7 +121,7 @@ typedef enum { DDTRACE_METRIC_NAMESPACE_SIDECAR, } ddtrace_metric_ns; -extern void (*nullable ddtrace_metric_register_buffer)( +extern void (*nullable datadog_metric_register_buffer)( zend_string *nonnull name, ddtrace_metric_type type, ddtrace_metric_ns ns); -extern bool (*nullable ddtrace_metric_add_point)(zend_string *nonnull name, +extern bool (*nullable datadog_metric_add_point)(zend_string *nonnull name, double value, zend_string *nonnull tags); diff --git a/appsec/src/extension/telemetry.c b/appsec/src/extension/telemetry.c index dcfc3271e3f..000f0cd0e5c 100644 --- a/appsec/src/extension/telemetry.c +++ b/appsec/src/extension/telemetry.c @@ -74,9 +74,9 @@ void dd_telemetry_note_helper_string_meta(const char *nonnull key, void dd_telemetry_add_metric(zend_string *nonnull name_zstr, double value, zend_string *nonnull tags_zstr, ddtrace_metric_type type) { - ddtrace_metric_register_buffer( + datadog_metric_register_buffer( name_zstr, type, DDTRACE_METRIC_NAMESPACE_APPSEC); - ddtrace_metric_add_point(name_zstr, value, tags_zstr); + datadog_metric_add_point(name_zstr, value, tags_zstr); mlog_g(dd_log_debug, "Telemetry metric %.*s added with tags %.*s and value %f", (int)ZSTR_LEN(name_zstr), ZSTR_VAL(name_zstr), (int)ZSTR_LEN(tags_zstr), @@ -162,8 +162,8 @@ void dd_telemetry_helper_conn_close(void) // NOLINTNEXTLINE(bugprone-easily-swappable-parameters) void dd_telemetry_submit_duration_ext(double waf_ext_us, double rasp_ext_us) { - if (!dd_trace_loaded() || ddtrace_metric_register_buffer == NULL || - ddtrace_metric_add_point == NULL) { + if (!dd_trace_loaded() || datadog_metric_register_buffer == NULL || + datadog_metric_add_point == NULL) { return; } @@ -173,16 +173,16 @@ void dd_telemetry_submit_duration_ext(double waf_ext_us, double rasp_ext_us) } if (waf_ext_us > 0.0) { - ddtrace_metric_register_buffer(_waf_duration_ext_tel_zstr, + datadog_metric_register_buffer(_waf_duration_ext_tel_zstr, DDTRACE_METRIC_TYPE_DISTRIBUTION, DDTRACE_METRIC_NAMESPACE_APPSEC); - ddtrace_metric_add_point( + datadog_metric_add_point( _waf_duration_ext_tel_zstr, waf_ext_us, tags_zstr); } if (rasp_ext_us > 0.0) { - ddtrace_metric_register_buffer(_rasp_duration_ext_tel_zstr, + datadog_metric_register_buffer(_rasp_duration_ext_tel_zstr, DDTRACE_METRIC_TYPE_DISTRIBUTION, DDTRACE_METRIC_NAMESPACE_APPSEC); - ddtrace_metric_add_point( + datadog_metric_add_point( _rasp_duration_ext_tel_zstr, rasp_ext_us, tags_zstr); } diff --git a/appsec/tests/integration/build.gradle b/appsec/tests/integration/build.gradle index 6f10f373ef6..e88073154a6 100644 --- a/appsec/tests/integration/build.gradle +++ b/appsec/tests/integration/build.gradle @@ -345,7 +345,7 @@ def buildTracerTask = { String version, String variant, altBaseTag = null -> '../../../ext', '../../../zend_abstract_interface', '../../../libdatadog', - '../../../ddtrace.sym', + '../../../datadog.sym', ], ], outputs: [ @@ -378,7 +378,7 @@ def buildTracerCmakeTask = { String version, String variant, altBaseTag = null - '../../../zend_abstract_interface', '../../../components-rs', '../../../libdatadog', - '../../../ddtrace.sym', + '../../../datadog.sym', '../../cmake', ], files: ['../../CMakeLists.txt', '../../cmake/ddtrace.cmake'], @@ -427,7 +427,7 @@ def buildTracerSsiTask = { String version, String variant -> '../../../zend_abstract_interface', '../../../components-rs', '../../../libdatadog', - '../../../ddtrace.sym', + '../../../datadog.sym', ], ], outputs: [ @@ -474,7 +474,7 @@ def buildTracerSsiCmakeTask = { String version, String variant -> '../../../zend_abstract_interface', '../../../components-rs', '../../../libdatadog', - '../../../ddtrace.sym', + '../../../datadog.sym', '../../cmake', ], files: ['../../CMakeLists.txt', '../../cmake/ddtrace.cmake'], diff --git a/appsec/third_party/CMakeLists.txt b/appsec/third_party/CMakeLists.txt index f09cfab64cf..7216bdca008 100644 --- a/appsec/third_party/CMakeLists.txt +++ b/appsec/third_party/CMakeLists.txt @@ -47,7 +47,7 @@ if(DD_APPSEC_BUILD_HELPER) endif() if(DD_APPSEC_BUILD_EXTENSION) - file(GLOB_RECURSE MPACK_C_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/../../ext/vendor/mpack/*.c) + file(GLOB_RECURSE MPACK_C_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/../../tracer/vendor/mpack/*.c) add_library(mpack OBJECT ${MPACK_C_SOURCES}) set_target_properties(mpack PROPERTIES POSITION_INDEPENDENT_CODE 1 @@ -55,7 +55,7 @@ if(DD_APPSEC_BUILD_EXTENSION) target_include_directories(mpack PUBLIC - ${CMAKE_CURRENT_SOURCE_DIR}/../../ext/vendor/mpack/ + ${CMAKE_CURRENT_SOURCE_DIR}/../../tracer/vendor/mpack/ ${CMAKE_CURRENT_SOURCE_DIR}/../src/extension/mpack/) target_link_libraries(mpack PUBLIC PhpConfig) # for the allocation functions target_compile_definitions(mpack PUBLIC MPACK_HAS_CONFIG=1) @@ -67,7 +67,7 @@ if(DD_APPSEC_BUILD_EXTENSION) if(DD_APPSEC_TESTING) add_library(mpack_malloc OBJECT ${MPACK_C_SOURCES}) - target_include_directories(mpack_malloc PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/../../ext/vendor/mpack/) + target_include_directories(mpack_malloc PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/../../tracer/vendor/mpack/) target_compile_definitions(mpack_malloc PUBLIC MPACK_STDIO=0 MPACK_WRITE_TRACKING=1 MPACK_BUFFER_SIZE=131072) endif() endif() diff --git a/components-rs/ddtrace.h b/components-rs/ddtrace.h index 7c575e34319..2fe95a6e2fe 100644 --- a/components-rs/ddtrace.h +++ b/components-rs/ddtrace.h @@ -9,21 +9,21 @@ struct _zend_string; #include "telemetry.h" #include "sidecar.h" -extern ddog_Uuid ddtrace_runtime_id; +extern ddog_Uuid datadog_runtime_id; -extern ddog_Uuid ddtrace_session_id; +extern ddog_Uuid datadog_session_id; -extern uint8_t ddtrace_formatted_session_id[36]; +extern uint8_t datadog_formatted_session_id[36]; -extern uint8_t ddtrace_formatted_root_session_id[36]; +extern uint8_t datadog_formatted_root_session_id[36]; -extern uint8_t ddtrace_formatted_parent_session_id[36]; +extern uint8_t datadog_formatted_parent_session_id[36]; extern void (*ddog_log_callback)(ddog_CharSlice); -extern ddog_VecRemoteConfigProduct DDTRACE_REMOTE_CONFIG_PRODUCTS; +extern ddog_VecRemoteConfigProduct DATADOG_REMOTE_CONFIG_PRODUCTS; -extern ddog_VecRemoteConfigCapabilities DDTRACE_REMOTE_CONFIG_CAPABILITIES; +extern ddog_VecRemoteConfigCapabilities DATADOG_REMOTE_CONFIG_CAPABILITIES; extern const uint8_t *DDOG_PHP_FUNCTION; @@ -31,15 +31,15 @@ extern const uint8_t *DDOG_PHP_FUNCTION; * # Safety * Must be called from a single-threaded context, such as MINIT or first rinit. */ -void ddtrace_generate_runtime_id(void); +void datadog_generate_runtime_id(void); /** * # Safety * Must be called from a single-threaded context, such as MINIT. */ -void ddtrace_generate_session_id(void); +void datadog_generate_session_id(void); -void ddtrace_format_runtime_id(uint8_t (*buf)[36]); +void datadog_format_runtime_id(uint8_t (*buf)[36]); ddog_CharSlice ddtrace_get_container_id(void); @@ -49,9 +49,9 @@ char *ddtrace_strip_invalid_utf8(const char *input, uintptr_t *len); void ddtrace_drop_rust_string(char *input, uintptr_t len); -struct ddog_Endpoint *ddtrace_parse_agent_url(ddog_CharSlice url); +struct ddog_Endpoint *datadog_parse_agent_url(ddog_CharSlice url); -void ddtrace_endpoint_as_crashtracker_config(const struct ddog_Endpoint *endpoint, +void datadog_endpoint_as_crashtracker_config(const struct ddog_Endpoint *endpoint, void (*callback)(ddog_crasht_EndpointConfig, void*), void *userdata); @@ -199,7 +199,7 @@ ddog_MaybeError ddog_sidecar_connect_php(struct ddog_SidecarTransport **connecti uint64_t backpressure_bytes, uint64_t backpressure_queue); -void ddtrace_sidecar_reconnect(struct ddog_SidecarTransport **transport, +void datadog_sidecar_reconnect(struct ddog_SidecarTransport **transport, struct ddog_SidecarTransport *(*factory)(void)); bool ddog_shm_limiter_inc(const struct ddog_MaybeShmLimiter *limiter, uint32_t limit); diff --git a/components-rs/lib.rs b/components-rs/lib.rs index bf9a2675ff2..5b785200416 100644 --- a/components-rs/lib.rs +++ b/components-rs/lib.rs @@ -30,38 +30,38 @@ pub use libdd_telemetry_ffi::*; #[no_mangle] #[allow(non_upper_case_globals)] -pub static mut ddtrace_runtime_id: Uuid = Uuid::nil(); +pub static mut datadog_runtime_id: Uuid = Uuid::nil(); #[no_mangle] #[allow(non_upper_case_globals)] -pub static mut ddtrace_session_id: Uuid = Uuid::nil(); +pub static mut datadog_session_id: Uuid = Uuid::nil(); #[no_mangle] #[allow(non_upper_case_globals)] -pub static mut ddtrace_formatted_session_id: [u8; 36] = [0u8; 36]; +pub static mut datadog_formatted_session_id: [u8; 36] = [0u8; 36]; #[no_mangle] #[allow(non_upper_case_globals)] -pub static mut ddtrace_formatted_root_session_id: [u8; 36] = [0u8; 36]; +pub static mut datadog_formatted_root_session_id: [u8; 36] = [0u8; 36]; #[no_mangle] #[allow(non_upper_case_globals)] -pub static mut ddtrace_formatted_parent_session_id: [u8; 36] = [0u8; 36]; +pub static mut datadog_formatted_parent_session_id: [u8; 36] = [0u8; 36]; /// # Safety /// Must be called from a single-threaded context, such as MINIT or first rinit. #[no_mangle] -pub unsafe extern "C" fn ddtrace_generate_runtime_id() { - ddtrace_runtime_id = Uuid::new_v4(); +pub unsafe extern "C" fn datadog_generate_runtime_id() { + datadog_runtime_id = Uuid::new_v4(); } /// # Safety /// Must be called from a single-threaded context, such as MINIT. #[no_mangle] -pub unsafe extern "C" fn ddtrace_generate_session_id() { - ddtrace_session_id = Uuid::new_v4(); - ddtrace_runtime_id = ddtrace_session_id; - ddtrace_session_id.as_hyphenated().encode_lower(&mut ddtrace_formatted_session_id); +pub unsafe extern "C" fn datadog_generate_session_id() { + datadog_session_id = Uuid::new_v4(); + datadog_runtime_id = datadog_session_id; + datadog_session_id.as_hyphenated().encode_lower(&mut datadog_formatted_session_id); unsafe fn set(name: &str, value: &mut [u8; 36], force: bool) { if let Ok(str) = std::env::var(name) { @@ -73,18 +73,18 @@ pub unsafe extern "C" fn ddtrace_generate_session_id() { } } } - std::env::set_var(name, OsStr::from_encoded_bytes_unchecked(&ddtrace_formatted_session_id)); + std::env::set_var(name, OsStr::from_encoded_bytes_unchecked(&datadog_formatted_session_id)); } - set("_DD_PARENT_PHP_SESSION_ID", &mut ddtrace_formatted_parent_session_id, true); - set("_DD_ROOT_PHP_SESSION_ID", &mut ddtrace_formatted_root_session_id, false); + set("_DD_PARENT_PHP_SESSION_ID", &mut datadog_formatted_parent_session_id, true); + set("_DD_ROOT_PHP_SESSION_ID", &mut datadog_formatted_root_session_id, false); } #[no_mangle] -pub extern "C" fn ddtrace_format_runtime_id(buf: &mut [u8; 36]) { - // Safety: ddtrace_runtime_id is only supposed to be mutated from single- +pub extern "C" fn datadog_format_runtime_id(buf: &mut [u8; 36]) { + // Safety: datadog_runtime_id is only supposed to be mutated from single- // threaded contexts, so reads should always be safe. - unsafe { ddtrace_runtime_id.as_hyphenated().encode_lower(buf) }; + unsafe { datadog_runtime_id.as_hyphenated().encode_lower(buf) }; } #[must_use] @@ -120,7 +120,7 @@ pub unsafe extern "C" fn ddtrace_drop_rust_string(input: *mut c_char, len: usize } #[no_mangle] -pub unsafe extern "C" fn ddtrace_parse_agent_url( +pub unsafe extern "C" fn datadog_parse_agent_url( url: CharSlice, ) -> std::option::Option> { parse_uri(url.to_utf8_lossy().as_ref()) @@ -147,7 +147,7 @@ pub unsafe extern "C" fn ddtrace_parse_agent_url( #[no_mangle] #[cfg(unix)] -pub unsafe extern "C" fn ddtrace_endpoint_as_crashtracker_config( +pub unsafe extern "C" fn datadog_endpoint_as_crashtracker_config( endpoint: &Endpoint, callback: unsafe extern "C" fn(EndpointConfig<'_>, *mut std::ffi::c_void), userdata: *mut std::ffi::c_void, diff --git a/components-rs/remote_config.rs b/components-rs/remote_config.rs index 515aede6f36..f9024eb77f9 100644 --- a/components-rs/remote_config.rs +++ b/components-rs/remote_config.rs @@ -53,11 +53,11 @@ static mut DYNAMIC_CONFIG_UPDATE: Option = None; type VecRemoteConfigProduct = libdd_common_ffi::Vec; #[no_mangle] -pub static mut DDTRACE_REMOTE_CONFIG_PRODUCTS: VecRemoteConfigProduct = libdd_common_ffi::Vec::new(); +pub static mut DATADOG_REMOTE_CONFIG_PRODUCTS: VecRemoteConfigProduct = libdd_common_ffi::Vec::new(); type VecRemoteConfigCapabilities = libdd_common_ffi::Vec; #[no_mangle] -pub static mut DDTRACE_REMOTE_CONFIG_CAPABILITIES: VecRemoteConfigCapabilities = +pub static mut DATADOG_REMOTE_CONFIG_CAPABILITIES: VecRemoteConfigCapabilities = libdd_common_ffi::Vec::new(); struct ActiveDynamicConfig { @@ -123,30 +123,30 @@ pub unsafe extern "C" fn ddog_init_remote_config( appsec_activation: bool, appsec_config: bool, ) { - DDTRACE_REMOTE_CONFIG_PRODUCTS.push(RemoteConfigProduct::ApmTracing); - DDTRACE_REMOTE_CONFIG_CAPABILITIES.push(RemoteConfigCapabilities::ApmTracingCustomTags); - DDTRACE_REMOTE_CONFIG_CAPABILITIES.push(RemoteConfigCapabilities::ApmTracingEnabled); - DDTRACE_REMOTE_CONFIG_CAPABILITIES.push(RemoteConfigCapabilities::ApmTracingHttpHeaderTags); - DDTRACE_REMOTE_CONFIG_CAPABILITIES.push(RemoteConfigCapabilities::ApmTracingLogsInjection); - DDTRACE_REMOTE_CONFIG_CAPABILITIES.push(RemoteConfigCapabilities::ApmTracingSampleRate); - DDTRACE_REMOTE_CONFIG_CAPABILITIES.push(RemoteConfigCapabilities::ApmTracingSampleRules); - DDTRACE_REMOTE_CONFIG_CAPABILITIES.push(RemoteConfigCapabilities::ApmTracingMulticonfig); - - DDTRACE_REMOTE_CONFIG_PRODUCTS.push(RemoteConfigProduct::AsmFeatures); - DDTRACE_REMOTE_CONFIG_CAPABILITIES.push(RemoteConfigCapabilities::AsmAutoUserInstrumMode); + DATADOG_REMOTE_CONFIG_PRODUCTS.push(RemoteConfigProduct::ApmTracing); + DATADOG_REMOTE_CONFIG_CAPABILITIES.push(RemoteConfigCapabilities::ApmTracingCustomTags); + DATADOG_REMOTE_CONFIG_CAPABILITIES.push(RemoteConfigCapabilities::ApmTracingEnabled); + DATADOG_REMOTE_CONFIG_CAPABILITIES.push(RemoteConfigCapabilities::ApmTracingHttpHeaderTags); + DATADOG_REMOTE_CONFIG_CAPABILITIES.push(RemoteConfigCapabilities::ApmTracingLogsInjection); + DATADOG_REMOTE_CONFIG_CAPABILITIES.push(RemoteConfigCapabilities::ApmTracingSampleRate); + DATADOG_REMOTE_CONFIG_CAPABILITIES.push(RemoteConfigCapabilities::ApmTracingSampleRules); + DATADOG_REMOTE_CONFIG_CAPABILITIES.push(RemoteConfigCapabilities::ApmTracingMulticonfig); + + DATADOG_REMOTE_CONFIG_PRODUCTS.push(RemoteConfigProduct::AsmFeatures); + DATADOG_REMOTE_CONFIG_CAPABILITIES.push(RemoteConfigCapabilities::AsmAutoUserInstrumMode); if appsec_activation { - DDTRACE_REMOTE_CONFIG_CAPABILITIES.push(RemoteConfigCapabilities::AsmActivation); + DATADOG_REMOTE_CONFIG_CAPABILITIES.push(RemoteConfigCapabilities::AsmActivation); } if live_debugging_enabled { - DDTRACE_REMOTE_CONFIG_PRODUCTS.push(RemoteConfigProduct::LiveDebugger) + DATADOG_REMOTE_CONFIG_PRODUCTS.push(RemoteConfigProduct::LiveDebugger) } if appsec_config { - DDTRACE_REMOTE_CONFIG_PRODUCTS.push(RemoteConfigProduct::AsmData); - DDTRACE_REMOTE_CONFIG_PRODUCTS.push(RemoteConfigProduct::AsmDD); - DDTRACE_REMOTE_CONFIG_PRODUCTS.push(RemoteConfigProduct::Asm); + DATADOG_REMOTE_CONFIG_PRODUCTS.push(RemoteConfigProduct::AsmData); + DATADOG_REMOTE_CONFIG_PRODUCTS.push(RemoteConfigProduct::AsmDD); + DATADOG_REMOTE_CONFIG_PRODUCTS.push(RemoteConfigProduct::Asm); [ RemoteConfigCapabilities::AsmIpBlocking, RemoteConfigCapabilities::AsmDdRules, @@ -170,7 +170,7 @@ pub unsafe extern "C" fn ddog_init_remote_config( RemoteConfigCapabilities::AsmCustomDataScanners, ] .iter() - .for_each(|c| DDTRACE_REMOTE_CONFIG_CAPABILITIES.push(*c)); + .for_each(|c| DATADOG_REMOTE_CONFIG_CAPABILITIES.push(*c)); } } diff --git a/components-rs/sidecar.rs b/components-rs/sidecar.rs index 499a7b3e7b5..bd02688c1bb 100644 --- a/components-rs/sidecar.rs +++ b/components-rs/sidecar.rs @@ -160,7 +160,7 @@ pub extern "C" fn ddog_sidecar_connect_php( } #[no_mangle] -pub extern "C" fn ddtrace_sidecar_reconnect( +pub extern "C" fn datadog_sidecar_reconnect( transport: &mut Box, factory: unsafe extern "C" fn() -> Option>, ) { diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 5920bce6ce0..0a6836e0c88 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -52,7 +52,6 @@ add_library(datadog_php_components INTERFACE) add_subdirectory(string_view) -add_subdirectory(container_id) add_subdirectory(sapi) add_subdirectory(stack-sample) diff --git a/components/container_id/CMakeLists.txt b/components/container_id/CMakeLists.txt deleted file mode 100644 index 08706e31684..00000000000 --- a/components/container_id/CMakeLists.txt +++ /dev/null @@ -1,37 +0,0 @@ -add_library(datadog_php_container_id container_id.c) - -target_include_directories(datadog_php_container_id - PUBLIC - $ - $ -) - -target_compile_features(datadog_php_container_id - PUBLIC c_std_99 -) - -set_target_properties(datadog_php_container_id PROPERTIES - EXPORT_NAME ContainerId - VERSION ${PROJECT_VERSION} -) - -add_library(Datadog::Php::ContainerId - ALIAS datadog_php_container_id -) - -if (${DATADOG_PHP_TESTING}) - add_subdirectory(tests) -endif () - -# This copies the include files when `install` is ran -install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/container_id.h - DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/container_id/ -) - -target_link_libraries(datadog_php_components - INTERFACE datadog_php_container_id -) - -install(TARGETS datadog_php_container_id - EXPORT DatadogPhpComponentsTargets -) diff --git a/components/container_id/container_id.c b/components/container_id/container_id.c deleted file mode 100644 index 1c5fd59c2f7..00000000000 --- a/components/container_id/container_id.c +++ /dev/null @@ -1,251 +0,0 @@ -#include "container_id.h" - -#include -#include -#include -#include - -/* The Oniguruma library breaks extended regular expressions (ERE) in POSIX - * regex (REG_EXTENDED) until 6.9.5-rc1. Simply linking the library '-lonig' - * will cause the bug to occur. Starting in PHP 7.4, Oniguruma is no longer - * bundled with ext/mbstring, but is linked in ('-lonig') so we cannot reliably - * use ERE here. Basic regular expressions (BRE) do not seem to be affected by - * this bug therefore we used BRE syntax for the container ID pattern matching. - * - * https://github.com/kkos/oniguruma/issues/233 - * https://www.php.net/manual/en/mbstring.installation.php - */ -#define LINE_REGEX "^[0-9]\\{1,20\\}:[^:]*:.*$" // Original ERE: "^[0-9]+:[^:]*:.+$" -/* Examples of some valid container IDs. - * - * Docker - * 13:name=systemd:/docker/3726184226f5d3147c25fdeab5b60097e378e8a720503a5e19ecfdf29f869860 - * - * Kubernetes - * 11:perf_event:/kubepods/something/pod3d274242-8ee0-11e9-a8a6-1e68d864ef1a/3e74d3fd9db4c9dd921ae05c2502fb984d0cde1b36e581b13f79c639da4518a1 - * - * ECS - * 9:perf_event:/ecs/user-ecs-classic/5a0d5ceddf6c44c1928d367a815d890f/38fac3e99302b3622be089dd41e7ccf38aff368a86cc339972075136ee2710ce - * - * Fargate < 1.4 - * 11:something:/ecs/5a081c13-b8cf-4801-b427-f4601742204d/432624d2150b349fe35ba397284dea788c2bf66b885d14dfc1569b01890ca7da - */ -#define CONTAINER_REGEX "[0-9a-f]\\{64\\}" // Original ERE: "[0-9a-f]{64}" -/* Example of a valid task ID. - * - * Fargate 1.4+ - * 1:name=systemd:/ecs/34dc0b5e626f2c5c4c5170e34b10e765-1234567890 - */ -#define TASK_REGEX "[0-9a-f]\\{32\\}-[0-9]\\{1,20\\}" // Original ERE: "[0-9a-f]{32}-[0-9]+" - -typedef datadog_php_container_id_parser dd_parser; - -static bool dd_parser_is_valid_line(dd_parser *parser, const char *line) { - return regexec(&parser->line_regex, line, 0, NULL, 0) == 0; -} - -#define TASK_ID_MIN_LEN (32 + 1 + 1) // [0-9a-f]{32}-[0-9]{1} -#define TASK_ID_MAX_LEN (32 + 1 + 20) // [0-9a-f]{32}-[0-9]{20} - -static bool dd_parser_extract_task_id(dd_parser *parser, char *buf, const char *line) { - if (regexec(&parser->task_regex, line, 0, NULL, 0) != 0) return false; - - /* Normally we would just use 'regmatch_t' for position matching and - * extract the desired string from the matched position. But - * unfortunately if Oniguruma <= 6.9.4 is linked in, the POSIX regex - * symbols are overridden with Oniguruma flavored ones and 'regmatch_t' - * will be mangled so we cannot use it here. - * - * Ideally we would fall back to extracting the IDs using sscanf(), but - * since there is no format directive for a minimum or exact field width, - * sscanf() will often pull out other parts of the cgroup line that are - * not part of the target ID. - * - * That leaves us with our final old-school fallback of traversing the - * string one character at a time to find start and end of the target ID. - */ - const char *start = line; - size_t len = strlen(line); - - /* Traverse the string to find a task ID with the following pattern: - * - * [0-9a-f]{32}-[0-9]{1,20} - * - */ - while ((size_t)(start - line + TASK_ID_MIN_LEN) <= len) { - /* We start off looking for 32 hex chars in a row: [0-9a-f]{32} */ - size_t task_len = 0; - while (task_len < 32 && isxdigit(start[task_len])) { - ++task_len; - } - - /* After exactly 32 hex characters, there should be a hyphen: - */ - if (task_len != 32 || start[task_len] != '-') { - start++; - continue; - } - ++task_len; - - /* Finally there should be an unsigned 64-bit int: [0-9]{1,20} */ - while (task_len < TASK_ID_MAX_LEN && isdigit(start[task_len])) { - ++task_len; - } - - /* We must capture at least one number. */ - if (task_len < TASK_ID_MIN_LEN) { - start++; - continue; - } - - /* We have a valid task ID at this point so we can ignore the rest of - * the line. - */ - memcpy(buf, start, task_len); - buf[task_len] = '\0'; - - return true; - } - - /* If we made it down here that means our regex pattern matched but we - * failed to manually extract the ID from the string. - */ - return false; -} - -#define CONTAINER_ID_LEN 64 // [0-9a-f]{64} - -static bool dd_parser_extract_container_id(dd_parser *parser, char *buf, const char *line) { - if (regexec(&parser->container_regex, line, 0, NULL, 0) != 0) return false; - - /* We cannot use 'regmatch_t' for position matching due to the possibility - * of Oniguruma <= 6.9.4 being linked nor can we use sscanf() (as explained - * in comments above). So we fall back to traversing the string - * character-by-character to find the start and end positions of the target - * ID. - */ - const char *start = line; - size_t len = strlen(line); - - /* Traverse the string to find a container ID with the following pattern: - * - * [0-9a-f]{64} - * - */ - while ((size_t)(start - line + CONTAINER_ID_LEN) <= len) { - /* We need exactly 64 hex characters in a row. */ - size_t id_len = 0; - while (id_len < CONTAINER_ID_LEN && isxdigit(start[id_len])) { - ++id_len; - } - - if (id_len != CONTAINER_ID_LEN) { - start++; - continue; - } - - /* We have a valid container ID at this point so we can ignore the rest - * of the line. - */ - memcpy(buf, start, id_len); - buf[id_len] = '\0'; - - return true; - } - - /* If we made it down here that means our regex pattern matched but we - * failed to manually extract the ID from the string. - */ - return false; -} - -bool datadog_php_container_id_parser_ctor(dd_parser *parser) { - if (parser == NULL) return false; - - /* According to the in-code docs: - * - * "Note that the translate table must either have been initialized by - * 'regcomp', with a malloc'ed value, or set to NULL before calling - * 'regfree'." - * https://elixir.bootlin.com/glibc/latest/source/posix/regex.h#L535 - * - * For this reason we zero-out all of the 'regex_t' patterns so that we can - * still call regfree() on them if regcomp() fails to initialize the - * pattern buffer. - */ - memset(parser, 0, sizeof *parser); - - int l_res = regcomp(&parser->line_regex, LINE_REGEX, REG_NOSUB); - int t_res = regcomp(&parser->task_regex, TASK_REGEX, REG_NOSUB); - int c_res = regcomp(&parser->container_regex, CONTAINER_REGEX, REG_NOSUB); - if (l_res != 0 || t_res != 0 || c_res != 0) { - datadog_php_container_id_parser_dtor(parser); - return false; - } - - parser->is_valid_line = dd_parser_is_valid_line; - parser->extract_task_id = dd_parser_extract_task_id; - parser->extract_container_id = dd_parser_extract_container_id; - - return true; -} - -bool datadog_php_container_id_parser_dtor(dd_parser *parser) { - if (parser == NULL) return false; - - regfree(&parser->container_regex); - regfree(&parser->task_regex); - regfree(&parser->line_regex); - - return true; -} - -bool datadog_php_container_id_from_file(char *buf, const char *file) { - FILE *fp; - - if (buf == NULL) return false; - - buf[0] = '\0'; - - if (file == NULL || file[0] == '\0' || (fp = fopen(file, "r")) == NULL) return false; - - dd_parser parser; - if (datadog_php_container_id_parser_ctor(&parser) == false) { - fclose(fp); - return false; - } - - char line[1024]; - while (!feof(fp)) { - if (fgets(line, sizeof line, fp) == NULL) continue; - - /* Match a valid cgroup line. */ - if (!parser.is_valid_line(&parser, line)) { - /* This does not look like a valid cgroup line so we skip it. */ - continue; - } - - /* Match a task ID and fill into buf. */ - if (parser.extract_task_id(&parser, buf, line)) { - /* We found a task ID which takes precedence over a standard - * container ID so we can stop scanning the file. - */ - break; - } - - /* Match a container ID and fill into empty buf. */ - if (buf[0] == '\0' && parser.extract_container_id(&parser, buf, line)) { - /* We found a valid container ID but we cannot stop scanning the - * file because there might be a task ID in the file (as is the - * case with Fargate 1.4+) and those take precedence over standard - * container IDs. - */ - /* break; */ - } - } - - /* This only fails if parser is NULL. */ - (void)datadog_php_container_id_parser_dtor(&parser); - fclose(fp); - - return true; -} diff --git a/components/container_id/container_id.h b/components/container_id/container_id.h deleted file mode 100644 index 9f81a74dde6..00000000000 --- a/components/container_id/container_id.h +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef DATADOG_PHP_CONTAINER_ID_H -#define DATADOG_PHP_CONTAINER_ID_H - -#include -#include -// comment to ensure both defs are before regex.h -#include -#include - -/* Fargate 1.4+ IDs match: - * [0-9a-f]{32}-\d+ - * Assuming it is possible for '\d+' to be a single digit, the shortest - * expected ID would be 32 + 1 + 1 = 34. - * Assuming '\d+' is an unsigned 64-bit integer, the maximum possible value is - * 18446744073709551615 which is 20 characters long. Thus the longest possible - * Fargate 1.4+ ID would be 32 + 1 + 20 = 53 characters long. - * - * Most of the container IDs match: - * [0-9a-f]{64} - * This makes the longest expected ID 64 characters long. - */ -#define DATADOG_PHP_CONTAINER_ID_MAX_LEN 64 - -typedef struct datadog_php_container_id_parser { - regex_t line_regex; - regex_t task_regex; - regex_t container_regex; - bool (*is_valid_line)(struct datadog_php_container_id_parser *parser, const char *line); - bool (*extract_task_id)(struct datadog_php_container_id_parser *parser, char *buf, const char *line); - bool (*extract_container_id)(struct datadog_php_container_id_parser *parser, char *buf, const char *line); -} datadog_php_container_id_parser; - -bool datadog_php_container_id_parser_ctor(datadog_php_container_id_parser *parser); -bool datadog_php_container_id_parser_dtor(datadog_php_container_id_parser *parser); - -bool datadog_php_container_id_from_file(char *buf, const char *file); - -#endif // DATADOG_PHP_CONTAINER_ID_H diff --git a/components/container_id/tests/CMakeLists.txt b/components/container_id/tests/CMakeLists.txt deleted file mode 100644 index ba8ec4f9eb5..00000000000 --- a/components/container_id/tests/CMakeLists.txt +++ /dev/null @@ -1,15 +0,0 @@ -add_executable(container_id - container_id_from_file.cc - container_id_parser.cc -) - -target_link_libraries(container_id - PUBLIC Catch2::Catch2WithMain Datadog::Php::ContainerId -) - -file( - COPY ${CMAKE_CURRENT_SOURCE_DIR}/stubs - DESTINATION ${CMAKE_CURRENT_BINARY_DIR} -) - -catch_discover_tests(container_id) diff --git a/components/container_id/tests/container_id_from_file.cc b/components/container_id/tests/container_id_from_file.cc deleted file mode 100644 index 4f32e00bd9c..00000000000 --- a/components/container_id/tests/container_id_from_file.cc +++ /dev/null @@ -1,115 +0,0 @@ -extern "C" { -#include -} - -#include -#include - -TEST_CASE("parse a Docker container ID", "[container_id]") { - char id[DATADOG_PHP_CONTAINER_ID_MAX_LEN + 1]; - REQUIRE(datadog_php_container_id_from_file(id, "./stubs/cgroup.docker")); - REQUIRE(strcmp("9d5b23edb1ba181e8910389a99906598d69ac9a0ead109ee55730cc416d95f7f", id) == 0); -} - -TEST_CASE("parse a Kubernetes container ID", "[container_id]") { - char id[DATADOG_PHP_CONTAINER_ID_MAX_LEN + 1]; - REQUIRE(datadog_php_container_id_from_file(id, "./stubs/cgroup.kubernetes")); - REQUIRE(strcmp("3e74d3fd9db4c9dd921ae05c2502fb984d0cde1b36e581b13f79c639da4518a1", id) == 0); -} - -TEST_CASE("parse an ECS container ID", "[container_id]") { - char id[DATADOG_PHP_CONTAINER_ID_MAX_LEN + 1]; - REQUIRE(datadog_php_container_id_from_file(id, "./stubs/cgroup.ecs")); - REQUIRE(strcmp("38fac3e99302b3622be089dd41e7ccf38aff368a86cc339972075136ee2710ce", id) == 0); -} - -TEST_CASE("parse a Fargate container ID", "[container_id]") { - char id[DATADOG_PHP_CONTAINER_ID_MAX_LEN + 1]; - REQUIRE(datadog_php_container_id_from_file(id, "./stubs/cgroup.fargate")); - REQUIRE(strcmp("432624d2150b349fe35ba397284dea788c2bf66b885d14dfc1569b01890ca7da", id) == 0); -} - -TEST_CASE("parse a Fargate 1.4+ container ID", "[container_id]") { - char id[DATADOG_PHP_CONTAINER_ID_MAX_LEN + 1]; - REQUIRE(datadog_php_container_id_from_file(id, "./stubs/cgroup.fargate.1.4")); - REQUIRE(strcmp("34dc0b5e626f2c5c4c5170e34b10e765-1234567890", id) == 0); -} - -/* Whitespace around the matching ID is permitted so long as it is matched - * within a valid cgroup line. - */ -TEST_CASE("parse a container ID with leading and trailing whitespace", "[container_id]") { - char id[DATADOG_PHP_CONTAINER_ID_MAX_LEN + 1]; - REQUIRE(datadog_php_container_id_from_file(id, "./stubs/cgroup.whitespace")); - REQUIRE(strcmp("3726184226f5d3147c25fdeab5b60097e378e8a720503a5e19ecfdf29f869860", id) == 0); -} - -TEST_CASE("a non-container Linux cgroup file makes an empty string", "[container_id]") { - char id[DATADOG_PHP_CONTAINER_ID_MAX_LEN + 1]; - REQUIRE(datadog_php_container_id_from_file(id, "./stubs/cgroup.linux")); - REQUIRE(id[0] == '\0'); -} - -TEST_CASE("missing cgroup file makes an empty string", "[container_id]") { - char id[DATADOG_PHP_CONTAINER_ID_MAX_LEN + 1]; - REQUIRE(false == datadog_php_container_id_from_file(id, "/path/to/cgroup.missing")); - REQUIRE(id[0] == '\0'); -} - -/* To be consistent with other tracers, unrecognized services that match the - * generic container ID regex patterns are considered valid. - */ -TEST_CASE("parse unrecognized container ID", "[container_id]") { - char id[DATADOG_PHP_CONTAINER_ID_MAX_LEN + 1]; - REQUIRE(datadog_php_container_id_from_file(id, "./stubs/cgroup.unrecognized")); - REQUIRE(strcmp("9d5b23edb1ba181e8910389a99906598d69ac9a0ead109ee55730cc416d95f7f", id) == 0); -} - -TEST_CASE("error edge cases when parsing container ID", "[container_id]") { - char id[DATADOG_PHP_CONTAINER_ID_MAX_LEN + 1]; - REQUIRE(datadog_php_container_id_from_file(id, "./stubs/cgroup.edge_cases")); - REQUIRE(id[0] == '\0'); -} - -TEST_CASE("a NULL cgroup file makes an empty string", "[container_id]") { - char id[DATADOG_PHP_CONTAINER_ID_MAX_LEN + 1]; - REQUIRE(false == datadog_php_container_id_from_file(id, nullptr)); - REQUIRE(id[0] == '\0'); -} - -TEST_CASE("a NULL buf does not crash", "[container_id]") { - REQUIRE(false == datadog_php_container_id_from_file(nullptr, "./stubs/cgroup.docker")); - REQUIRE(true); -} - -TEST_CASE("an empty cgroup file makes an empty string", "[container_id]") { - char id[DATADOG_PHP_CONTAINER_ID_MAX_LEN + 1]; - REQUIRE(false == datadog_php_container_id_from_file(id, "")); - REQUIRE(id[0] == '\0'); -} - -TEST_CASE("the buffer defaults to an empty string", "[container_id]") { - char id[DATADOG_PHP_CONTAINER_ID_MAX_LEN + 1]; - id[0] = 'a'; - REQUIRE(false == datadog_php_container_id_from_file(id, "")); - REQUIRE(id[0] == '\0'); -} - -TEST_CASE("valid container ID with invalid line pattern makes an empty string", "[container_id]") { - char id[DATADOG_PHP_CONTAINER_ID_MAX_LEN + 1]; - REQUIRE(datadog_php_container_id_from_file(id, "./stubs/cgroup.invalid_line_container_id")); - REQUIRE(id[0] == '\0'); -} - -TEST_CASE("valid task ID with invalid line pattern makes an empty string", "[container_id]") { - char id[DATADOG_PHP_CONTAINER_ID_MAX_LEN + 1]; - REQUIRE(datadog_php_container_id_from_file(id, "./stubs/cgroup.invalid_line_task_id")); - REQUIRE(id[0] == '\0'); -} - -/* To be consistent with other tracers we only match lower case hex. */ -TEST_CASE("uppercase container IDs return an empty string", "[container_id]") { - char id[DATADOG_PHP_CONTAINER_ID_MAX_LEN + 1]; - REQUIRE(datadog_php_container_id_from_file(id, "./stubs/cgroup.upper")); - REQUIRE(id[0] == '\0'); -} diff --git a/components/container_id/tests/container_id_parser.cc b/components/container_id/tests/container_id_parser.cc deleted file mode 100644 index bbaea56563d..00000000000 --- a/components/container_id/tests/container_id_parser.cc +++ /dev/null @@ -1,216 +0,0 @@ -extern "C" { -#include -} - -#include -#include - -#define MAX_ID_LEN DATADOG_PHP_CONTAINER_ID_MAX_LEN - -typedef datadog_php_container_id_parser dd_parser; - -TEST_CASE("parser: valid cgroup lines", "[container_id_parser]") { - dd_parser parser; - REQUIRE(datadog_php_container_id_parser_ctor(&parser)); - - const char *lines[] = { - "4:perf_event:/", - "1:name=systemd:/ecs/34dc0b5e626f2c5c4c5170e34b10e765-1234567890", - "2:memory:/ecs/55091c13-b8cf-4801-b527-f4601742204d/432624d2150b349fe35ba397284dea788c2bf66b885d14dfc1569b01890ca7da", - "7:pids:/user.slice/user-0.slice/session-14.scope", - "7:pids:/user.slice/user-0.slice/session-14.scope\n", - "1::/", - "0::", - }; - - for (const char *line : lines) { - REQUIRE(parser.is_valid_line(&parser, line)); - } - - REQUIRE(datadog_php_container_id_parser_dtor(&parser)); -} - -TEST_CASE("parser: invalid cgroup lines", "[container_id_parser]") { - dd_parser parser; - REQUIRE(datadog_php_container_id_parser_ctor(&parser)); - - const char *lines[] = { - "foo line", "a4:perf_event:/", ":perf_event:/", "1:perf_event", "\n", "", - }; - - for (const char *line : lines) { - REQUIRE(false == parser.is_valid_line(&parser, line)); - } - - REQUIRE(datadog_php_container_id_parser_dtor(&parser)); -} - -TEST_CASE("parser: successfully parse a container ID", "[container_id_parser]") { - dd_parser parser; - REQUIRE(datadog_php_container_id_parser_ctor(&parser)); - - const char *lines[] = { - "9d5b23edb1ba181e8910389a99906598d69ac9a0ead109ee55730cc416d95f7f", - "12:pids:/docker/9d5b23edb1ba181e8910389a99906598d69ac9a0ead109ee55730cc416d95f7f", - "1::9d5b23edb1ba181e8910389a99906598d69ac9a0ead109ee55730cc416d95f7f", - "1:devices:9d5b23edb1ba181e8910389a99906598d69ac9a0ead109ee55730cc416d95f7f\n", - "1:devices: 9d5b23edb1ba181e8910389a99906598d69ac9a0ead109ee55730cc416d95f7f ", - "1:name=systemd:/ecs/9d5b23edb1ba181e8910389a99906598d69ac9a0ead109ee55730cc416d95f7f/34dc0b5e626f2c5c4c5170e34b10e765-1234567890", // Contains valid task ID - "8:net_cls,net_prio:/ecs/55091c13-b8cf-4801-b527-f4601742204d/9d5b23edb1ba181e8910389a99906598d69ac9a0ead109ee55730cc416d95f7f", - }; - - char buf[MAX_ID_LEN + 1] = {0}; - - for (const char *line : lines) { - memset(buf, 0, sizeof buf); - REQUIRE(buf[0] == '\0'); - - REQUIRE(parser.extract_container_id(&parser, buf, line)); - REQUIRE(strcmp("9d5b23edb1ba181e8910389a99906598d69ac9a0ead109ee55730cc416d95f7f", buf) == 0); - } - - REQUIRE(datadog_php_container_id_parser_dtor(&parser)); -} - -TEST_CASE("parser: fail to parse a container ID", "[container_id_parser]") { - dd_parser parser; - REQUIRE(datadog_php_container_id_parser_ctor(&parser)); - - const char *lines[] = { - "d5b23edb1ba181e8910389a99906598d69ac9a0ead109ee55730cc416d95f7f", // 63 characters - "34dc0b5e626f2c5c4c5170e34b10e765-1234567890", // Task ID - "", - "a", - "zd5b23edb1ba181e8910389a99906598d69ac9a0ead109ee55730cc416d95f7f", - }; - - char buf[MAX_ID_LEN + 1] = {0}; - - for (const char *line : lines) { - memset(buf, 0, sizeof buf); - REQUIRE(buf[0] == '\0'); - - REQUIRE(false == parser.extract_container_id(&parser, buf, line)); - REQUIRE(buf[0] == '\0'); - } - - REQUIRE(datadog_php_container_id_parser_dtor(&parser)); -} - -TEST_CASE("parser: successfully parse a task ID", "[container_id_parser]") { - dd_parser parser; - REQUIRE(datadog_php_container_id_parser_ctor(&parser)); - - const char *lines[] = { - "34dc0b5e626f2c5c4c5170e34b10e765-1234567890", - "2:memory:/ecs/55091c13-b8cf-4801-b527-f4601742204d/34dc0b5e626f2c5c4c5170e34b10e765-1234567890", - "aaaaaaaaaa34dc0b5e626f2c5c4c5170e34b10e765-1234567890aaaaaaa", - "1:name=systemd:/ecs/34dc0b5e626f2c5c4c5170e34b10e765-1234567890", - "1:name=systemd:/ecs/ 34dc0b5e626f2c5c4c5170e34b10e765-1234567890", - "1:name=systemd:/ecs/ 34dc0b5e626f2c5c4c5170e34b10e765-1234567890 ", - "1:name=systemd:/ecs/55091c13-b8cf-4801-b527-f4601742204d/34dc0b5e626f2c5c4c5170e34b10e765-1234567890", - "1:name=systemd:/ecs/9d5b23edb1ba181e8910389a99906598d69ac9a0ead109ee55730cc416d95f7f/34dc0b5e626f2c5c4c5170e34b10e765-1234567890", // Contains valid container ID - }; - - char buf[MAX_ID_LEN + 1] = {0}; - - for (const char *line : lines) { - memset(buf, 0, sizeof buf); - REQUIRE(buf[0] == '\0'); - - REQUIRE(parser.extract_task_id(&parser, buf, line)); - REQUIRE(strcmp("34dc0b5e626f2c5c4c5170e34b10e765-1234567890", buf) == 0); - } - - REQUIRE(datadog_php_container_id_parser_dtor(&parser)); -} - -TEST_CASE("parser: successfully parse a task ID variations", "[container_id_parser]") { - dd_parser parser; - REQUIRE(datadog_php_container_id_parser_ctor(&parser)); - - const char *line; - char buf[MAX_ID_LEN + 1] = {0}; - - /* We wrap these in SECTIONs so that buf gets reset every time. */ - - SECTION("successful task ID 0") { - line = "34dc0b5e626f2c5c4c5170e34b10e765-1"; - - REQUIRE(parser.extract_task_id(&parser, buf, line)); - REQUIRE(strcmp("34dc0b5e626f2c5c4c5170e34b10e765-1", buf) == 0); - } - - SECTION("successful task ID 1") { - line = "34dc0b5e626f2c5c4c5170e34b10e765-12345678901234567890"; - - REQUIRE(parser.extract_task_id(&parser, buf, line)); - REQUIRE(strcmp("34dc0b5e626f2c5c4c5170e34b10e765-12345678901234567890", buf) == 0); - } - - SECTION("successful task ID 2") { - line = "34dc0b5e626f2c5c4c5170e34b10e765-123456789012345678900000000000000000000000000"; - - REQUIRE(parser.extract_task_id(&parser, buf, line)); - REQUIRE(strcmp("34dc0b5e626f2c5c4c5170e34b10e765-12345678901234567890", buf) == 0); - } - - SECTION("successful task ID 3") { - line = "34dc0b5e626f2c5c4c5170e34b10e765-123456789012345678900000000000000000000000000"; - - REQUIRE(parser.extract_task_id(&parser, buf, line)); - REQUIRE(strcmp("34dc0b5e626f2c5c4c5170e34b10e765-12345678901234567890", buf) == 0); - } - - SECTION("successful task ID 4") { - line = "aaaa0b5e626f2c5c4c5170e34b10e765-1234567890bbbb0b5e626f2c5c4c5170e34b10e765-1234567890"; - - REQUIRE(parser.extract_task_id(&parser, buf, line)); - REQUIRE(strcmp("aaaa0b5e626f2c5c4c5170e34b10e765-1234567890", buf) == 0); - } - - REQUIRE(datadog_php_container_id_parser_dtor(&parser)); -} - -TEST_CASE("parser: fail to parse a task ID", "[container_id_parser]") { - dd_parser parser; - REQUIRE(datadog_php_container_id_parser_ctor(&parser)); - - const char *lines[] = { - "4dc0b5e626f2c5c4c5170e34b10e765-1234567890", // 31 hex characters - "9d5b23edb1ba181e8910389a99906598d69ac9a0ead109ee55730cc416d95f7f", // Container ID - "34dc0b5e626f2c5c4c5170e34b10e765-", - "a-0", - "", - "a", - "\n", - }; - - char buf[MAX_ID_LEN + 1] = {0}; - - for (const char *line : lines) { - memset(buf, 0, sizeof buf); - REQUIRE(buf[0] == '\0'); - - REQUIRE(false == parser.extract_task_id(&parser, buf, line)); - REQUIRE(buf[0] == '\0'); - } - - REQUIRE(datadog_php_container_id_parser_dtor(&parser)); -} - -/* This specific k8s example was reported as not being parsed correctly on the - * Python tracer. - * https://github.com/DataDog/dd-trace-py/issues/2314 - */ -TEST_CASE("parser: successfully parse a Kubernetes container ID", "[container_id_parser]") { - dd_parser parser; - char buf[MAX_ID_LEN + 1] = {0}; - const char line[] = - "1:name=systemd:/kubepods.slice/kubepods-burstable.slice/kubepods-burstable-pod2d3da189_6407_48e3_9ab6_78188d75e609.slice/docker-7b8952daecf4c0e44bbcefe1b5c5ebc7b4839d4eefeccefe694709d3809b6199.scope"; - - REQUIRE(datadog_php_container_id_parser_ctor(&parser)); - REQUIRE(parser.extract_container_id(&parser, buf, line)); - REQUIRE(strcmp("7b8952daecf4c0e44bbcefe1b5c5ebc7b4839d4eefeccefe694709d3809b6199", buf) == 0); - REQUIRE(datadog_php_container_id_parser_dtor(&parser)); -} diff --git a/components/container_id/tests/stubs/cgroup.docker b/components/container_id/tests/stubs/cgroup.docker deleted file mode 100644 index 72aaa1b90a9..00000000000 --- a/components/container_id/tests/stubs/cgroup.docker +++ /dev/null @@ -1,14 +0,0 @@ -14:name=systemd:/docker/9d5b23edb1ba181e8910389a99906598d69ac9a0ead109ee55730cc416d95f7f -13:rdma:/ -12:pids:/docker/9d5b23edb1ba181e8910389a99906598d69ac9a0ead109ee55730cc416d95f7f -11:hugetlb:/docker/9d5b23edb1ba181e8910389a99906598d69ac9a0ead109ee55730cc416d95f7f -10:net_prio:/docker/9d5b23edb1ba181e8910389a99906598d69ac9a0ead109ee55730cc416d95f7f -9:perf_event:/docker/9d5b23edb1ba181e8910389a99906598d69ac9a0ead109ee55730cc416d95f7f -8:net_cls:/docker/9d5b23edb1ba181e8910389a99906598d69ac9a0ead109ee55730cc416d95f7f -7:freezer:/docker/9d5b23edb1ba181e8910389a99906598d69ac9a0ead109ee55730cc416d95f7f -6:devices:/docker/9d5b23edb1ba181e8910389a99906598d69ac9a0ead109ee55730cc416d95f7f -5:memory:/docker/9d5b23edb1ba181e8910389a99906598d69ac9a0ead109ee55730cc416d95f7f -4:blkio:/docker/9d5b23edb1ba181e8910389a99906598d69ac9a0ead109ee55730cc416d95f7f -3:cpuacct:/docker/9d5b23edb1ba181e8910389a99906598d69ac9a0ead109ee55730cc416d95f7f -2:cpu:/docker/9d5b23edb1ba181e8910389a99906598d69ac9a0ead109ee55730cc416d95f7f -1:cpuset:/docker/9d5b23edb1ba181e8910389a99906598d69ac9a0ead109ee55730cc416d95f7f diff --git a/components/container_id/tests/stubs/cgroup.ecs b/components/container_id/tests/stubs/cgroup.ecs deleted file mode 100644 index 3c883125c2f..00000000000 --- a/components/container_id/tests/stubs/cgroup.ecs +++ /dev/null @@ -1,14 +0,0 @@ -14:name=systemd:/ecs/user-ecs-classic/5a0d5ceddf6c44c1928d367a815d890f/38fac3e99302b3622be089dd41e7ccf38aff368a86cc339972075136ee2710ce -13:rdma:/ -12:pids:/ecs/user-ecs-classic/5a0d5ceddf6c44c1928d367a815d890f/38fac3e99302b3622be089dd41e7ccf38aff368a86cc339972075136ee2710ce -11:hugetlb:/ecs/user-ecs-classic/5a0d5ceddf6c44c1928d367a815d890f/38fac3e99302b3622be089dd41e7ccf38aff368a86cc339972075136ee2710ce -10:net_prio:/ecs/user-ecs-classic/5a0d5ceddf6c44c1928d367a815d890f/38fac3e99302b3622be089dd41e7ccf38aff368a86cc339972075136ee2710ce -9:perf_event:/ecs/user-ecs-classic/5a0d5ceddf6c44c1928d367a815d890f/38fac3e99302b3622be089dd41e7ccf38aff368a86cc339972075136ee2710ce -8:net_cls:/ecs/user-ecs-classic/5a0d5ceddf6c44c1928d367a815d890f/38fac3e99302b3622be089dd41e7ccf38aff368a86cc339972075136ee2710ce -7:freezer:/ecs/user-ecs-classic/5a0d5ceddf6c44c1928d367a815d890f/38fac3e99302b3622be089dd41e7ccf38aff368a86cc339972075136ee2710ce -6:devices:/ecs/user-ecs-classic/5a0d5ceddf6c44c1928d367a815d890f/38fac3e99302b3622be089dd41e7ccf38aff368a86cc339972075136ee2710ce -5:memory:/ecs/user-ecs-classic/5a0d5ceddf6c44c1928d367a815d890f/38fac3e99302b3622be089dd41e7ccf38aff368a86cc339972075136ee2710ce -4:blkio:/ecs/user-ecs-classic/5a0d5ceddf6c44c1928d367a815d890f/38fac3e99302b3622be089dd41e7ccf38aff368a86cc339972075136ee2710ce -3:cpuacct:/ecs/user-ecs-classic/5a0d5ceddf6c44c1928d367a815d890f/38fac3e99302b3622be089dd41e7ccf38aff368a86cc339972075136ee2710ce -2:cpu:/ecs/user-ecs-classic/5a0d5ceddf6c44c1928d367a815d890f/38fac3e99302b3622be089dd41e7ccf38aff368a86cc339972075136ee2710ce -1:cpuset:/ecs/user-ecs-classic/5a0d5ceddf6c44c1928d367a815d890f/38fac3e99302b3622be089dd41e7ccf38aff368a86cc339972075136ee2710ce diff --git a/components/container_id/tests/stubs/cgroup.edge_cases b/components/container_id/tests/stubs/cgroup.edge_cases deleted file mode 100644 index 350c7a5b82f..00000000000 --- a/components/container_id/tests/stubs/cgroup.edge_cases +++ /dev/null @@ -1,7 +0,0 @@ -14:name=systemd:/docker/abcd -12:pids:/docker/9d5b23edb1ba181e8910389a99906598d69ac9a0ead109ee55730cc416d95f7 -11:hugetlb:/docker/ -10:net_prio:/docker/ -9:perf_event:/docker/ -8:net_cls:/docker/ZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA -some invalid line diff --git a/components/container_id/tests/stubs/cgroup.fargate b/components/container_id/tests/stubs/cgroup.fargate deleted file mode 100644 index 649847180e4..00000000000 --- a/components/container_id/tests/stubs/cgroup.fargate +++ /dev/null @@ -1,14 +0,0 @@ -14:name=systemd:/ecs/5a081c13-b8cf-4801-b427-f4601742204d/432624d2150b349fe35ba397284dea788c2bf66b885d14dfc1569b01890ca7da -13:rdma:/ -12:pids:/ecs/5a081c13-b8cf-4801-b427-f4601742204d/432624d2150b349fe35ba397284dea788c2bf66b885d14dfc1569b01890ca7da -11:hugetlb:/ecs/5a081c13-b8cf-4801-b427-f4601742204d/432624d2150b349fe35ba397284dea788c2bf66b885d14dfc1569b01890ca7da -10:net_prio:/ecs/5a081c13-b8cf-4801-b427-f4601742204d/432624d2150b349fe35ba397284dea788c2bf66b885d14dfc1569b01890ca7da -9:perf_event:/ecs/5a081c13-b8cf-4801-b427-f4601742204d/432624d2150b349fe35ba397284dea788c2bf66b885d14dfc1569b01890ca7da -8:net_cls:/ecs/5a081c13-b8cf-4801-b427-f4601742204d/432624d2150b349fe35ba397284dea788c2bf66b885d14dfc1569b01890ca7da -7:freezer:/ecs/5a081c13-b8cf-4801-b427-f4601742204d/432624d2150b349fe35ba397284dea788c2bf66b885d14dfc1569b01890ca7da -6:devices:/ecs/5a081c13-b8cf-4801-b427-f4601742204d/432624d2150b349fe35ba397284dea788c2bf66b885d14dfc1569b01890ca7da -5:memory:/ecs/5a081c13-b8cf-4801-b427-f4601742204d/432624d2150b349fe35ba397284dea788c2bf66b885d14dfc1569b01890ca7da -4:blkio:/ecs/5a081c13-b8cf-4801-b427-f4601742204d/432624d2150b349fe35ba397284dea788c2bf66b885d14dfc1569b01890ca7da -3:cpuacct:/ecs/5a081c13-b8cf-4801-b427-f4601742204d/432624d2150b349fe35ba397284dea788c2bf66b885d14dfc1569b01890ca7da -2:cpu:/ecs/5a081c13-b8cf-4801-b427-f4601742204d/432624d2150b349fe35ba397284dea788c2bf66b885d14dfc1569b01890ca7da -1:cpuset:/ecs/5a081c13-b8cf-4801-b427-f4601742204d/432624d2150b349fe35ba397284dea788c2bf66b885d14dfc1569b01890ca7da diff --git a/components/container_id/tests/stubs/cgroup.fargate.1.4 b/components/container_id/tests/stubs/cgroup.fargate.1.4 deleted file mode 100644 index b0699f2cf0c..00000000000 --- a/components/container_id/tests/stubs/cgroup.fargate.1.4 +++ /dev/null @@ -1,11 +0,0 @@ -11:hugetlb:/ecs/55091c13-b8cf-4801-b527-f4601742204d/432624d2150b349fe35ba397284dea788c2bf66b885d14dfc1569b01890ca7da -10:pids:/ecs/55091c13-b8cf-4801-b527-f4601742204d/432624d2150b349fe35ba397284dea788c2bf66b885d14dfc1569b01890ca7da -9:cpuset:/ecs/55091c13-b8cf-4801-b527-f4601742204d/432624d2150b349fe35ba397284dea788c2bf66b885d14dfc1569b01890ca7da -8:net_cls,net_prio:/ecs/55091c13-b8cf-4801-b527-f4601742204d/432624d2150b349fe35ba397284dea788c2bf66b885d14dfc1569b01890ca7da -7:cpu,cpuacct:/ecs/55091c13-b8cf-4801-b527-f4601742204d/432624d2150b349fe35ba397284dea788c2bf66b885d14dfc1569b01890ca7da -6:perf_event:/ecs/55091c13-b8cf-4801-b527-f4601742204d/432624d2150b349fe35ba397284dea788c2bf66b885d14dfc1569b01890ca7da -5:freezer:/ecs/55091c13-b8cf-4801-b527-f4601742204d/432624d2150b349fe35ba397284dea788c2bf66b885d14dfc1569b01890ca7da -4:devices:/ecs/55091c13-b8cf-4801-b527-f4601742204d/432624d2150b349fe35ba397284dea788c2bf66b885d14dfc1569b01890ca7da -3:blkio:/ecs/55091c13-b8cf-4801-b527-f4601742204d/432624d2150b349fe35ba397284dea788c2bf66b885d14dfc1569b01890ca7da -2:memory:/ecs/55091c13-b8cf-4801-b527-f4601742204d/432624d2150b349fe35ba397284dea788c2bf66b885d14dfc1569b01890ca7da -1:name=systemd:/ecs/34dc0b5e626f2c5c4c5170e34b10e765-1234567890 diff --git a/components/container_id/tests/stubs/cgroup.invalid_line_container_id b/components/container_id/tests/stubs/cgroup.invalid_line_container_id deleted file mode 100644 index 0bb3ccdb8b1..00000000000 --- a/components/container_id/tests/stubs/cgroup.invalid_line_container_id +++ /dev/null @@ -1,2 +0,0 @@ -Invalid line with valid container ID 9d5b23edb1ba181e8910389a99906598d69ac9a0ead109ee55730cc416d95f7f -This line is also invalid 12:pids:/docker/9d5b23edb1ba181e8910389a99906598d69ac9a0ead109ee55730cc416d95f7f diff --git a/components/container_id/tests/stubs/cgroup.invalid_line_task_id b/components/container_id/tests/stubs/cgroup.invalid_line_task_id deleted file mode 100644 index a4618cf597e..00000000000 --- a/components/container_id/tests/stubs/cgroup.invalid_line_task_id +++ /dev/null @@ -1,2 +0,0 @@ -Invalid line with valid task ID 34dc0b5e626f2c5c4c5170e34b10e765-1234567890 -This line is also invalid 1:name=systemd:/ecs/34dc0b5e626f2c5c4c5170e34b10e765-1234567890 diff --git a/components/container_id/tests/stubs/cgroup.kubernetes b/components/container_id/tests/stubs/cgroup.kubernetes deleted file mode 100644 index b369265999b..00000000000 --- a/components/container_id/tests/stubs/cgroup.kubernetes +++ /dev/null @@ -1,14 +0,0 @@ -14:name=systemd:/kubepods/something/pod3d274242-8ee0-11e9-a8a6-1e68d864ef1a/3e74d3fd9db4c9dd921ae05c2502fb984d0cde1b36e581b13f79c639da4518a1 -13:rdma:/ -12:pids:/kubepods/something/pod3d274242-8ee0-11e9-a8a6-1e68d864ef1a/3e74d3fd9db4c9dd921ae05c2502fb984d0cde1b36e581b13f79c639da4518a1 -11:hugetlb:/kubepods/something/pod3d274242-8ee0-11e9-a8a6-1e68d864ef1a/3e74d3fd9db4c9dd921ae05c2502fb984d0cde1b36e581b13f79c639da4518a1 -10:net_prio:/kubepods/something/pod3d274242-8ee0-11e9-a8a6-1e68d864ef1a/3e74d3fd9db4c9dd921ae05c2502fb984d0cde1b36e581b13f79c639da4518a1 -9:perf_event:/kubepods/something/pod3d274242-8ee0-11e9-a8a6-1e68d864ef1a/3e74d3fd9db4c9dd921ae05c2502fb984d0cde1b36e581b13f79c639da4518a1 -8:net_cls:/kubepods/something/pod3d274242-8ee0-11e9-a8a6-1e68d864ef1a/3e74d3fd9db4c9dd921ae05c2502fb984d0cde1b36e581b13f79c639da4518a1 -7:freezer:/kubepods/something/pod3d274242-8ee0-11e9-a8a6-1e68d864ef1a/3e74d3fd9db4c9dd921ae05c2502fb984d0cde1b36e581b13f79c639da4518a1 -6:devices:/kubepods/something/pod3d274242-8ee0-11e9-a8a6-1e68d864ef1a/3e74d3fd9db4c9dd921ae05c2502fb984d0cde1b36e581b13f79c639da4518a1 -5:memory:/kubepods/something/pod3d274242-8ee0-11e9-a8a6-1e68d864ef1a/3e74d3fd9db4c9dd921ae05c2502fb984d0cde1b36e581b13f79c639da4518a1 -4:blkio:/kubepods/something/pod3d274242-8ee0-11e9-a8a6-1e68d864ef1a/3e74d3fd9db4c9dd921ae05c2502fb984d0cde1b36e581b13f79c639da4518a1 -3:cpuacct:/kubepods/something/pod3d274242-8ee0-11e9-a8a6-1e68d864ef1a/3e74d3fd9db4c9dd921ae05c2502fb984d0cde1b36e581b13f79c639da4518a1 -2:cpu:/kubepods/something/pod3d274242-8ee0-11e9-a8a6-1e68d864ef1a/3e74d3fd9db4c9dd921ae05c2502fb984d0cde1b36e581b13f79c639da4518a1 -1:cpuset:/kubepods/something/pod3d274242-8ee0-11e9-a8a6-1e68d864ef1a/3e74d3fd9db4c9dd921ae05c2502fb984d0cde1b36e581b13f79c639da4518a1 diff --git a/components/container_id/tests/stubs/cgroup.linux b/components/container_id/tests/stubs/cgroup.linux deleted file mode 100644 index eab140c1a0b..00000000000 --- a/components/container_id/tests/stubs/cgroup.linux +++ /dev/null @@ -1,11 +0,0 @@ -11:blkio:/user.slice/user-0.slice/session-14.scope -10:memory:/user.slice/user-0.slice/session-14.scope -9:hugetlb:/ -8:cpuset:/ -7:pids:/user.slice/user-0.slice/session-14.scope -6:freezer:/ -5:net_cls,net_prio:/ -4:perf_event:/ -3:cpu,cpuacct:/user.slice/user-0.slice/session-14.scope -2:devices:/user.slice/user-0.slice/session-14.scope -1:name=systemd:/user.slice/user-0.slice/session-14.scope diff --git a/components/container_id/tests/stubs/cgroup.unrecognized b/components/container_id/tests/stubs/cgroup.unrecognized deleted file mode 100644 index 18e30317a7e..00000000000 --- a/components/container_id/tests/stubs/cgroup.unrecognized +++ /dev/null @@ -1,14 +0,0 @@ -14:name=systemd:/unrecognized/9d5b23edb1ba181e8910389a99906598d69ac9a0ead109ee55730cc416d95f7f -13:rdma:/ -12:pids:/unrecognized/9d5b23edb1ba181e8910389a99906598d69ac9a0ead109ee55730cc416d95f7f -11:hugetlb:/unrecognized/9d5b23edb1ba181e8910389a99906598d69ac9a0ead109ee55730cc416d95f7f -10:net_prio:/unrecognized/9d5b23edb1ba181e8910389a99906598d69ac9a0ead109ee55730cc416d95f7f -9:perf_event:/unrecognized/9d5b23edb1ba181e8910389a99906598d69ac9a0ead109ee55730cc416d95f7f -8:net_cls:/unrecognized/9d5b23edb1ba181e8910389a99906598d69ac9a0ead109ee55730cc416d95f7f -7:freezer:/unrecognized/9d5b23edb1ba181e8910389a99906598d69ac9a0ead109ee55730cc416d95f7f -6:devices:/unrecognized/9d5b23edb1ba181e8910389a99906598d69ac9a0ead109ee55730cc416d95f7f -5:memory:/unrecognized/9d5b23edb1ba181e8910389a99906598d69ac9a0ead109ee55730cc416d95f7f -4:blkio:/unrecognized/9d5b23edb1ba181e8910389a99906598d69ac9a0ead109ee55730cc416d95f7f -3:cpuacct:/unrecognized/9d5b23edb1ba181e8910389a99906598d69ac9a0ead109ee55730cc416d95f7f -2:cpu:/unrecognized/9d5b23edb1ba181e8910389a99906598d69ac9a0ead109ee55730cc416d95f7f -1:cpuset:/unrecognized/9d5b23edb1ba181e8910389a99906598d69ac9a0ead109ee55730cc416d95f7f diff --git a/components/container_id/tests/stubs/cgroup.upper b/components/container_id/tests/stubs/cgroup.upper deleted file mode 100644 index 188be5fad93..00000000000 --- a/components/container_id/tests/stubs/cgroup.upper +++ /dev/null @@ -1,14 +0,0 @@ -14:name=systemd:/docker/9D5B23EDB1BA181E8910389A99906598D69AC9A0EAD109EE55730CC416D95F7F -13:rdma:/ -12:pids:/docker/9D5B23EDB1BA181E8910389A99906598D69AC9A0EAD109EE55730CC416D95F7F -11:hugetlb:/docker/9D5B23EDB1BA181E8910389A99906598D69AC9A0EAD109EE55730CC416D95F7F -10:net_prio:/docker/9D5B23EDB1BA181E8910389A99906598D69AC9A0EAD109EE55730CC416D95F7F -9:perf_event:/docker/9D5B23EDB1BA181E8910389A99906598D69AC9A0EAD109EE55730CC416D95F7F -8:net_cls:/docker/9D5B23EDB1BA181E8910389A99906598D69AC9A0EAD109EE55730CC416D95F7F -7:freezer:/docker/9D5B23EDB1BA181E8910389A99906598D69AC9A0EAD109EE55730CC416D95F7F -6:devices:/docker/9D5B23EDB1BA181E8910389A99906598D69AC9A0EAD109EE55730CC416D95F7F -5:memory:/docker/9D5B23EDB1BA181E8910389A99906598D69AC9A0EAD109EE55730CC416D95F7F -4:blkio:/docker/9D5B23EDB1BA181E8910389A99906598D69AC9A0EAD109EE55730CC416D95F7F -3:cpuacct:/docker/9D5B23EDB1BA181E8910389A99906598D69AC9A0EAD109EE55730CC416D95F7F -2:cpu:/docker/9D5B23EDB1BA181E8910389A99906598D69AC9A0EAD109EE55730CC416D95F7F -1:cpuset:/docker/9D5B23EDB1BA181E8910389A99906598D69AC9A0EAD109EE55730CC416D95F7F diff --git a/components/container_id/tests/stubs/cgroup.whitespace b/components/container_id/tests/stubs/cgroup.whitespace deleted file mode 100644 index 29f0a3e0a2f..00000000000 --- a/components/container_id/tests/stubs/cgroup.whitespace +++ /dev/null @@ -1,2 +0,0 @@ -13:name=systemd:/docker/ 3726184226f5d3147c25fdeab5b60097e378e8a720503a5e19ecfdf29f869860 -12:pids:/docker/ 3726184226f5d3147c25fdeab5b60097e378e8a720503a5e19ecfdf29f869860 diff --git a/components/log/log.h b/components/log/log.h index c51393e6adf..95094bff7e1 100644 --- a/components/log/log.h +++ b/components/log/log.h @@ -1,7 +1,8 @@ #ifndef COMPONENT_LOG_H #define COMPONENT_LOG_H -#include "../../components-rs/ddtrace.h" +#include +#include #ifndef _WIN32 extern __thread ddog_Log _ddog_log_source_value; diff --git a/config.m4 b/config.m4 index 8a7ab3c1c68..80447678d4e 100644 --- a/config.m4 +++ b/config.m4 @@ -1,6 +1,9 @@ -PHP_ARG_ENABLE(ddtrace, whether to enable Datadog tracing support, +PHP_ARG_ENABLE(ddtrace, whether to enable Datadog support, [ --enable-ddtrace Enable Datadog tracing support]) +PHP_ARG_ENABLE(ddtrace-tracer, whether to enable Datadog tracing support, + [ --disable-ddtrace-tracer Disable Datadog tracing support], yes, no) + PHP_ARG_ENABLE(ddtrace-sanitize, whether to enable AddressSanitizer for ddtrace, [ --enable-ddtrace-sanitize Build Datadog tracing with AddressSanitizer support], no, no) @@ -98,13 +101,12 @@ if test "$PHP_DDTRACE" != "no"; then ]) DD_TRACE_VENDOR_SOURCES="\ - ext/vendor/mpack/mpack.c \ - ext/vendor/mt19937/mt19937-64.c \ + tracer/vendor/mpack/mpack.c \ + tracer/vendor/mt19937/mt19937-64.c \ src/dogstatsd/client.c \ " - DD_TRACE_COMPONENT_SOURCES="\ - components/container_id/container_id.c \ + DATADOG_COMPONENT_SOURCES="\ components/log/log.c \ components/sapi/sapi.c \ components/string_view/string_view.c \ @@ -114,6 +116,8 @@ if test "$PHP_DDTRACE" != "no"; then PHP_VERSION_ID=$("$PHP_CONFIG" --vernum) fi + EXTRA_DATADOG_SOURCES="" + if test $PHP_VERSION_ID -lt 70000; then dnl PHP 5 echo "PHP 5 is not supported on this branch. Use the PHP-5 branch to build PHP 5." @@ -121,10 +125,10 @@ if test "$PHP_DDTRACE" != "no"; then elif test $PHP_VERSION_ID -lt 80000; then dnl PHP 7.x - EXTRA_PHP_SOURCES="ext/handlers_curl_php7.c" + EXTRA_TRACER_SOURCES="tracer/handlers_curl_php7.c" if test $PHP_VERSION_ID -lt 70300; then - EXTRA_PHP_SOURCES="$EXTRA_PHP_SOURCES \ + EXTRA_DATADOG_SOURCES="$EXTRA_DATADOG_SOURCES \ ext/zend_hrtime.c" fi @@ -135,22 +139,25 @@ if test "$PHP_DDTRACE" != "no"; then " elif test $PHP_VERSION_ID -lt 90000; then dnl PHP 8.x - EXTRA_PHP_SOURCES="\ - ext/handlers_curl.c \ - ext/hook/uhook_attributes.c \ - ext/hook/uhook_otel.c \ + EXTRA_TRACER_SOURCES="\ + tracer/handlers_curl.c \ + tracer/hook/uhook_attributes.c \ + tracer/hook/uhook_otel.c \ " ZAI_RESOLVER_SUFFIX="" if test $PHP_VERSION_ID -lt 80200; then ZAI_RESOLVER_SUFFIX="_pre-8_2" - EXTRA_PHP_SOURCES="$EXTRA_PHP_SOURCES \ - ext/weakrefs.c" + EXTRA_TRACER_SOURCES="$EXTRA_TRACER_SOURCES \ + tracer/weakrefs.c" + + EXTRA_DATADOG_SOURCES="$EXTRA_DATADOG_SOURCES \ + ext/patch_zend_call_known_function.c" fi if test $PHP_VERSION_ID -ge 80100; then - EXTRA_PHP_SOURCES="$EXTRA_PHP_SOURCES \ - ext/handlers_fiber.c" + EXTRA_TRACER_SOURCES="$EXTRA_TRACER_SOURCES \ + tracer/handlers_fiber.c" fi EXTRA_ZAI_SOURCES="\ @@ -161,75 +168,79 @@ if test "$PHP_DDTRACE" != "no"; then " fi - dnl ddtrace.c comes first, then everything else alphabetically - DD_TRACE_PHP_SOURCES="$EXTRA_PHP_SOURCES \ - ext/ddtrace.c \ + dnl datadog.c/ddtrace.c comes first, then everything else alphabetically + DATADOG_PHP_SOURCES="$EXTRA_DATADOG_SOURCES \ + ext/datadog.c ext/agent_info.c \ - ext/asm_event.c \ - ext/arrays.c \ - ext/auto_flush.c \ - ext/autoload_php_files.c \ - ext/code_origins.c \ - ext/collect_backtrace.c \ - ext/comms_php.c \ - ext/compat_string.c \ - ext/coms.c \ + ext/compat_getrandom.c \ ext/configuration.c \ ext/crashtracking_frames.c \ - ext/ddshared.c \ - ext/distributed_tracing_headers.c \ - ext/dogstatsd.c \ - ext/dogstatsd_client.c \ - ext/endpoint_guessing.c \ - ext/engine_api.c \ - ext/engine_hooks.c \ - ext/exception_serialize.c \ + ext/endpoints.c \ ext/excluded_modules.c \ ext/git.c \ ext/handlers_api.c \ - ext/handlers_exception.c \ - ext/handlers_httpstreams.c \ - ext/handlers_internal.c \ - ext/handlers_kafka.c \ ext/handlers_pcntl.c \ ext/handlers_signal.c \ - ext/inferred_proxy_headers.c \ - ext/integrations/exec_integration.c \ - ext/integrations/integrations.c \ - ext/ip_extraction.c \ - ext/standalone_limiter.c \ - ext/live_debugger.c \ ext/logging.c \ - ext/limiter/limiter.c \ - ext/memory_limit.c \ ext/otel_config.c \ - ext/priority_sampling/priority_sampling.c \ + ext/phpinfo.c \ ext/process_tags.c \ - ext/profiling.c \ - ext/random.c \ ext/remote_config.c \ - ext/serializer.c \ ext/sidecar.c \ ext/signals.c \ - ext/span.c \ - ext/span_stats.c \ - ext/trace_filter.c \ ext/startup_logging.c \ - ext/telemetry.c \ + ext/string_utils.c \ ext/threads.c \ - ext/trace_source.c \ - ext/tracer_tag_propagation/tracer_tag_propagation.c \ - ext/user_request.c \ - ext/weak_resources.c \ - ext/hook/uhook.c \ - ext/hook/uhook_legacy.c \ + ext/telemetry.c \ " - dnl Always provide a local, weak getrandom() fallback to avoid runtime - dnl relocation failures when running on older libcs (e.g., Alpine 3.7 musl). - dnl On newer libcs, the libc getrandom() takes precedence. - DD_TRACE_PHP_SOURCES="$DD_TRACE_PHP_SOURCES \ - ext/compat_getrandom.c" + DATADOG_TRACER_SOURCES="$EXTRA_TRACER_SOURCES \ + tracer/ddtrace.c \ + tracer/asm_event.c \ + tracer/auto_flush.c \ + tracer/autoload_php_files.c \ + tracer/code_origins.c \ + tracer/collect_backtrace.c \ + tracer/comms_php.c \ + tracer/coms.c \ + tracer/distributed_tracing_headers.c \ + tracer/dogstatsd_client.c \ + tracer/endpoint_guessing.c \ + tracer/engine_api.c \ + tracer/engine_hooks.c \ + tracer/exception_serialize.c \ + tracer/functions.c \ + tracer/git_metadata.c \ + tracer/handlers_exception.c \ + tracer/handlers_httpstreams.c \ + tracer/handlers_internal.c \ + tracer/handlers_kafka.c \ + tracer/inferred_proxy_headers.c \ + tracer/integrations/exec_integration.c \ + tracer/integrations/integrations.c \ + tracer/ip_extraction.c \ + tracer/live_debugger.c \ + tracer/limiter/limiter.c \ + tracer/memory_limit.c \ + tracer/tracer_otel_config.c \ + tracer/priority_sampling/priority_sampling.c \ + tracer/profiling.c \ + tracer/random.c \ + tracer/rule_matching.c \ + tracer/serializer.c \ + tracer/standalone_limiter.c \ + tracer/span.c \ + tracer/span_stats.c \ + tracer/trace_filter.c \ + tracer/trace_source.c \ + tracer/tracer_startup_logging.c \ + tracer/tracer_tag_propagation/tracer_tag_propagation.c \ + tracer/tracer_telemetry.c \ + tracer/user_request.c \ + tracer/weak_resources.c \ + tracer/hook/uhook.c \ + tracer/hook/uhook_legacy.c \ + " ZAI_SOURCES="$EXTRA_ZAI_SOURCES \ zend_abstract_interface/config/config.c \ @@ -247,7 +258,25 @@ if test "$PHP_DDTRACE" != "no"; then zend_abstract_interface/zai_string/string.c \ " - PHP_NEW_EXTENSION(ddtrace, $DD_TRACE_COMPONENT_SOURCES $ZAI_SOURCES $DD_TRACE_VENDOR_SOURCES $DD_TRACE_PHP_SOURCES, $ext_shared,, -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -Wall -std=gnu11) + DATADOG_EXTENSION_FLAGS="-DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -Wall -std=gnu11" + + ALL_DATADOG_SOURCES=" \ + $DATADOG_PHP_SOURCES \ + $ZAI_SOURCES \ + $DATADOG_COMPONENT_SOURCES \ + " + + if test "$PHP_DDTRACE_TRACER" != "no"; then + ALL_DATADOG_SOURCES="$ALL_DATADOG_SOURCES \ + $DD_TRACE_VENDOR_SOURCES \ + $DATADOG_TRACER_SOURCES \ + $DD_TRACE_PHP_SOURCES + " + + DATADOG_EXTENSION_FLAGS="$DATADOG_EXTENSION_FLAGS -DDDTRACE" + fi + + PHP_NEW_EXTENSION(ddtrace, $ALL_DATADOG_SOURCES, $ext_shared,, $DATADOG_EXTENSION_FLAGS) PHP_ADD_BUILD_DIR($ext_builddir/ext, 1) dnl sidecar requires us to be linked against libm for pow and powf and librt for shm_* functions @@ -276,10 +305,10 @@ if test "$PHP_DDTRACE" != "no"; then AC_CHECK_HEADER(time.h, [], [AC_MSG_ERROR([Cannot find or include time.h])]) if test "$ext_shared" = "yes"; then - dnl Only export symbols defined in ddtrace.sym, which should all be marked as - dnl DDTRACE_PUBLIC in their source files as well. + dnl Only export symbols defined in datadog.sym, which should all be marked as + dnl DATADOG_PUBLIC in their source files as well. EXTRA_CFLAGS="$EXTRA_CFLAGS -fvisibility=hidden" - EXTRA_LDFLAGS="$EXTRA_LDFLAGS -export-symbols $ext_srcdir/ddtrace.sym -flto -fuse-linker-plugin" + EXTRA_LDFLAGS="$EXTRA_LDFLAGS -export-symbols $ext_srcdir/datadog.sym -flto -fuse-linker-plugin" dnl On Linux: set the ELF entry point so ddtrace.so can be exec'd directly by ld.so dnl for sidecar spawning (no trampoline binary, no memfd, no temp files). @@ -294,19 +323,17 @@ if test "$PHP_DDTRACE" != "no"; then PHP_SUBST(DDTRACE_SHARED_LIBADD) fi - cat <ext/version.h + cat <"$ext_srcdir/ext/version.h" #ifndef PHP_DDTRACE_VERSION #define PHP_DDTRACE_VERSION "$(cat "$ext_srcdir/VERSION")" #endif EOT PHP_ADD_INCLUDE([$ext_srcdir]) - PHP_ADD_INCLUDE([$ext_srcdir/ext]) PHP_ADD_BUILD_DIR([$ext_builddir/components-rs]) PHP_ADD_BUILD_DIR([$ext_builddir/components]) - PHP_ADD_BUILD_DIR([$ext_builddir/components/container_id]) PHP_ADD_BUILD_DIR([$ext_builddir/components/log]) PHP_ADD_BUILD_DIR([$ext_builddir/components/sapi]) PHP_ADD_BUILD_DIR([$ext_builddir/components/string_view]) @@ -331,30 +358,29 @@ EOT PHP_ADD_BUILD_DIR([$ext_builddir/zend_abstract_interface/zai_assert]) PHP_ADD_BUILD_DIR([$ext_builddir/zend_abstract_interface/zai_string]) - PHP_ADD_BUILD_DIR([$ext_builddir/ext/hook]) - - PHP_ADD_INCLUDE([$ext_srcdir/ext/vendor]) - PHP_ADD_BUILD_DIR([$ext_builddir/ext/vendor]) + PHP_ADD_BUILD_DIR([$ext_builddir/tracer/hook]) - PHP_ADD_INCLUDE([$ext_srcdir/ext/vendor/zai/hook]) - PHP_ADD_BUILD_DIR([$ext_builddir/ext/vendor/zai/hook]) + PHP_ADD_INCLUDE([$ext_srcdir/tracer/vendor]) + PHP_ADD_BUILD_DIR([$ext_builddir/tracer/vendor]) - PHP_ADD_INCLUDE([$ext_srcdir/ext/vendor/mpack]) - PHP_ADD_BUILD_DIR([$ext_builddir/ext/vendor/mpack]) + PHP_ADD_INCLUDE([$ext_srcdir/tracer/vendor/mpack]) + PHP_ADD_BUILD_DIR([$ext_builddir/tracer/vendor/mpack]) - PHP_ADD_INCLUDE([$ext_srcdir/ext/vendor/mt19937]) - PHP_ADD_BUILD_DIR([$ext_builddir/ext/vendor/mt19937]) + PHP_ADD_INCLUDE([$ext_srcdir/tracer/vendor/mt19937]) + PHP_ADD_BUILD_DIR([$ext_builddir/tracer/vendor/mt19937]) - dnl TODO Move this to ext/ + dnl TODO Drop this in favor of sidecar PHP_ADD_INCLUDE([$ext_srcdir/src/dogstatsd]) PHP_ADD_BUILD_DIR([$ext_builddir/src/dogstatsd]) PHP_ADD_BUILD_DIR([$ext_builddir/ext]) - PHP_ADD_BUILD_DIR([$ext_builddir/ext/limiter]) - PHP_ADD_BUILD_DIR([$ext_builddir/ext/priority_sampling]) - PHP_ADD_BUILD_DIR([$ext_builddir/ext/tracer_tag_propagation]) - PHP_ADD_BUILD_DIR([$ext_builddir/ext/integrations]) - PHP_ADD_INCLUDE([$ext_builddir/ext/integrations]) + + PHP_ADD_BUILD_DIR([$ext_builddir/tracer]) + PHP_ADD_BUILD_DIR([$ext_builddir/tracer/limiter]) + PHP_ADD_BUILD_DIR([$ext_builddir/tracer/priority_sampling]) + PHP_ADD_BUILD_DIR([$ext_builddir/tracer/tracer_tag_propagation]) + PHP_ADD_BUILD_DIR([$ext_builddir/tracer/integrations]) + PHP_ADD_INCLUDE([$ext_builddir/tracer/integrations]) dnl Avoid cleaning rust artifacts with make clean (cargo is really good at detecting changes - and rust files are not dependent on php environment). dnl However, for users who really want to clean, there's always make distclean, which will flatly remove the whole target/ directory. @@ -374,8 +400,8 @@ EOT EOT if test "$ext_shared" = "yes"; then - all_object_files=$(for src in $DD_TRACE_PHP_SOURCES $ZAI_SOURCES; do printf ' %s' "${src%?}lo"; done) - all_object_files_absolute=$(for src in $DD_TRACE_PHP_SOURCES $ZAI_SOURCES; do printf ' $(builddir)/%s' "$(dirname "$src")/$objdir/$(basename "${src%?}o")"; done) + all_object_files=$(for src in $ALL_DATADOG_SOURCES; do printf ' %s' "${src%?}lo"; done) + all_object_files_absolute=$(for src in $ALL_DATADOG_SOURCES; do printf ' $(builddir)/%s' "$(dirname "$src")/$objdir/$(basename "${src%?}o")"; done) php_binary=$("$PHP_CONFIG" --php-binary) if test "$PHP_DDTRACE_SIDECAR_MOCKGEN" != "-"; then ddtrace_mockgen_invocation="HOST= TARGET= $PHP_DDTRACE_SIDECAR_MOCKGEN" diff --git a/config.w32 b/config.w32 index dbf504c3320..262a65438c7 100644 --- a/config.w32 +++ b/config.w32 @@ -18,63 +18,73 @@ if (PHP_DDTRACE != 'no') { var version = PHP_VERSION * 100 + PHP_MINOR_VERSION; var DDTRACE_EXT_SOURCES = "agent_info.c"; - DDTRACE_EXT_SOURCES += " arrays.c"; - DDTRACE_EXT_SOURCES += " asm_event.c"; - DDTRACE_EXT_SOURCES += " auto_flush.c"; - DDTRACE_EXT_SOURCES += " autoload_php_files.c"; - DDTRACE_EXT_SOURCES += " code_origins.c"; - DDTRACE_EXT_SOURCES += " collect_backtrace.c"; - DDTRACE_EXT_SOURCES += " compat_string.c"; DDTRACE_EXT_SOURCES += " configuration.c"; - DDTRACE_EXT_SOURCES += " distributed_tracing_headers.c"; - DDTRACE_EXT_SOURCES += " ddshared.c"; - DDTRACE_EXT_SOURCES += " dogstatsd.c"; - DDTRACE_EXT_SOURCES += " endpoint_guessing.c"; - DDTRACE_EXT_SOURCES += " engine_api.c"; - DDTRACE_EXT_SOURCES += " engine_hooks.c"; - DDTRACE_EXT_SOURCES += " exception_serialize.c"; + DDTRACE_EXT_SOURCES += " crashtracking_windows.c"; + DDTRACE_EXT_SOURCES += " endpoints.c"; DDTRACE_EXT_SOURCES += " excluded_modules.c"; DDTRACE_EXT_SOURCES += " git.c"; DDTRACE_EXT_SOURCES += " handlers_api.c"; - DDTRACE_EXT_SOURCES += " handlers_curl" + (version < 800 ? "_php7" : "") + ".c"; - DDTRACE_EXT_SOURCES += " handlers_exception.c"; - DDTRACE_EXT_SOURCES += " handlers_httpstreams.c"; - DDTRACE_EXT_SOURCES += " handlers_internal.c"; - DDTRACE_EXT_SOURCES += " handlers_kafka.c"; DDTRACE_EXT_SOURCES += " handlers_pcntl.c"; - DDTRACE_EXT_SOURCES += " inferred_proxy_headers.c"; - DDTRACE_EXT_SOURCES += " ip_extraction.c"; - DDTRACE_EXT_SOURCES += " standalone_limiter.c"; - DDTRACE_EXT_SOURCES += " live_debugger.c"; DDTRACE_EXT_SOURCES += " logging.c"; - DDTRACE_EXT_SOURCES += " memory_limit.c"; DDTRACE_EXT_SOURCES += " otel_config.c"; + DDTRACE_EXT_SOURCES += " phpinfo.c"; DDTRACE_EXT_SOURCES += " process_tags.c"; - DDTRACE_EXT_SOURCES += " profiling.c"; - DDTRACE_EXT_SOURCES += " random.c"; DDTRACE_EXT_SOURCES += " remote_config.c"; - DDTRACE_EXT_SOURCES += " serializer.c"; DDTRACE_EXT_SOURCES += " sidecar.c"; - DDTRACE_EXT_SOURCES += " span.c"; - DDTRACE_EXT_SOURCES += " span_stats.c"; DDTRACE_EXT_SOURCES += " startup_logging.c"; + DDTRACE_EXT_SOURCES += " string_utils.c"; DDTRACE_EXT_SOURCES += " telemetry.c"; - DDTRACE_EXT_SOURCES += " trace_source.c"; - DDTRACE_EXT_SOURCES += " trace_filter.c"; DDTRACE_EXT_SOURCES += " threads.c"; - DDTRACE_EXT_SOURCES += " user_request.c"; - DDTRACE_EXT_SOURCES += " weak_resources.c"; - DDTRACE_EXT_SOURCES += " crashtracking_windows.c"; if (version >= 800 && version < 802) { - DDTRACE_EXT_SOURCES += " weakrefs.c"; - } - if (version >= 801) { - DDTRACE_EXT_SOURCES += " handlers_fiber.c"; + DDTRACE_EXT_SOURCES += " patch_zend_call_known_function.c"; } if (version < 703 || version == 803) { DDTRACE_EXT_SOURCES += " zend_hrtime.c"; } + var DDTRACE_TRACER_SOURCES = "ddtrace.c"; + DDTRACE_TRACER_SOURCES += " asm_event.c"; + DDTRACE_TRACER_SOURCES += " auto_flush.c"; + DDTRACE_TRACER_SOURCES += " autoload_php_files.c"; + DDTRACE_TRACER_SOURCES += " code_origins.c"; + DDTRACE_TRACER_SOURCES += " collect_backtrace.c"; + DDTRACE_TRACER_SOURCES += " distributed_tracing_headers.c"; + DDTRACE_TRACER_SOURCES += " endpoint_guessing.c"; + DDTRACE_TRACER_SOURCES += " engine_api.c"; + DDTRACE_TRACER_SOURCES += " engine_hooks.c"; + DDTRACE_TRACER_SOURCES += " exception_serialize.c"; + DDTRACE_TRACER_SOURCES += " functions.c"; + DDTRACE_TRACER_SOURCES += " git_metadata.c"; + DDTRACE_TRACER_SOURCES += " handlers_curl" + (version < 800 ? "_php7" : "") + ".c"; + DDTRACE_TRACER_SOURCES += " handlers_exception.c"; + DDTRACE_TRACER_SOURCES += " handlers_httpstreams.c"; + DDTRACE_TRACER_SOURCES += " handlers_internal.c"; + DDTRACE_TRACER_SOURCES += " handlers_kafka.c"; + DDTRACE_TRACER_SOURCES += " inferred_proxy_headers.c"; + DDTRACE_TRACER_SOURCES += " ip_extraction.c"; + DDTRACE_TRACER_SOURCES += " live_debugger.c"; + DDTRACE_TRACER_SOURCES += " memory_limit.c"; + DDTRACE_TRACER_SOURCES += " tracer_otel_config.c"; + DDTRACE_TRACER_SOURCES += " profiling.c"; + DDTRACE_TRACER_SOURCES += " random.c"; + DDTRACE_TRACER_SOURCES += " rule_matching.c"; + DDTRACE_TRACER_SOURCES += " serializer.c"; + DDTRACE_TRACER_SOURCES += " span.c"; + DDTRACE_TRACER_SOURCES += " span_stats.c"; + DDTRACE_TRACER_SOURCES += " standalone_limiter.c"; + DDTRACE_TRACER_SOURCES += " trace_filter.c"; + DDTRACE_TRACER_SOURCES += " trace_source.c"; + DDTRACE_TRACER_SOURCES += " tracer_startup_logging.c"; + DDTRACE_TRACER_SOURCES += " tracer_telemetry.c"; + DDTRACE_TRACER_SOURCES += " user_request.c"; + DDTRACE_TRACER_SOURCES += " weak_resources.c"; + if (version >= 800 && version < 802) { + DDTRACE_TRACER_SOURCES += " weakrefs.c"; + } + if (version >= 801) { + DDTRACE_TRACER_SOURCES += " handlers_fiber.c"; + } + var DDTRACE_HOOK_SOURCES = "uhook.c uhook_legacy.c"; if (version >= 800) { DDTRACE_HOOK_SOURCES += " uhook_attributes.c uhook_otel.c"; @@ -83,9 +93,8 @@ if (PHP_DDTRACE != 'no') { var zai_dirname = configure_module_dirname + "/zend_abstract_interface"; var components_dirname = configure_module_dirname + "/components"; - EXTENSION('ddtrace', "ext\\ddtrace.c"); + EXTENSION('ddtrace', "ext\\datadog.c"); ADD_FLAG("CFLAGS_DDTRACE", " /I " + configure_module_dirname + " "); - ADD_FLAG("CFLAGS_DDTRACE", " /I " + configure_module_dirname + "/ext "); // ADD_FLAG("CFLAGS_DDTRACE", " /I " + configure_module_dirname + "/src/dogstatsd "); ADD_FLAG("CFLAGS_DDTRACE", " /I " + zai_dirname + " "); @@ -96,12 +105,15 @@ if (PHP_DDTRACE != 'no') { ADD_FLAG("CFLAGS_DDTRACE", " /Zc:preprocessor "); } + ADD_FLAG("CFLAGS_DDTRACE", " /DDDTRACE "); + ADD_SOURCES(configure_module_dirname + "/ext", DDTRACE_EXT_SOURCES, "ddtrace"); - ADD_SOURCES(configure_module_dirname + "/ext/hook", DDTRACE_HOOK_SOURCES, "ddtrace"); - ADD_SOURCES(configure_module_dirname + "/ext/integrations", "exec_integration.c integrations.c", "ddtrace"); - ADD_SOURCES(configure_module_dirname + "/ext/limiter", "limiter.c", "ddtrace"); - ADD_SOURCES(configure_module_dirname + "/ext/priority_sampling", "priority_sampling.c", "ddtrace"); - ADD_SOURCES(configure_module_dirname + "/ext/tracer_tag_propagation", "tracer_tag_propagation.c", "ddtrace"); + ADD_SOURCES(configure_module_dirname + "/tracer", DDTRACE_TRACER_SOURCES, "ddtrace"); + ADD_SOURCES(configure_module_dirname + "/tracer/hook", DDTRACE_HOOK_SOURCES, "ddtrace"); + ADD_SOURCES(configure_module_dirname + "/tracer/integrations", "exec_integration.c integrations.c", "ddtrace"); + ADD_SOURCES(configure_module_dirname + "/tracer/limiter", "limiter.c", "ddtrace"); + ADD_SOURCES(configure_module_dirname + "/tracer/priority_sampling", "priority_sampling.c", "ddtrace"); + ADD_SOURCES(configure_module_dirname + "/tracer/tracer_tag_propagation", "tracer_tag_propagation.c", "ddtrace"); ADD_SOURCES(zai_dirname + "/config", "config.c config_decode.c config_ini.c config_stable_file.c config_runtime.c", "ddtrace"); ADD_SOURCES(zai_dirname + "/env", "env.c", "ddtrace"); @@ -121,8 +133,8 @@ if (PHP_DDTRACE != 'no') { ADD_SOURCES(zai_dirname + "/interceptor/php8", "interceptor.c resolver" + (version < 802 ? "_pre-8_2" : "") + ".c", "ddtrace"); } - ADD_SOURCES(configure_module_dirname + "/ext/vendor/mpack", "mpack.c", "ddtrace"); - ADD_SOURCES(configure_module_dirname + "/ext/vendor/mt19937", "mt19937-64.c", "ddtrace"); + ADD_SOURCES(configure_module_dirname + "/tracer/vendor/mpack", "mpack.c", "ddtrace"); + ADD_SOURCES(configure_module_dirname + "/tracer/vendor/mt19937", "mt19937-64.c", "ddtrace"); // ADD_SOURCES(configure_module_dirname + "/src/dogstatsd", "client.c", "ddtrace"); ADD_SOURCES(components_dirname + "/log", "log.c", "ddtrace"); @@ -183,9 +195,9 @@ if (PHP_DDTRACE != 'no') { var defpath = configure_module_dirname + "/ddtrace.def"; deffile = FSO.CreateTextFile(defpath, true); deffile.WriteLine("EXPORTS"); - var contents = FSO.OpenTextFile(configure_module_dirname + "/ddtrace.sym", 1).ReadAll(); + var contents = FSO.OpenTextFile(configure_module_dirname + "/datadog.sym", 1).ReadAll(); contents = contents.replace(/ddog_crashtracker_entry_point\s*/, ""); // unix-only symbol - contents = contents + "\n" + FSO.OpenTextFile(configure_module_dirname + "/ddtrace-windows.sym", 1).ReadAll(); + contents = contents + "\n" + FSO.OpenTextFile(configure_module_dirname + "/datadog-windows.sym", 1).ReadAll(); if (!PHP_DDTRACE_SHARED) { contents = contents.replace(/get_module\s*/, ""); } diff --git a/ddtrace-windows.sym b/datadog-windows.sym similarity index 100% rename from ddtrace-windows.sym rename to datadog-windows.sym diff --git a/ddtrace.sym b/datadog.sym similarity index 77% rename from ddtrace.sym rename to datadog.sym index 854f3f5bf7b..510519066f2 100644 --- a/ddtrace.sym +++ b/datadog.sym @@ -1,22 +1,22 @@ ddtrace_close_all_spans_and_flush -ddtrace_get_formatted_session_id +datadog_get_formatted_session_id ddtrace_get_profiling_context ddtrace_get_root_span -ddtrace_process_tags_get_serialized -ddtrace_get_sidecar_queue_id +datadog_process_tags_get_serialized +datadog_get_sidecar_queue_id ddtrace_get_priority_sampling_on_span_zobj ddtrace_set_priority_sampling_on_span_zobj ddtrace_add_propagated_tag_on_span_zobj -ddtrace_runtime_id +datadog_runtime_id ddtrace_user_req_add_listeners ddtrace_ip_extraction_find -ddtrace_set_all_thread_vm_interrupt -ddtrace_get_telemetry_rc_info -ddtrace_metric_register_buffer -ddtrace_metric_add_point +datadog_set_all_thread_vm_interrupt +datadog_get_telemetry_rc_info +datadog_metric_register_buffer +datadog_metric_add_point ddtrace_emit_asm_event -ddtrace_loaded_by_ssi -ddtrace_ssi_forced_injection_enabled +datadog_loaded_by_ssi +datadog_ssi_forced_injection_enabled ddtrace_guess_endpoint_from_url ddog_remote_config_reader_for_path ddog_remote_config_read diff --git a/ext/agent_info.c b/ext/agent_info.c index 4d32b83c4d3..4bea66668df 100644 --- a/ext/agent_info.c +++ b/ext/agent_info.c @@ -1,31 +1,31 @@ #include "agent_info.h" -#include "ddtrace.h" +#include "datadog.h" #include "sidecar.h" #include "configuration.h" #include "process_tags.h" -ZEND_EXTERN_MODULE_GLOBALS(ddtrace); +ZEND_EXTERN_MODULE_GLOBALS(datadog); -void ddtrace_agent_info_rinit() { - if (ddtrace_endpoint && !DDTRACE_G(agent_info_reader)) { - DDTRACE_G(agent_info_reader) = ddog_get_agent_info_reader(ddtrace_endpoint); +void datadog_agent_info_rinit() { + if (datadog_endpoint && !DATADOG_G(agent_info_reader)) { + DATADOG_G(agent_info_reader) = ddog_get_agent_info_reader(datadog_endpoint); } } -void ddtrace_apply_agent_info(void) { - if (!DDTRACE_G(agent_info_reader)) { +void datadog_apply_agent_info(void) { + if (!DATADOG_G(agent_info_reader)) { return; } ddog_CharSlice env = {0}, hash = {0}; - ddog_apply_agent_info(DDTRACE_G(agent_info_reader), &env, &hash); + ddog_apply_agent_info(DATADOG_G(agent_info_reader), &env, &hash); if (env.len && ZSTR_LEN(get_DD_ENV()) == 0) { zend_alter_ini_entry_chars( - zai_config_memoized_entries[DDTRACE_CONFIG_DD_ENV].ini_entries[0]->name, + zai_config_memoized_entries[DATADOG_CONFIG_DD_ENV].ini_entries[0]->name, env.ptr, env.len, ZEND_INI_USER, ZEND_INI_STAGE_RUNTIME); } if (hash.len) { zend_string *hash_str = zend_string_init(hash.ptr, hash.len, 1); - ddtrace_process_tags_set_container_tags_hash(hash_str); + datadog_process_tags_set_container_tags_hash(hash_str); zend_string_release(hash_str); } } diff --git a/ext/agent_info.h b/ext/agent_info.h index 62e4c4dc1f6..476248ef587 100644 --- a/ext/agent_info.h +++ b/ext/agent_info.h @@ -1,10 +1,10 @@ -#ifndef DD_AGENT_INFO_H -#define DD_AGENT_INFO_H +#ifndef DATADOG_AGENT_INFO_H +#define DATADOG_AGENT_INFO_H #include #include "Zend/zend_types.h" -void ddtrace_agent_info_rinit(void); -void ddtrace_apply_agent_info(void); +void datadog_agent_info_rinit(void); +void datadog_apply_agent_info(void); -#endif // DD_AGENT_INFO_H +#endif // DATADOG_AGENT_INFO_H diff --git a/ext/arrays.c b/ext/arrays.c deleted file mode 100644 index c70d5f542ae..00000000000 --- a/ext/arrays.c +++ /dev/null @@ -1,27 +0,0 @@ -#include "arrays.h" - -#include - -void ddtrace_array_walk(HashTable *input, ddtrace_walk_fn callback, void *context) { - zval *item = NULL; - size_t order = 0; - ZEND_HASH_FOREACH_VAL(input, item) { callback(item, order++, context); } - ZEND_HASH_FOREACH_END(); -} - -void *ddtrace_hash_find_ptr(const HashTable *ht, const char *str, size_t len) { - void *result; - result = zend_hash_str_find_ptr(ht, str, len); - return result; -} - -void *ddtrace_hash_find_ptr_lc(const HashTable *ht, const char *str, size_t len) { - void *result; - // Stack allocate small strings to improve performance - ALLOCA_FLAG(use_heap) - // zend_str_tolower_copy will add a null terminator; leave room for it - char *lc_str = zend_str_tolower_copy(do_alloca(len + 1, use_heap), str, len); - result = ddtrace_hash_find_ptr(ht, lc_str, len); - free_alloca(lc_str, use_heap); - return result; -} diff --git a/ext/arrays.h b/ext/arrays.h deleted file mode 100644 index f20d3c9c739..00000000000 --- a/ext/arrays.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef DDTRACE_ARRAYS_H -#define DDTRACE_ARRAYS_H - -#include - -typedef void (*ddtrace_walk_fn)(zval *item, size_t visitation_order, void *context); -void ddtrace_array_walk(HashTable *input, ddtrace_walk_fn, void *context); - -/** - * Use ddtrace_hash_find_ptr_lc if you do not already have a lowercased string - * and do not need one for any reason other than to look up the string in the - * ht. - * If you already have a lowered string, use ddtrace_hash_find_ptr. - */ -void *ddtrace_hash_find_ptr_lc(const HashTable *ht, const char *str, size_t len); -void *ddtrace_hash_find_ptr(const HashTable *ht, const char *str, size_t len); - -#endif // DDTRACE_ARRAYS_H diff --git a/ext/compatibility.h b/ext/compatibility.h index 9d66a40ff11..4207990066c 100644 --- a/ext/compatibility.h +++ b/ext/compatibility.h @@ -1,12 +1,12 @@ -#ifndef DD_COMPATIBILITY_H -#define DD_COMPATIBILITY_H +#ifndef DATADOG_COMPATIBILITY_H +#define DATADOG_COMPATIBILITY_H #include #include #include #include -#include "ext/standard/base64.h" +#include #if !defined(ZEND_ASSERT) #if ZEND_DEBUG @@ -91,7 +91,7 @@ static zend_always_inline void dd_get_closure_to_fcc(zval *closure, zend_fcall_i #endif } -static inline zval *ddtrace_assign_variable(zval *variable_ptr, zval *value) { +static inline zval *datadog_assign_variable(zval *variable_ptr, zval *value) { #if PHP_VERSION_ID < 70400 return zend_assign_to_variable(variable_ptr, value, IS_TMP_VAR); #else @@ -108,7 +108,7 @@ static inline zval *ddtrace_assign_variable(zval *variable_ptr, zval *value) { #define Z_EXTRA_P(z) Z_NEXT_P(z) #undef zval_get_long -#define zval_get_long ddtrace_zval_get_long +#define zval_get_long datadog_zval_get_long static inline zend_long zval_get_long(zval *op) { if (Z_ISUNDEF_P(op)) { return 0; @@ -594,16 +594,16 @@ static zend_always_inline bool zend_string_starts_with(const zend_string *str, c #define zend_string_starts_with_literal(str, prefix) \ zend_string_starts_with_cstr(str, prefix, strlen(prefix)) -static inline zend_string *ddtrace_vstrpprintf(size_t max_len, const char *format, va_list ap) +static inline zend_string *datadog_vstrpprintf(size_t max_len, const char *format, va_list ap) { zend_string *str = zend_vstrpprintf(max_len, format, ap); return zend_string_realloc(str, ZSTR_LEN(str), 0); } #undef zend_vstrpprintf -#define zend_vstrpprintf ddtrace_vstrpprintf +#define zend_vstrpprintf datadog_vstrpprintf -static inline zend_string *ddtrace_strpprintf(size_t max_len, const char *format, ...) +static inline zend_string *datadog_strpprintf(size_t max_len, const char *format, ...) { va_list arg; zend_string *str; @@ -615,12 +615,14 @@ static inline zend_string *ddtrace_strpprintf(size_t max_len, const char *format } #undef zend_strpprintf -#define zend_strpprintf ddtrace_strpprintf +#define zend_strpprintf datadog_strpprintf #define ZEND_HASH_ELEMENT(ht, idx) (&ht->arData[idx].val) #define ZEND_HASH_MAP_FOREACH_PTR ZEND_HASH_FOREACH_PTR #define ZEND_HASH_MAP_FOREACH_STR_KEY_VAL ZEND_HASH_FOREACH_STR_KEY_VAL +const char *zend_memnistr(const char *haystack, const char *needle, size_t needle_len, const char *end); + #if PHP_VERSION_ID >= 80000 #define zend_weakrefs_hash_add zend_weakrefs_hash_add_fallback #define zend_weakrefs_hash_del zend_weakrefs_hash_del_fallback @@ -769,21 +771,17 @@ enum { #endif ZEND_STR__LAST }; -extern zend_string *ddtrace_known_strings[ZEND_STR__LAST]; +extern zend_string *datadog_known_strings[ZEND_STR__LAST]; #undef ZSTR_KNOWN #if PHP_VERSION_ID >= 70200 -#define ZSTR_KNOWN(idx) (idx < 0 ? ddtrace_known_strings[-1 - idx] : zend_known_strings[idx]) +#define ZSTR_KNOWN(idx) (idx < 0 ? datadog_known_strings[-1 - idx] : zend_known_strings[idx]) #elif PHP_VERSION_ID >= 70100 -#define ZSTR_KNOWN(idx) (idx < 0 ? ddtrace_known_strings[-1 - idx] : CG(known_strings)[idx]) +#define ZSTR_KNOWN(idx) (idx < 0 ? datadog_known_strings[-1 - idx] : CG(known_strings)[idx]) #else -#define ZSTR_KNOWN(idx) ddtrace_known_strings[idx] -#endif - +#define ZSTR_KNOWN(idx) datadog_known_strings[idx] #endif -#if PHP_VERSION_ID < 80200 -const char *zend_memnistr(const char *haystack, const char *needle, size_t needle_len, const char *end); #endif -#endif // DD_COMPATIBILITY_H +#endif // DATADOG_COMPATIBILITY_H diff --git a/ext/configuration.c b/ext/configuration.c index 7714360cebf..e205ce8cdf5 100644 --- a/ext/configuration.c +++ b/ext/configuration.c @@ -2,17 +2,16 @@ #include -#include "ip_extraction.h" +#include "datadog.h" #include "logging.h" -#include "json/json.h" +#include #include "sidecar.h" #include #include -#include "live_debugger.h" -#include "sidecar.h" +ZEND_EXTERN_MODULE_GLOBALS(datadog); -ZEND_EXTERN_MODULE_GLOBALS(ddtrace); +#include #define DD_TO_DATADOG_INC 5 /* "DD" expanded to "datadog" */ @@ -35,7 +34,7 @@ ZEND_EXTERN_MODULE_GLOBALS(ddtrace); #ifndef _WIN32 #define CALIAS CONFIG #define CONFIG(...) 1, -#define NUMBER_OF_CONFIGURATIONS sizeof((uint8_t[]){DD_CONFIGURATION}) +#define NUMBER_OF_CONFIGURATIONS sizeof((uint8_t[]){DD_ALL_CONFIGURATIONS}) _Static_assert(NUMBER_OF_CONFIGURATIONS < ZAI_CONFIG_ENTRIES_COUNT_MAX, "There are more config entries than ZAI_CONFIG_ENTRIES_COUNT_MAX."); #undef CONFIG @@ -43,7 +42,7 @@ _Static_assert(NUMBER_OF_CONFIGURATIONS < ZAI_CONFIG_ENTRIES_COUNT_MAX, _Static_assert(sizeof(#name) < ZAI_CONFIG_NAME_BUFSIZ - DD_TO_DATADOG_INC, \ "The name of " #name \ " is longer than allowed ZAI_CONFIG_NAME_BUFSIZ - " DD_CFG_STR(DD_TO_DATADOG_INC)); -DD_CONFIGURATION +DD_ALL_CONFIGURATIONS #undef CONFIG #undef CALIAS #define CONFIG(...) @@ -53,7 +52,7 @@ DD_CONFIGURATION #define CALIAS(type, name, default, aliases, ...) \ _Static_assert(sizeof((uint8_t[]){ELEMENTS aliases}) < ZAI_CONFIG_NAMES_COUNT_MAX, \ #name " has more than the allowed ZAI_CONFIG_NAMES_COUNT_MAX alias names"); -DD_CONFIGURATION +DD_ALL_CONFIGURATIONS #undef CALIAS #undef CALIASES #define CALIAS_CHECK_LENGTH(name) \ @@ -62,133 +61,12 @@ DD_CONFIGURATION " alias is longer than allowed ZAI_CONFIG_NAME_BUFSIZ - " DD_CFG_STR(DD_TO_DATADOG_INC)); #define CALIASES(...) APPLY_N(CALIAS_CHECK_LENGTH, ##__VA_ARGS__) #define CALIAS(type, name, default, aliases, ...) aliases -DD_CONFIGURATION +DD_ALL_CONFIGURATIONS #undef CALIAS #undef CALIASES #undef CONFIG #endif -static bool dd_parse_dbm_mode(zai_str value, zval *decoded_value, bool persistent) { - UNUSED(persistent); - if (zai_str_eq_ci_cstr(value, "disabled")) { - ZVAL_LONG(decoded_value, DD_TRACE_DBM_PROPAGATION_DISABLED); - } else if (zai_str_eq_ci_cstr(value, "service")) { - ZVAL_LONG(decoded_value, DD_TRACE_DBM_PROPAGATION_SERVICE); - } else if (zai_str_eq_ci_cstr(value, "full")) { - ZVAL_LONG(decoded_value, DD_TRACE_DBM_PROPAGATION_FULL); - } else { - return false; - } - - return true; -} - -static bool dd_parse_sampling_rules_format(zai_str value, zval *decoded_value, bool persistent) { - UNUSED(persistent); - if (zai_str_eq_ci_cstr(value, "regex")) { - ZVAL_LONG(decoded_value, DD_TRACE_SAMPLING_RULES_FORMAT_REGEX); - } else if (zai_str_eq_ci_cstr(value, "glob")) { - ZVAL_LONG(decoded_value, DD_TRACE_SAMPLING_RULES_FORMAT_GLOB); - } else { - return false; - } - - return true; -} - -static bool dd_parse_sidecar_connection_mode(zai_str value, zval *decoded_value, bool persistent) { - UNUSED(persistent); - if (zai_str_eq_ci_cstr(value, "auto")) { - ZVAL_LONG(decoded_value, DD_TRACE_SIDECAR_CONNECTION_MODE_AUTO); - } else if (zai_str_eq_ci_cstr(value, "subprocess")) { - ZVAL_LONG(decoded_value, DD_TRACE_SIDECAR_CONNECTION_MODE_SUBPROCESS); - } else if (zai_str_eq_ci_cstr(value, "thread")) { - ZVAL_LONG(decoded_value, DD_TRACE_SIDECAR_CONNECTION_MODE_THREAD); - } 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); - - if (value.len == 0) { - return true; - } - - const char *str = value.ptr; - const char *end = str + value.len; - const char *current = str; - - // Determine separator - prefer comma if present, otherwise use space - char sep = memchr(str, ',', value.len) ? ',': ' '; - - while (current < end) { - // Skip leading whitespace - while (current < end && (*current == ' ' || *current == sep)) current++; - if (current == end) { - // Abort if only separators are remaining - break; - } - - // Find next separator, this will be the end of the tag - const char *tag_end = memchr(current, sep, end - current); - if (!tag_end) { - tag_end = end; - } - // Prepare key and value - // Initialize key to be the entire tag and value to be empty - const char *key_start = current; - const char *key_end = tag_end; - const char *val_start = tag_end; - const char *val_end = tag_end; - // If the tag has a colon, use the index of the colon to split the tag into key and value - const char *colon = memchr(current, ':', tag_end - current); - if (colon) { - // Tag has a colon, use the index of the colon to split into key and value - key_end = colon; - val_start = colon + 1; - } - - // Strip whitespace from key - while (key_start < key_end && *key_start == ' ') key_start++; - while (key_end > key_start && key_end[-1] == ' ') key_end--; - // Only add if key is non-empty - if (key_start != key_end) { - // Strip whitespace from value - while (val_start < val_end && *val_start == ' ') val_start++; - while (val_end > val_start && val_end[-1] == ' ') val_end--; - - zval val; - ZVAL_STR(&val, zend_string_init(val_start, val_end - val_start, persistent)); - zend_hash_str_update(Z_ARRVAL_P(decoded_value), key_start, key_end - key_start, &val); - } - // Move to the start of the next tag - current = tag_end + 1; - } - - return true; -} - -#define INI_CHANGE_DYNAMIC_CONFIG(name, config) \ - static bool ddtrace_alter_##name(zval *old_value, zval *new_value, zend_string *new_str) { \ - UNUSED(old_value, new_value); \ - /* When RC writes, bypass the check for ddog_remote_config_alter_dynamic_config */ \ - if (!DDTRACE_G(remote_config_state) || DDTRACE_G(remote_config_writing)) { \ - return true; \ - } \ - return ddog_remote_config_alter_dynamic_config(DDTRACE_G(remote_config_state), DDOG_CHARSLICE_C(config), zend_string_copy(new_str)); \ - } - -INI_CHANGE_DYNAMIC_CONFIG(DD_TRACE_HEADER_TAGS, "datadog.trace.header_tags") -INI_CHANGE_DYNAMIC_CONFIG(DD_TRACE_SAMPLE_RATE, "datadog.trace.sample_rate") -INI_CHANGE_DYNAMIC_CONFIG(DD_TRACE_LOGS_ENABLED, "datadog.logs_injection") -INI_CHANGE_DYNAMIC_CONFIG(DD_CODE_ORIGIN_FOR_SPANS_ENABLED, "datadog.code_origin_for_spans_enabled") -INI_CHANGE_DYNAMIC_CONFIG(DD_EXCEPTION_REPLAY_ENABLED, "datadog.exception_replay_enabled") - #define CALIAS_EXPAND(name) {.ptr = name, .len = sizeof(name) - 1}, #define EXPAND_FIRST(arg, ...) arg #define EXPAND_CALL(macro, args) macro args // I hate the "traditional" MSVC preprocessor @@ -201,36 +79,25 @@ INI_CHANGE_DYNAMIC_CONFIG(DD_EXCEPTION_REPLAY_ENABLED, "datadog.exception_replay #define CONFIG(...) #define CALIASES(...) ({APPLY_N(CALIAS_EXPAND, ##__VA_ARGS__)}) #define CALIAS(type, name, default, aliases, ...) const zai_str dd_config_aliases_##name[] = EXPAND_CALL(EXPAND_IDENTITY, EXPAND_FIRST(aliases)); -DD_CONFIGURATION +DD_ALL_CONFIGURATIONS #undef CALIAS #undef CONFIG #endif #define CUSTOM(...) CUSTOM -#define CONFIG(type, name, ...) EXPAND_CALL(ZAI_CONFIG_ENTRY, (DDTRACE_CONFIG_##name, name, type, __VA_ARGS__)), +#define CONFIG(type, name, ...) EXPAND_CALL(ZAI_CONFIG_ENTRY, (DATADOG_CONFIG_##name, name, type, __VA_ARGS__)), #ifndef _WIN32 #define CALIASES(...) ((zai_str[]){APPLY_N(CALIAS_EXPAND, ##__VA_ARGS__)}) -#define CALIAS(type, name, ...) ZAI_CONFIG_ALIASED_ENTRY(DDTRACE_CONFIG_##name, name, type, __VA_ARGS__), +#define CALIAS(type, name, ...) ZAI_CONFIG_ALIASED_ENTRY(DATADOG_CONFIG_##name, name, type, __VA_ARGS__), #else -#define CALIAS(type, name, default, aliases, ...) ZAI_CONFIG_ALIASED_ENTRY(DDTRACE_CONFIG_##name, name, type, default, dd_config_aliases_##name, ##__VA_ARGS__), +#define CALIAS(type, name, default, aliases, ...) ZAI_CONFIG_ALIASED_ENTRY(DATADOG_CONFIG_##name, name, type, default, dd_config_aliases_##name, ##__VA_ARGS__), #endif -static zai_config_entry config_entries[] = {DD_CONFIGURATION}; +zai_config_entry datadog_config_entries[] = {DD_ALL_CONFIGURATIONS}; #undef CALIAS #undef CONFIG bool runtime_config_first_init = false; -bool ddtrace_runtime_config_is_modified(ddtrace_config_id config) { - if (zai_config_memoized_entries[config].name_index >= 0) { - return true; - } -#if ZTS - return EG(modified_ini_directives) && zend_hash_exists(EG(modified_ini_directives), zai_config_memoized_entries[config].ini_entries[0]->name); -#else - return zai_config_memoized_entries[config].ini_entries[0]->modified; -#endif -} - static char dd_tolower_ascii(char c) { return c >= 'A' && c <= 'Z' ? c - ('A' - 'a') : c; } #if defined(_WIN32) && PHP_VERSION_ID < 80000 && !defined(restrict) @@ -268,33 +135,10 @@ static void dd_ini_env_to_ini_name(const zai_str env_name, zai_config_name *ini_ ini_name->ptr[ini_name->len] = '\0'; } -bool ddtrace_config_minit(int module_number) { - if (ddtrace_active_sapi == DATADOG_PHP_SAPI_CLI) { - config_entries[DDTRACE_CONFIG_DD_TRACE_AUTO_FLUSH_ENABLED].default_encoded_value = (zai_str) ZAI_STR_FROM_CSTR("true"); - } - -#ifndef _WIN32 - // PID 1 *obviously* needs to ensure the sidecar gets flushed. (As PID 1 terminating will just SIGKILL it.) - // As to PPID 1, common scenarios where PHP is a direct child of PID 1: - // - apache / fpm running in a container as PID 1 each - // - PHP CLI processes running in a container as part of a bash script - // - root processes of supervisord/systemd services - if these terminate, it's likely because the service or container shuts down. - // -> If the sidecar is part of a cgroup, it will terminate the sidecar as well. - if (getpid() == 1 || getppid() == 1) { - config_entries[DDTRACE_CONFIG_DD_TRACE_FORCE_FLUSH_ON_SHUTDOWN].default_encoded_value = (zai_str) ZAI_STR_FROM_CSTR("true"); - config_entries[DDTRACE_CONFIG_DD_TRACE_FORCE_FLUSH_ON_SIGTERM].default_encoded_value = (zai_str) ZAI_STR_FROM_CSTR("true"); - config_entries[DDTRACE_CONFIG_DD_TRACE_FORCE_FLUSH_ON_SIGINT].default_encoded_value = (zai_str) ZAI_STR_FROM_CSTR("true"); - } - - // Background sender does not send a Content-Length header, but sidecar does. Force-enable it thus, as the background sender does not work at all. - if (getenv("AWS_LAMBDA_FUNCTION_NAME")) { - config_entries[DDTRACE_CONFIG_DD_TRACE_SIDECAR_TRACE_SENDER].default_encoded_value = (zai_str) ZAI_STR_FROM_CSTR("true"); - } -#endif - - if (!zai_config_minit(config_entries, (sizeof config_entries / sizeof *config_entries), dd_ini_env_to_ini_name, +bool datadog_config_minit(int module_number) { + if (!zai_config_minit(datadog_config_entries, (sizeof datadog_config_entries / sizeof *datadog_config_entries), dd_ini_env_to_ini_name, module_number)) { - ddtrace_log_ginit(); + datadog_log_ginit(); LOG(ERROR, "Unable to load configuration; likely due to json symbols failing to resolve."); return false; } @@ -304,14 +148,14 @@ bool ddtrace_config_minit(int module_number) { // arduous way of accessing the decoded_value directly from zai_config_memoized_entries. zai_config_first_time_rinit(false); - ddtrace_alter_dd_trace_debug(NULL, &zai_config_memoized_entries[DDTRACE_CONFIG_DD_TRACE_DEBUG].decoded_value, NULL); - ddtrace_log_ginit(); + datadog_alter_dd_trace_debug(NULL, &zai_config_memoized_entries[DATADOG_CONFIG_DD_TRACE_DEBUG].decoded_value, NULL); + datadog_log_ginit(); return true; } -void ddtrace_config_first_rinit() { +void datadog_config_first_rinit() { zend_ini_entry *internal_functions_ini = - zai_config_memoized_entries[DDTRACE_CONFIG_DD_TRACE_TRACED_INTERNAL_FUNCTIONS].ini_entries[0]; + zai_config_memoized_entries[DATADOG_CONFIG_DD_TRACE_TRACED_INTERNAL_FUNCTIONS].ini_entries[0]; zend_string *internal_functions_old = zend_string_copy( internal_functions_ini->modified ? internal_functions_ini->orig_value : internal_functions_ini->value); @@ -338,41 +182,3 @@ void ddtrace_config_first_rinit() { runtime_config_first_init = true; } - -// note: only call this if get_DD_TRACE_ENABLED() returns true -bool ddtrace_config_integration_enabled(ddtrace_integration_name integration_name) { - ddtrace_integration *integration = &ddtrace_integrations[integration_name]; - - return integration->is_enabled(); -} - -void ddtrace_change_default_ini(ddtrace_config_id config_id, zai_str str) { - zai_config_memoized_entry *memoized = &zai_config_memoized_entries[config_id]; - zend_ini_entry *entry = memoized->ini_entries[0]; - zend_string_release(entry->value); - entry->value = zend_string_init(str.ptr, str.len, 1); - if (entry->modified) { - entry->modified = false; - zend_string_release(entry->orig_value); - } -#if ZTS - zend_ini_entry *runtime_entry = zend_hash_find_ptr(EG(ini_directives), entry->name); - if (runtime_entry != entry) { - zend_string_release(runtime_entry->value); - runtime_entry->value = zend_string_copy(entry->value); - if (runtime_entry->modified) { - runtime_entry->modified = false; - zend_string_release(runtime_entry->orig_value); - } - } -#endif - memoized->default_encoded_value = str; - memoized->name_index = ZAI_CONFIG_ORIGIN_DEFAULT; - - zval decoded; - ZVAL_UNDEF(&decoded); - if (zai_config_decode_value(str, memoized->type, memoized->parser, &decoded, 1)) { - zai_json_dtor_pzval(&memoized->decoded_value); - ZVAL_COPY_VALUE(&memoized->decoded_value, &decoded); - } -} diff --git a/ext/configuration.h b/ext/configuration.h index 1c95a47abda..71ca5db07e7 100644 --- a/ext/configuration.h +++ b/ext/configuration.h @@ -1,36 +1,18 @@ -#ifndef DD_CONFIGURATION_H -#define DD_CONFIGURATION_H +#ifndef DATADOG_CONFIGURATION_H +#define DATADOG_CONFIGURATION_H #include #include "compatibility.h" -#include "config/config.h" -#include "ddtrace_string.h" -#include "integrations/integrations.h" -#include "span.h" -#include "otel_config.h" +#include -// note: only call this if ddtrace_config_trace_enabled() returns true -bool ddtrace_config_integration_enabled(ddtrace_integration_name integration_name); - -bool ddtrace_config_minit(int module_number); -void ddtrace_config_first_rinit(); +bool datadog_config_minit(int module_number); +void datadog_config_first_rinit(); extern bool runtime_config_first_init; +extern zai_config_entry datadog_config_entries[]; -enum ddtrace_dbm_propagation_mode { - DD_TRACE_DBM_PROPAGATION_DISABLED, - DD_TRACE_DBM_PROPAGATION_SERVICE, - DD_TRACE_DBM_PROPAGATION_FULL, -}; - -// To remove in 1.0 -enum ddtrace_sampling_rules_format { - DD_TRACE_SAMPLING_RULES_FORMAT_REGEX, - DD_TRACE_SAMPLING_RULES_FORMAT_GLOB -}; - -enum ddtrace_sidecar_connection_mode { +enum datadog_sidecar_connection_mode { DD_TRACE_SIDECAR_CONNECTION_MODE_AUTO = 0, // Default: try subprocess, fallback to thread DD_TRACE_SIDECAR_CONNECTION_MODE_SUBPROCESS = 1, // Force subprocess only DD_TRACE_SIDECAR_CONNECTION_MODE_THREAD = 2, // Force thread only @@ -46,55 +28,11 @@ enum ddtrace_sidecar_connection_mode { * A user hit an issue with the userland time of 100. */ #define DD_TRACE_AGENT_CONNECT_TIMEOUT_VAL 100 -#define DD_TRACE_BGS_CONNECT_TIMEOUT_VAL 2000 - -/* Default for the PHP sender; should be kept in sync with DDTrace\Transport\Http::DEFAULT_AGENT_TIMEOUT */ #define DD_TRACE_AGENT_TIMEOUT_VAL 500 - -/* This should be at least an order of magnitude higher than the userland HTTP Transport default. */ -#define DD_TRACE_BGS_TIMEOUT_VAL 5000 - #define DD_TRACE_AGENT_FLUSH_INTERVAL_VAL 1001 -#define DD_INTEGRATION_ANALYTICS_ENABLED_DEFAULT false -#define DD_INTEGRATION_ANALYTICS_SAMPLE_RATE_DEFAULT 1.0 - -#if PHP_VERSION_ID >= 80300 || defined(_WIN32) -#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/" -#else -#define DD_DEFAULT_SOURCES_PATH "" -#endif - #define DD_CFG_STR(str) #str #define DD_CFG_EXPSTR(str) DD_CFG_STR(str) -#define INTEGRATION_ALIAS(id, _, initial, ...) \ - CALIAS(BOOL, id, initial, __VA_ARGS__) -#define INTEGRATION_WITH_DEFAULT(id, _, initial) \ - CONFIG(BOOL, id, initial) -#define INTEGRATION_NORMAL(id, _) \ - CONFIG(BOOL, id, "true") -#define GET_INTEGRATION_CONFIG_MACRO(_1, _2, _3, DEFAULT, NAME, ...) NAME -#if defined(_MSVC_TRADITIONAL) && _MSVC_TRADITIONAL -#define GET_INTEGRATION_CONFIG_MACRO_EXPAND(...) __VA_ARGS__ -#define INTEGRATION_CONFIG_ACTIVE(id, ...) GET_INTEGRATION_CONFIG_MACRO_EXPAND(GET_INTEGRATION_CONFIG_MACRO(__VA_ARGS__, INTEGRATION_ALIAS, INTEGRATION_ALIAS, INTEGRATION_WITH_DEFAULT, INTEGRATION_NORMAL))GET_INTEGRATION_CONFIG_MACRO_EXPAND((DD_TRACE_##id##_ENABLED, __VA_ARGS__)) -#else -#define INTEGRATION_CONFIG_ACTIVE(id, ...) GET_INTEGRATION_CONFIG_MACRO(__VA_ARGS__, INTEGRATION_ALIAS, INTEGRATION_ALIAS, INTEGRATION_WITH_DEFAULT, INTEGRATION_NORMAL)(DD_TRACE_##id##_ENABLED, __VA_ARGS__) -#endif -#define INTEGRATION(id, ...) \ - INTEGRATION_CONFIG_ACTIVE(id, __VA_ARGS__) \ - CALIAS(BOOL, DD_TRACE_##id##_ANALYTICS_ENABLED, DD_CFG_EXPSTR(DD_INTEGRATION_ANALYTICS_ENABLED_DEFAULT), \ - CALIASES(DD_CFG_STR(DD_##id##_ANALYTICS_ENABLED), DD_CFG_STR(DD_TRACE_##id##_ANALYTICS_ENABLED))) \ - CALIAS(DOUBLE, DD_TRACE_##id##_ANALYTICS_SAMPLE_RATE, DD_CFG_EXPSTR(DD_INTEGRATION_ANALYTICS_SAMPLE_RATE_DEFAULT), \ - CALIASES(DD_CFG_STR(DD_##id##_ANALYTICS_SAMPLE_RATE), DD_CFG_STR(DD_TRACE_##id##_ANALYTICS_SAMPLE_RATE))) - -#define DD_TRACE_OBFUSCATION_QUERY_STRING_REGEXP_DEFAULT \ - "(?i)(?:(?:\"|%22)?)(?:(?:old[-_]?|new[-_]?)?p(?:ass)?w(?:or)?d(?:1|2)?|pass(?:[-_]?phrase)?|secret|(?:api[-_]?|private[-_]?|public[-_]?|access[-_]?|secret[-_]?|app(?:lication)?[-_]?)key(?:[-_]?id)?|token|consumer[-_]?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?)(?:(?:\\s|%20)*(?:=|%3D)[^&]+|(?:\"|%22)(?:\\s|%20)*(?::|%3A)(?:\\s|%20)*(?:\"|%22)(?:%2[^2]|%[^2]|[^\"%])+(?:\"|%22))|(?:bearer(?:\\s|%20)+[a-z0-9._\\-]+|token(?::|%3A)[a-z0-9]{13}|gh[opsu]_[0-9a-zA-Z]{36}|ey[I-L](?:[\\w=-]|%3D)+\\.ey[I-L](?:[\\w=-]|%3D)+(?:\\.(?:[\\w.+/=-]|%3D|%2F|%2B)+)?|-{5}BEGIN(?:[a-z\\s]|%20)+PRIVATE(?:\\s|%20)KEY-{5}[^\\-]+-{5}END(?:[a-z\\s]|%20)+PRIVATE(?:\\s|%20)KEY(?:-{5})?(?:\\n|%0A)?|(?:ssh-(?:rsa|dss)|ecdsa-[a-z0-9]+-[a-z0-9]+)(?:\\s|%20|%09)+(?:[a-z0-9/.+]|%2F|%5C|%2B){100,}(?:=|%3D)*(?:(?:\\s|%20|%09)+[a-z0-9._-]+)?)" #ifdef __SANITIZE_ADDRESS__ #define DD_CRASHTRACKING_ENABLED_DEFAULT "false" @@ -102,257 +40,97 @@ enum ddtrace_sidecar_connection_mode { #define DD_CRASHTRACKING_ENABLED_DEFAULT "true" #endif -#define DD_CONFIGURATION_ALL \ - CONFIG(STRING, DD_TRACE_SOURCES_PATH, DD_DEFAULT_SOURCES_PATH, .ini_change = zai_config_system_ini_change) \ - CONFIG(BOOL, DD_AUTOLOAD_NO_COMPILE, "false", .ini_change = zai_config_system_ini_change) \ +#define DATADOG_CONFIGURATION \ CONFIG(STRING, DD_TRACE_AGENT_URL, "", .ini_change = zai_config_system_ini_change) \ CONFIG(STRING, DD_AGENT_HOST, "localhost", .ini_change = zai_config_system_ini_change) \ CONFIG(STRING, DD_DOGSTATSD_URL, "http://localhost:8125") \ CONFIG(STRING, DD_DOGSTATSD_HOST, "localhost") \ CONFIG(STRING, DD_API_KEY, "", .ini_change = zai_config_system_ini_change) \ - CONFIG(BOOL, DD_DISTRIBUTED_TRACING, "true") \ CONFIG(INT, DD_DOGSTATSD_PORT, "8125") \ - CONFIG(STRING, DD_ENV, "", .ini_change = ddtrace_alter_dd_env, \ + CONFIG(STRING, DD_ENV, "", .ini_change = datadog_alter_dd_env, \ .env_config_fallback = ddtrace_conf_otel_resource_attributes_env) \ - CONFIG(BOOL, DD_AUTOFINISH_SPANS, "false") \ - CONFIG(BOOL, DD_TRACE_URL_AS_RESOURCE_NAMES_ENABLED, "true") \ - CONFIG(BOOL, DD_HTTP_SERVER_ROUTE_BASED_NAMING, "true") \ - CONFIG(STRING, DD_SERVICE, "", .ini_change = ddtrace_alter_dd_service, \ + CONFIG(STRING, DD_SERVICE, "", .ini_change = datadog_alter_dd_service, \ .env_config_fallback = ddtrace_conf_otel_service_name) \ CONFIG(MAP, DD_SERVICE_MAPPING, "") \ CONFIG(CUSTOM(MAP), DD_TAGS, "", \ .env_config_fallback = ddtrace_conf_otel_resource_attributes_tags, \ .parser = dd_parse_tags) \ CONFIG(INT, DD_TRACE_AGENT_PORT, "8126", .ini_change = zai_config_system_ini_change) \ - CONFIG(BOOL, DD_TRACE_ANALYTICS_ENABLED, "false") \ - CONFIG(BOOL, DD_TRACE_APPEND_TRACE_IDS_TO_LOGS, "false") \ - CONFIG(BOOL, DD_TRACE_AUTO_FLUSH_ENABLED, "false") /* true in CLI */ \ CONFIG(BOOL, DD_TRACE_CLI_ENABLED, "true") \ - CONFIG(BOOL, DD_TRACE_MEASURE_COMPILE_TIME, "true") \ - CONFIG(BOOL, DD_TRACE_MEASURE_PEAK_MEMORY_USAGE, "true") \ - CONFIG(BOOL, DD_TRACE_DEBUG, "false", .ini_change = ddtrace_alter_dd_trace_debug) \ - CONFIG(BOOL, DD_TRACE_ENABLED, "true", .ini_change = ddtrace_alter_dd_trace_disabled_config, \ + CONFIG(BOOL, DD_TRACE_DEBUG, "false", .ini_change = datadog_alter_dd_trace_debug) \ + CONFIG(BOOL, DD_TRACE_ENABLED, "true", .ini_change = datadog_alter_dd_trace_disabled_config, \ .env_config_fallback = ddtrace_conf_otel_traces_exporter) \ CONFIG(BOOL, DD_INSTRUMENTATION_TELEMETRY_ENABLED, "true", .ini_change = zai_config_system_ini_change) \ - CONFIG(BOOL, DD_TELEMETRY_LOG_COLLECTION_ENABLED, "true") \ CONFIG(BOOL, DD_TRACE_HEALTH_METRICS_ENABLED, "false", .ini_change = zai_config_system_ini_change) \ CONFIG(DOUBLE, DD_TRACE_HEALTH_METRICS_HEARTBEAT_SAMPLE_RATE, "0.001") \ - CONFIG(BOOL, DD_TRACE_DB_CLIENT_SPLIT_BY_INSTANCE, "false") \ - CONFIG(BOOL, DD_TRACE_HTTP_CLIENT_SPLIT_BY_DOMAIN, "false") \ - CONFIG(BOOL, DD_TRACE_REDIS_CLIENT_SPLIT_BY_HOST, "false") \ - CONFIG(BOOL, DD_EXCEPTION_REPLAY_ENABLED, "false", .ini_change = ddtrace_alter_DD_EXCEPTION_REPLAY_ENABLED) \ - CONFIG(INT, DD_EXCEPTION_REPLAY_CAPTURE_MAX_FRAMES, "-1") \ - CONFIG(INT, DD_EXCEPTION_REPLAY_CAPTURE_INTERVAL_SECONDS, "3600") \ - CONFIG(STRING, DD_TRACE_MEMORY_LIMIT, "") \ CONFIG(BOOL, DD_TRACE_REPORT_HOSTNAME, "false") \ CONFIG(STRING, DD_HOSTNAME, "") \ - CONFIG(BOOL, DD_TRACE_FLUSH_COLLECT_CYCLES, "false") \ CONFIG(BOOL, DD_TRACE_FORCE_FLUSH_ON_SHUTDOWN, "false") /* true if pid == 1 || ppid == 1 */ \ CONFIG(BOOL, DD_TRACE_FORCE_FLUSH_ON_SIGTERM, "false") /* true if pid == 1 || ppid == 1 */ \ CONFIG(BOOL, DD_TRACE_FORCE_FLUSH_ON_SIGINT, "false") /* true if pid == 1 || ppid == 1 */ \ - CONFIG(BOOL, DD_TRACE_KAFKA_DISTRIBUTED_TRACING, "true") \ - CONFIG(BOOL, DD_TRACE_LARAVEL_QUEUE_DISTRIBUTED_TRACING, "true") \ - CONFIG(BOOL, DD_TRACE_SYMFONY_MESSENGER_DISTRIBUTED_TRACING, "true") \ - CONFIG(BOOL, DD_TRACE_SYMFONY_MESSENGER_MIDDLEWARES, "false") \ - CONFIG(BOOL, DD_TRACE_SYMFONY_HTTP_ROUTE, "true") \ - CONFIG(BOOL, DD_TRACE_REMOVE_ROOT_SPAN_LARAVEL_QUEUE, "true") \ - CONFIG(BOOL, DD_TRACE_REMOVE_ROOT_SPAN_SYMFONY_MESSENGER, "true") \ CONFIG(BOOL, DD_APPSEC_ENABLED, "false", .ini_change = zai_config_system_ini_change) \ CONFIG(BOOL, DD_APPSEC_RASP_ENABLED , "true") \ - CONFIG(BOOL, DD_TRACE_REMOVE_AUTOINSTRUMENTATION_ORPHANS, "false") \ - CONFIG(SET, DD_TRACE_RESOURCE_URI_FRAGMENT_REGEX, "") \ - CONFIG(SET, DD_TRACE_RESOURCE_URI_MAPPING_INCOMING, "") \ - CONFIG(SET, DD_TRACE_RESOURCE_URI_MAPPING_OUTGOING, "") \ - CONFIG(SET, DD_TRACE_RESOURCE_URI_QUERY_PARAM_ALLOWED, "") \ - CONFIG(SET, DD_TRACE_HTTP_URL_QUERY_PARAM_ALLOWED, "*") \ - CONFIG(SET, DD_TRACE_HTTP_POST_DATA_PARAM_ALLOWED, "") \ - CONFIG(INT, DD_TRACE_RATE_LIMIT, "100", .ini_change = zai_config_system_ini_change) \ - CONFIG(DOUBLE, DD_TRACE_SAMPLE_RATE, "-1", .ini_change = ddtrace_alter_DD_TRACE_SAMPLE_RATE, \ - .env_config_fallback = ddtrace_conf_otel_sample_rate) \ - CONFIG(JSON, DD_TRACE_SAMPLING_RULES, "[]") \ - CONFIG(CUSTOM(INT), DD_TRACE_SAMPLING_RULES_FORMAT, "glob", .parser = dd_parse_sampling_rules_format) \ - CONFIG(JSON, DD_SPAN_SAMPLING_RULES, "[]") \ - CONFIG(STRING, DD_SPAN_SAMPLING_RULES_FILE, "", .ini_change = ddtrace_alter_sampling_rules_file_config) \ - CONFIG(SET_OR_MAP_LOWERCASE, DD_TRACE_HEADER_TAGS, "", .ini_change = ddtrace_alter_DD_TRACE_HEADER_TAGS) \ - CONFIG(INT, DD_TRACE_X_DATADOG_TAGS_MAX_LENGTH, "512") \ - CONFIG(MAP, DD_TRACE_PEER_SERVICE_MAPPING, "") \ - CONFIG(BOOL, DD_TRACE_PEER_SERVICE_DEFAULTS_ENABLED, "false") \ - CONFIG(BOOL, DD_TRACE_REMOVE_INTEGRATION_SERVICE_NAMES_ENABLED, "false") \ - CONFIG(BOOL, DD_TRACE_PROPAGATE_SERVICE, "false") \ - CONFIG(SET_LOWERCASE, DD_TRACE_PROPAGATION_STYLE_EXTRACT, "datadog,tracecontext,B3,B3 single header,baggage") \ - CONFIG(SET_LOWERCASE, DD_TRACE_PROPAGATION_STYLE_INJECT, "datadog,tracecontext,baggage") \ - CONFIG(SET_LOWERCASE, DD_TRACE_PROPAGATION_STYLE, "datadog,tracecontext,baggage", \ - .env_config_fallback = ddtrace_conf_otel_propagators) \ - CONFIG(SET, DD_TRACE_BAGGAGE_TAG_KEYS, "user.id, session.id, account.id") \ - CONFIG(BOOL, DD_TRACE_IGNORE_AGENT_SAMPLING_RATES, "false", .ini_change = zai_config_system_ini_change) \ - CONFIG(SET, DD_TRACE_TRACED_INTERNAL_FUNCTIONS, "") \ CONFIG(INT, DD_TRACE_AGENT_TIMEOUT, DD_CFG_EXPSTR(DD_TRACE_AGENT_TIMEOUT_VAL), \ .ini_change = zai_config_system_ini_change) \ CONFIG(INT, DD_TRACE_AGENT_CONNECT_TIMEOUT, DD_CFG_EXPSTR(DD_TRACE_AGENT_CONNECT_TIMEOUT_VAL), \ .ini_change = zai_config_system_ini_change) \ - CONFIG(INT, DD_TRACE_DEBUG_PRNG_SEED, "-1", .ini_change = ddtrace_reseed_seed_change) \ - CONFIG(BOOL, DD_TRACE_SECURE_RANDOM, "false") \ CONFIG(BOOL, DD_LOG_BACKTRACE, "false") \ CONFIG(BOOL, DD_CRASHTRACKING_ENABLED, DD_CRASHTRACKING_ENABLED_DEFAULT) \ - CONFIG(BOOL, DD_TRACE_GENERATE_ROOT_SPAN, "true", .ini_change = ddtrace_span_alter_root_span_config) \ - CONFIG(INT, DD_TRACE_SPANS_LIMIT, "1000") \ - CONFIG(BOOL, DD_TRACE_128_BIT_TRACEID_GENERATION_ENABLED, "true") \ - CONFIG(BOOL, DD_TRACE_128_BIT_TRACEID_LOGGING_ENABLED, "true") \ - CONFIG(INT, DD_TRACE_BGS_CONNECT_TIMEOUT, DD_CFG_EXPSTR(DD_TRACE_BGS_CONNECT_TIMEOUT_VAL), \ - .ini_change = zai_config_system_ini_change) \ - CONFIG(INT, DD_TRACE_BGS_TIMEOUT, DD_CFG_EXPSTR(DD_TRACE_BGS_TIMEOUT_VAL), \ - .ini_change = zai_config_system_ini_change) \ CONFIG(INT, DD_TRACE_AGENT_FLUSH_INTERVAL, DD_CFG_EXPSTR(DD_TRACE_AGENT_FLUSH_INTERVAL_VAL), \ .ini_change = zai_config_system_ini_change) \ CONFIG(INT, DD_TELEMETRY_HEARTBEAT_INTERVAL, "60", .ini_change = zai_config_system_ini_change) \ - CONFIG(INT, DD_TELEMETRY_EXTENDED_HEARTBEAT_INTERVAL, "86400", \ - .ini_change = zai_config_system_ini_change) \ - CONFIG(INT, DD_TRACE_AGENT_FLUSH_AFTER_N_REQUESTS, "0") \ + CONFIG(INT, DD_TELEMETRY_EXTENDED_HEARTBEAT_INTERVAL, "86400", \ + .ini_change = zai_config_system_ini_change) \ CONFIG(INT, DD_TRACE_SHUTDOWN_TIMEOUT, "5000", .ini_change = zai_config_system_ini_change) \ CONFIG(BOOL, DD_TRACE_STARTUP_LOGS, "true") \ CONFIG(BOOL, DD_TRACE_ONCE_LOGS, "true") \ - CONFIG(INT, DD_TRACE_AGENT_RETRIES, "0", .ini_change = zai_config_system_ini_change) \ - 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_AGENTLESS, "false", .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_VERSION, "", .ini_change = ddtrace_alter_dd_version, \ + CONFIG(STRING, DD_VERSION, "", .ini_change = datadog_alter_dd_version, \ .env_config_fallback = ddtrace_conf_otel_resource_attributes_version) \ - CONFIG(STRING, DD_TRACE_OBFUSCATION_QUERY_STRING_REGEXP, DD_TRACE_OBFUSCATION_QUERY_STRING_REGEXP_DEFAULT) \ - CONFIG(BOOL, DD_TRACE_MEMCACHED_OBFUSCATION, "true") \ - CONFIG(BOOL, DD_TRACE_MONGODB_OBFUSCATION, "true") \ - CONFIG(BOOL, DD_TRACE_CLIENT_IP_ENABLED, "false") \ - CONFIG(CUSTOM(STRING), DD_TRACE_CLIENT_IP_HEADER, "", .parser = ddtrace_parse_client_ip_header_config) \ - CONFIG(BOOL, DD_TRACE_FORKED_PROCESS, "true") \ - CONFIG(INT, DD_TRACE_HOOK_LIMIT, "100") \ CONFIG(INT, DD_TRACE_BUFFER_SIZE, "2097152", .ini_change = zai_config_system_ini_change) \ CONFIG(INT, DD_TRACE_AGENT_MAX_PAYLOAD_SIZE, "52428800", .ini_change = zai_config_system_ini_change) \ - CONFIG(INT, DD_TRACE_AGENT_STACK_INITIAL_SIZE, "131072", .ini_change = zai_config_system_ini_change) \ CONFIG(INT, DD_TRACE_AGENT_STACK_BACKLOG, "12", .ini_change = zai_config_system_ini_change) \ CONFIG(INT, DD_TRACE_SIDECAR_BACKPRESSURE_BYTES, "4194304", .ini_change = zai_config_system_ini_change) \ 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 = ddtrace_alter_test_session_token) \ - CONFIG(BOOL, DD_TRACE_PROPAGATE_USER_ID_DEFAULT, "false") \ - CONFIG(CUSTOM(INT), DD_DBM_PROPAGATION_MODE, "disabled", .parser = dd_parse_dbm_mode) \ - CONFIG(BOOL, DD_DBM_INJECT_SQL_BASEHASH, "false") \ - CONFIG(CUSTOM(INT), DD_TRACE_SIDECAR_CONNECTION_MODE, "auto", .parser = dd_parse_sidecar_connection_mode) \ - CONFIG(SET, DD_TRACE_WORDPRESS_ADDITIONAL_ACTIONS, "") \ - CONFIG(BOOL, DD_TRACE_WORDPRESS_CALLBACKS, "true") \ - CONFIG(BOOL, DD_INTEGRATION_METRICS_ENABLED, "true", \ - .env_config_fallback = ddtrace_conf_otel_metrics_exporter) \ - CONFIG(BOOL, DD_METRICS_OTEL_ENABLED, "false") \ - CONFIG(BOOL, DD_LOGS_OTEL_ENABLED, "false") \ - CONFIG(BOOL, DD_TRACE_OTEL_ENABLED, "false") \ + 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(STRING, DD_TRACE_LOG_FILE, "", .ini_change = zai_config_system_ini_change) \ - CONFIG(STRING, DD_TRACE_LOG_LEVEL, "error", .ini_change = ddtrace_alter_dd_trace_log_level, \ + CONFIG(STRING, DD_TRACE_LOG_LEVEL, "error", .ini_change = datadog_alter_dd_trace_log_level, \ .env_config_fallback = ddtrace_conf_otel_log_level) \ CONFIG(BOOL, DD_APPSEC_SCA_ENABLED, "false", .ini_change = zai_config_system_ini_change) \ CONFIG(BOOL, DD_TRACE_GIT_METADATA_ENABLED, "true") \ CONFIG(STRING, DD_GIT_COMMIT_SHA, "") \ CONFIG(STRING, DD_GIT_REPOSITORY_URL, "") \ - CONFIG(STRING, DD_OPENAI_SERVICE, "") \ - CONFIG(BOOL, DD_OPENAI_METRICS_ENABLED, "true") \ - CONFIG(BOOL, DD_OPENAI_LOGS_ENABLED, "false") \ - CONFIG(INT, DD_OPENAI_SPAN_CHAR_LIMIT, "128") \ - CONFIG(DOUBLE, DD_OPENAI_SPAN_PROMPT_COMPLETION_SAMPLE_RATE, "1.0") \ - CONFIG(DOUBLE, DD_OPENAI_LOG_PROMPT_COMPLETION_SAMPLE_RATE, "0.1") \ - CONFIG(BOOL, DD_TRACE_WEBSOCKET_MESSAGES_ENABLED, "true") \ - CONFIG(BOOL, DD_TRACE_WEBSOCKET_MESSAGES_INHERIT_SAMPLING, "true") \ - CONFIG(BOOL, DD_TRACE_WEBSOCKET_MESSAGES_SEPARATE_TRACES, "true") \ CONFIG(BOOL, DD_INJECT_FORCE, "false", .ini_change = zai_config_system_ini_change) \ CONFIG(DOUBLE, DD_REMOTE_CONFIG_POLL_INTERVAL_SECONDS, "5.0", .ini_change = zai_config_system_ini_change) \ CONFIG(BOOL, DD_REMOTE_CONFIG_ENABLED, "true", .ini_change = zai_config_system_ini_change) \ - CONFIG(BOOL, DD_DYNAMIC_INSTRUMENTATION_ENABLED, "false", .ini_change = ddtrace_alter_dynamic_instrumentation_config) \ - CONFIG(SET, DD_DYNAMIC_INSTRUMENTATION_REDACTED_IDENTIFIERS, "", .ini_change = zai_config_system_ini_change) \ - CONFIG(BOOL, DD_APM_TRACING_ENABLED, "true") \ - CONFIG(SET, DD_DYNAMIC_INSTRUMENTATION_REDACTED_TYPES, "", .ini_change = zai_config_system_ini_change) \ - CONFIG(SET, DD_DYNAMIC_INSTRUMENTATION_REDACTION_EXCLUDED_IDENTIFIERS, "", .ini_change = zai_config_system_ini_change) \ - CONFIG(INT, DD_TRACE_BAGGAGE_MAX_ITEMS, "64") \ - CONFIG(INT, DD_TRACE_BAGGAGE_MAX_BYTES, "8192") \ - CONFIG(BOOL, DD_TRACE_INFERRED_PROXY_SERVICES_ENABLED, "false") \ - CONFIG(SET, DD_TRACE_HTTP_CLIENT_ERROR_STATUSES, "400-499", .ini_change = zai_config_system_ini_change) \ - CONFIG(SET, DD_TRACE_HTTP_SERVER_ERROR_STATUSES, "500-599", .ini_change = zai_config_system_ini_change) \ - CONFIG(BOOL, DD_CODE_ORIGIN_FOR_SPANS_ENABLED, "true", .ini_change = ddtrace_alter_DD_CODE_ORIGIN_FOR_SPANS_ENABLED) \ - CONFIG(INT, DD_CODE_ORIGIN_MAX_USER_FRAMES, "8") \ - CONFIG(BOOL, DD_TRACE_RESOURCE_RENAMING_ENABLED, "false") \ - CONFIG(BOOL, DD_TRACE_RESOURCE_RENAMING_ALWAYS_SIMPLIFIED_ENDPOINT, "false") \ - CONFIG(BOOL, DD_EXPERIMENTAL_PROPAGATE_PROCESS_TAGS_ENABLED, "true") \ - CONFIG(BOOL, DD_TRACE_STATS_COMPUTATION_ENABLED, "false") \ - DD_INTEGRATIONS + CONFIG(BOOL, DD_EXPERIMENTAL_PROPAGATE_PROCESS_TAGS_ENABLED, "true") -#ifndef _WIN32 -# define DD_CONFIGURATION \ - CONFIG(BOOL, DD_TRACE_SIDECAR_TRACE_SENDER, DD_CFG_EXPSTR(DD_SIDECAR_TRACE_SENDER_DEFAULT), .ini_change = zai_config_system_ini_change) \ - DD_CONFIGURATION_ALL +#define DD_CONFIGURATIONS_ONLY +#ifdef DDTRACE +#include #else -# define DD_CONFIGURATION DD_CONFIGURATION_ALL +#define DDTRACE_CONFIGURATION #endif +#undef DD_CONFIGURATIONS_ONLY + +#define DD_ALL_CONFIGURATIONS \ + DATADOG_CONFIGURATION \ + DDTRACE_CONFIGURATION \ #define CALIAS CONFIG -#define CONFIG(type, name, ...) DDTRACE_CONFIG_##name, -typedef enum { DD_CONFIGURATION } ddtrace_config_id; +#define CONFIG(type, name, ...) DATADOG_CONFIG_##name, +typedef enum { + DD_ALL_CONFIGURATIONS +} datadog_config_id; #undef CONFIG -#define BOOL(id) \ - static inline bool get_##id(void) { return IS_TRUE == Z_TYPE_P(zai_config_get_value(DDTRACE_CONFIG_##id)); } \ - static inline bool get_global_##id(void) { \ - return IS_TRUE == Z_TYPE(zai_config_memoized_entries[DDTRACE_CONFIG_##id].decoded_value); \ - } -#define INT(id) \ - static inline zend_long get_##id(void) { return Z_LVAL_P(zai_config_get_value(DDTRACE_CONFIG_##id)); } \ - static inline zend_long get_global_##id(void) { \ - return Z_LVAL(zai_config_memoized_entries[DDTRACE_CONFIG_##id].decoded_value); \ - } -#define DOUBLE(id) \ - static inline double get_##id(void) { return Z_DVAL_P(zai_config_get_value(DDTRACE_CONFIG_##id)); } \ - static inline double get_global_##id(void) { \ - return Z_DVAL(zai_config_memoized_entries[DDTRACE_CONFIG_##id].decoded_value); \ - } -#define STRING(id) \ - static inline zend_string *get_##id(void) { return Z_STR_P(zai_config_get_value(DDTRACE_CONFIG_##id)); } \ - static inline zend_string *get_global_##id(void) { \ - return Z_STR(zai_config_memoized_entries[DDTRACE_CONFIG_##id].decoded_value); \ - } -#define SET MAP -#define SET_LOWERCASE MAP -#define SET_OR_MAP_LOWERCASE MAP -#define JSON MAP -#define MAP(id) \ - static inline zend_array *get_##id(void) { return Z_ARR_P(zai_config_get_value(DDTRACE_CONFIG_##id)); } \ - static inline zend_array *get_global_##id(void) { \ - return Z_ARR(zai_config_memoized_entries[DDTRACE_CONFIG_##id].decoded_value); \ - } -#define CUSTOM(type) type - -#define CONFIG(type, name, ...) type(name) -DD_CONFIGURATION -#undef CONFIG +#define DD_CONFIGURATION DATADOG_CONFIGURATION +#include "configuration_helpers.h" #ifdef _WIN32 static inline bool get_global_DD_TRACE_SIDECAR_TRACE_SENDER(void) { return true; } #endif -#undef STRING -#undef MAP -#undef SET -#undef SET_LOWERCASE -#undef SET_OR_MAP_LOWERCASE -#undef JSON -#undef BOOL -#undef INT -#undef DOUBLE - -#undef CUSTOM -#undef CALIAS - -static inline int ddtrace_quiet_zpp(void) { - return PHP_DEBUG ? 0 : ZEND_PARSE_PARAMS_QUIET; -} - -void ddtrace_change_default_ini(ddtrace_config_id config_id, zai_str str); -bool ddtrace_runtime_config_is_modified(ddtrace_config_id config); - -#endif // DD_CONFIGURATION_H +#endif // DATADOG_CONFIGURATION_H diff --git a/ext/configuration_helpers.h b/ext/configuration_helpers.h new file mode 100644 index 00000000000..7107368fc15 --- /dev/null +++ b/ext/configuration_helpers.h @@ -0,0 +1,50 @@ +#define BOOL(id) \ + static inline bool get_##id(void) { return IS_TRUE == Z_TYPE_P(zai_config_get_value(DATADOG_CONFIG_##id)); } \ + static inline bool get_global_##id(void) { \ + return IS_TRUE == Z_TYPE(zai_config_memoized_entries[DATADOG_CONFIG_##id].decoded_value); \ + } +#define INT(id) \ + static inline zend_long get_##id(void) { return Z_LVAL_P(zai_config_get_value(DATADOG_CONFIG_##id)); } \ + static inline zend_long get_global_##id(void) { \ + return Z_LVAL(zai_config_memoized_entries[DATADOG_CONFIG_##id].decoded_value); \ + } +#define DOUBLE(id) \ + static inline double get_##id(void) { return Z_DVAL_P(zai_config_get_value(DATADOG_CONFIG_##id)); } \ + static inline double get_global_##id(void) { \ + return Z_DVAL(zai_config_memoized_entries[DATADOG_CONFIG_##id].decoded_value); \ + } +#define STRING(id) \ + static inline zend_string *get_##id(void) { return Z_STR_P(zai_config_get_value(DATADOG_CONFIG_##id)); } \ + static inline zend_string *get_global_##id(void) { \ + return Z_STR(zai_config_memoized_entries[DATADOG_CONFIG_##id].decoded_value); \ + } +#define SET MAP +#define SET_LOWERCASE MAP +#define SET_OR_MAP_LOWERCASE MAP +#define JSON MAP +#define MAP(id) \ + static inline zend_array *get_##id(void) { return Z_ARR_P(zai_config_get_value(DATADOG_CONFIG_##id)); } \ + static inline zend_array *get_global_##id(void) { \ + return Z_ARR(zai_config_memoized_entries[DATADOG_CONFIG_##id].decoded_value); \ + } +#define CUSTOM(type) type + +#define CALIAS CONFIG +#define CONFIG(type, name, ...) type(name) +DD_CONFIGURATION +#undef CONFIG +#undef CALIAS + +#undef STRING +#undef MAP +#undef SET +#undef SET_LOWERCASE +#undef SET_OR_MAP_LOWERCASE +#undef JSON +#undef BOOL +#undef INT +#undef DOUBLE + +#undef CUSTOM + +#undef DD_CONFIGURATION diff --git a/ext/crashtracking_frames.c b/ext/crashtracking_frames.c index 84bdecc2895..3a0df6eda5f 100644 --- a/ext/crashtracking_frames.c +++ b/ext/crashtracking_frames.c @@ -7,6 +7,7 @@ #include #include "sidecar.h" +#include "ffi_utils.h" static ddog_CharSlice dd_validate_zstr(zend_string *str) { if (zai_is_mapped(str, XtOffsetOf(zend_string, val))) { @@ -177,7 +178,7 @@ static void dd_frames_callback(void (*emit_frame)(const ddog_crasht_RuntimeStack } } -void ddtrace_register_crashtracking_frames_collection() { +void datadog_register_crashtracking_frames_collection() { ddog_crasht_register_runtime_frame_callback(dd_frames_callback); } diff --git a/ext/crashtracking_frames.h b/ext/crashtracking_frames.h index 4ffc051950e..349d12dfa43 100644 --- a/ext/crashtracking_frames.h +++ b/ext/crashtracking_frames.h @@ -1,6 +1,6 @@ -#ifndef DD_CRASHTRACKING_FRAMES_H -#define DD_CRASHTRACKING_FRAMES_H +#ifndef DATADOG_CRASHTRACKING_FRAMES_H +#define DATADOG_CRASHTRACKING_FRAMES_H -void ddtrace_register_crashtracking_frames_collection(void); +void datadog_register_crashtracking_frames_collection(void); -#endif // DD_CRASHTRACKING_FRAMES_H \ No newline at end of file +#endif // DATADOG_CRASHTRACKING_FRAMES_H \ No newline at end of file diff --git a/ext/crashtracking_windows.c b/ext/crashtracking_windows.c index a185d211672..b006db80462 100644 --- a/ext/crashtracking_windows.c +++ b/ext/crashtracking_windows.c @@ -1,6 +1,6 @@ #define _CRASHTRACKING_COLLECTOR -#include "ddtrace.h" +#include "datadog.h" #include "sidecar.h" #include "version.h" @@ -13,11 +13,11 @@ #include #include -bool init_crash_tracking(void) { +bool datadog_init_crash_tracking(void) { ddog_Vec_Tag tags = ddog_Vec_Tag_new(); - const ddog_crasht_Metadata metadata = ddtrace_setup_crashtracking_metadata(&tags); + const ddog_crasht_Metadata metadata = datadog_setup_crashtracking_metadata(&tags); - ddog_Endpoint* agent_endpoint = ddtrace_sidecar_agent_endpoint(); + ddog_Endpoint* agent_endpoint = datadog_sidecar_agent_endpoint(); bool result = ddog_setup_crashtracking(agent_endpoint, metadata); if (result) { diff --git a/ext/crashtracking_windows.h b/ext/crashtracking_windows.h index 32c9310ce7e..4841e3455ad 100644 --- a/ext/crashtracking_windows.h +++ b/ext/crashtracking_windows.h @@ -1,8 +1,8 @@ -#ifndef DD_TRACE_CRASHTRACKING_WINDOWS_H -#define DD_TRACE_CRASHTRACKING_WINDOWS_H +#ifndef DATADOG_CRASHTRACKING_WINDOWS_H +#define DATADOG_CRASHTRACKING_WINDOWS_H #include -bool init_crash_tracking(void); +bool datadog_init_crash_tracking(void); -#endif // DD_TRACE_CRASHTRACKING_WINDOWS_H +#endif // DATADOG_CRASHTRACKING_WINDOWS_H diff --git a/ext/datadog.c b/ext/datadog.c new file mode 100644 index 00000000000..cf8ce2023c5 --- /dev/null +++ b/ext/datadog.c @@ -0,0 +1,757 @@ +#include "datadog.h" +#include +#include +#include +#include +#include + +#include +#include + +#include "configuration.h" +#include "excluded_modules.h" +#include "agent_info.h" +#include "logging.h" +#include "phpinfo.h" +#include "process_tags.h" +#include "remote_config.h" +#include "sidecar.h" +#include "signals.h" +#include "startup_logging.h" +#include "telemetry.h" +#include "zend_hrtime.h" +#include +#ifndef _WIN32 +#include +#include +#else +#include +#include "crashtracking_windows.h" +#endif +#include +#include +#if PHP_VERSION_ID < 80000 +#include +#endif + +bool datadog_has_excluded_module; +zend_module_entry *datadog_module; +static int dd_main_pid; +#if PHP_VERSION_ID >= 80000 && PHP_VERSION_ID < 80200 +static bool dd_has_other_observers; +static int dd_observer_extension_backup = -1; + +void datadog_patch_zend_call_known_function(); +#endif + +datadog_php_sapi datadog_active_sapi = DATADOG_PHP_SAPI_UNKNOWN; + +ddog_CharSlice php_version_rt; + +ZEND_DECLARE_MODULE_GLOBALS(datadog) + +#ifdef COMPILE_DL_DDTRACE +ZEND_GET_MODULE(datadog) +#ifdef ZTS +TSRM_TLS void *TSRMLS_CACHE = NULL; +#endif +#endif + +int datadog_disable = 0; // 0 = enabled, 1 = disabled via INI, 2 = disabled, but MINIT was fully executed +static ZEND_INI_MH(dd_OnUpdateDisabled) { + UNUSED(entry, mh_arg1, mh_arg2, mh_arg3, stage); + if (!datadog_disable) { + datadog_disable = zend_ini_parse_bool(new_value); + } + return SUCCESS; +} + +PHP_INI_BEGIN() + ZEND_INI_ENTRY("ddtrace.disable", "0", PHP_INI_SYSTEM, dd_OnUpdateDisabled) + + // Exposed for testing only + STD_PHP_INI_ENTRY("ddtrace.cgroup_file", "/proc/self/cgroup", PHP_INI_SYSTEM, OnUpdateString, cgroup_file, + zend_datadog_globals, datadog_globals) +PHP_INI_END() + +#if PHP_VERSION_ID >= 70300 && PHP_VERSION_ID < 70400 +static void datadog_sort_modules(void *base, size_t count, size_t siz, compare_func_t compare, swap_func_t swp) { + UNUSED(siz); + UNUSED(compare); + UNUSED(swp); + + // swap ddtrace and opcache for the rest of the modules lifecycle, so that opcache is always executed after ddtrace + for (Bucket *module = base, *end = module + count, *datadog_module = NULL; module < end; ++module) { + zend_module_entry *m = (zend_module_entry *)Z_PTR(module->val); + if (m->name == datadog_module_entry.name) { + datadog_module = module; + } + if (datadog_module && strcmp(m->name, "Zend OPcache") == 0) { + Bucket tmp = *datadog_module; + *datadog_module = *module; + *module = tmp; + break; + } + } +} +#endif + +#ifndef _WIN32 +void datadog_signal_block_handlers_startup(void); +#endif +void datadog_pcntl_handlers_startup(void); + +// put this into startup so that other extensions running code as part of rinit do not crash +static int datadog_startup(zend_extension *extension) { + UNUSED(extension); + +#if PHP_VERSION_ID >= 70300 && PHP_VERSION_ID < 70400 + // Turns out with zai config we have dynamically allocated INI entries. This does not play well with PHP 7.3 + // As of PHP 7.3 opcache stores INI entry values in SHM. However, only as of PHP 7.4 opcache delays detaching SHM. + // In PHP 7.3 SHM is freed in MSHUTDOWN, which may be executed before our extension, if we do not force an order. + // We have to sort this manually here, as opcache only registers itself as extension during zend_extension.startup. + zend_hash_sort_ex(&module_registry, datadog_sort_modules, NULL, 0); +#endif + +#if PHP_VERSION_ID >= 80000 && PHP_VERSION_ID < 80200 + dd_has_other_observers = ZEND_OBSERVER_ENABLED; +#endif + +#if PHP_VERSION_ID >= 80000 && PHP_VERSION_ID < 80200 +#if PHP_VERSION_ID < 80100 +#define BUG_STACK_ALLOCATED_CALL_PATCH_VERSION 16 +#else +#define BUG_STACK_ALLOCATED_CALL_PATCH_VERSION 3 +#endif + zend_long patch_version = Z_LVAL_P(zend_get_constant_str(ZEND_STRL("PHP_RELEASE_VERSION"))); + if (patch_version < BUG_STACK_ALLOCATED_CALL_PATCH_VERSION) { + datadog_patch_zend_call_known_function(); + } +#endif + + if (!datadog_disable) { + datadog_excluded_modules_startup(); + + // pcntl handlers have to run even if tracing of pcntl extension is not enabled. + datadog_pcntl_handlers_startup(); + +#ifndef _WIN32 + // Block remote-config signals of some functions + datadog_signal_block_handlers_startup(); +#endif + } + +#ifdef DDTRACE + ddtrace_startup(extension); +#endif + + return SUCCESS; +} + +static void datadog_shutdown(zend_extension *extension) { +#ifdef DDTRACE + ddtrace_shutdown(extension); +#endif +} + +static void dd_activate_once(void) { + datadog_config_first_rinit(); + if (dd_main_pid != getpid()) { // equal to session id if not a fork + datadog_generate_runtime_id(); + } + + // must run before the first zai_hook_activate as tracer telemetry setup installs a global hook + if (!datadog_disable) { + bool appsec_activation = false; + bool appsec_config = false; + + // if we're to enable appsec, we need to enable sidecar + datadog_sidecar_configure_appsec(&appsec_activation, &appsec_config); + + datadog_sidecar_setup(appsec_activation, appsec_config); +#ifdef DDTRACE + ddtrace_activate_once(); +#endif + } +} + +static pthread_once_t dd_activate_once_control = PTHREAD_ONCE_INIT; + +static bool dd_is_cli_autodisabled(const char *arg) { + const char *slashend = strrchr(arg, '/'); + const char *backslashend = strrchr(arg, '\\'); + arg = MAX(MAX(slashend, backslashend) + 1, arg); + return strcmp(arg, "composer") == 0 || strcmp(arg, "composer.phar") == 0; +} + +static void datadog_activate(void) { + ddog_reset_logger(); + + if (!datadog_disable && datadog_has_excluded_module == true) { + datadog_disable = 2; + } + + datadog_telemetry_rinit(); + +#ifdef DDTRACE + ddtrace_activate_early(); +#endif + + // ZAI config is always set up + pthread_once(&dd_activate_once_control, dd_activate_once); + zai_config_rinit(); + + if (!datadog_disable) { + datadog_sidecar_ensure_active(); + } + + datadog_sidecar_activate(); + + if (!datadog_disable && strcmp(sapi_module.name, "cli") == 0) { + if (zai_config_memoized_entries[DATADOG_CONFIG_DD_TRACE_CLI_ENABLED].name_index == ZAI_CONFIG_ORIGIN_DEFAULT && SG(request_info).argv && dd_is_cli_autodisabled(SG(request_info).argv[0])) { + zend_string *zero = zend_string_init("0", 1, 0); + zend_alter_ini_entry(zai_config_memoized_entries[DATADOG_CONFIG_DD_TRACE_CLI_ENABLED].ini_entries[0]->name, zero, + ZEND_INI_USER, ZEND_INI_STAGE_RUNTIME); + zend_string_release(zero); + } + if (!get_DD_TRACE_CLI_ENABLED()) { + datadog_disable = 2; + } + } + +#ifdef DDTRACE + ddtrace_activate_late(); +#endif +} + +static void datadog_deactivate(void) { +#if PHP_VERSION_ID >= 80000 && PHP_VERSION_ID < 80200 + if (dd_observer_extension_backup != -1) { + zend_observer_fcall_op_array_extension = dd_observer_extension_backup; + dd_observer_extension_backup = -1; + } +#endif +} + +static zend_extension dd_zend_extension_entry = {"ddtrace", + PHP_DDTRACE_VERSION, + "Datadog", + "https://github.com/DataDog/dd-trace-php", + "Copyright Datadog", + datadog_startup, + datadog_shutdown, + datadog_activate, + datadog_deactivate, + NULL, +#if PHP_VERSION_ID < 80000 && defined(DDTRACE) + zai_interceptor_op_array_pass_two, +#else + NULL, +#endif + NULL, + NULL, + NULL, +#if PHP_VERSION_ID < 80000 && defined(DDTRACE) + zai_interceptor_op_array_ctor, +#else + NULL, +#endif +#ifdef DDTRACE + zai_hook_unresolve_op_array, +#else + NULL, +#endif + STANDARD_ZEND_EXTENSION_PROPERTIES}; + +static void php_datadog_init_globals(zend_datadog_globals *ng) { memset(ng, 0, sizeof(zend_datadog_globals)); } + +static PHP_GINIT_FUNCTION(datadog) { +#if defined(COMPILE_DL_DDTRACE) && defined(ZTS) + ZEND_TSRMLS_CACHE_UPDATE(); +#endif + php_datadog_init_globals(datadog_globals); +#if ZTS + datadog_thread_ginit(); +#endif + datadog_globals->sidecar_universal_service_tags_mutex = tsrm_mutex_alloc(); + zend_hash_init(&datadog_globals->git_metadata, 8, unused, (dtor_func_t)datadog_git_metadata_dtor, 1); + +#ifdef DDTRACE + ddtrace_ginit(datadog_globals); +#endif +} + +// Rust code will call __cxa_thread_atexit_impl. This is a weak symbol; it's defined by glibc. +// The problem is that calls to __cxa_thread_atexit_impl cause shared libraries to remain referenced until the calling thread terminates. +// However in NTS builds the calling thread is the main thread and thus the shared object (i.e. ddtrace.so) WILL remain loaded. +// This is problematic with e.g. apache which, upon reloading will unload all PHP modules including PHP itself, then reload. +// This prevents us from a) having the weak symbols updated to the new locations and b) having ddtrace updates going live without hard restart. +// Thus, we need to intercept it: define it ourselves so that the linker will force the rust code to call our code here. +// Then we can collect the callbacks and invoke them ourselves right at thread shutdown, i.e. GSHUTDOWN. +#ifdef CXA_THREAD_ATEXIT_WRAPPER +#define CXA_THREAD_ATEXIT_PHP ((void *)0) +#define CXA_THREAD_ATEXIT_UNINITIALIZED ((void *)1) +#define CXA_THREAD_ATEXIT_UNAVAILABLE ((void *)2) + +static int (*glibc__cxa_thread_atexit_impl)(void (*func)(void *), void *obj, void *dso_symbol) = CXA_THREAD_ATEXIT_UNINITIALIZED; +static pthread_key_t dd_cxa_thread_atexit_key; // fallback for sidecar + +struct dd_rust_thread_destructor { + void (*dtor)(void *); + void *obj; + struct dd_rust_thread_destructor *next; +}; +// Use __thread explicitly: ZEND_TLS is empty on NTS builds. +static __thread struct dd_rust_thread_destructor *dd_rust_thread_destructors = NULL; +ZEND_TLS bool dd_is_main_thread = false; + +void dd_run_rust_thread_destructors(void *unused) { + UNUSED(unused); + struct dd_rust_thread_destructor *entry = dd_rust_thread_destructors; + dd_rust_thread_destructors = NULL; // destructors _may_ be invoked multiple times. We need to reset thus. + while (entry) { + struct dd_rust_thread_destructor *cur = entry; + cur->dtor(cur->obj); + entry = entry->next; + free(cur); + } +} + +// Note: this symbol is not public +int __cxa_thread_atexit_impl(void (*func)(void *), void *obj, void *dso_symbol) { + if (glibc__cxa_thread_atexit_impl == CXA_THREAD_ATEXIT_UNINITIALIZED) { + glibc__cxa_thread_atexit_impl = NULL; // DL_FETCH_SYMBOL(RTLD_DEFAULT, "__cxa_thread_atexit_impl"); + if (glibc__cxa_thread_atexit_impl == NULL) { + // no race condition here: logging is initialized in MINIT, at which point only a single thread lives + glibc__cxa_thread_atexit_impl = CXA_THREAD_ATEXIT_UNAVAILABLE; + pthread_key_create(&dd_cxa_thread_atexit_key, dd_run_rust_thread_destructors); + } + } + + if (glibc__cxa_thread_atexit_impl != CXA_THREAD_ATEXIT_PHP && glibc__cxa_thread_atexit_impl != CXA_THREAD_ATEXIT_UNAVAILABLE) { + return glibc__cxa_thread_atexit_impl(func, obj, dso_symbol); + } + + if (glibc__cxa_thread_atexit_impl == CXA_THREAD_ATEXIT_UNAVAILABLE) { + pthread_setspecific(dd_cxa_thread_atexit_key, (void *)0x1); // needs to be non-NULL + } + + struct dd_rust_thread_destructor *entry = malloc(sizeof(struct dd_rust_thread_destructor)); + entry->dtor = func; + entry->obj = obj; + entry->next = dd_rust_thread_destructors; + dd_rust_thread_destructors = entry; + return 0; +} + +static void dd_clean_main_thread_locals() { + dd_run_rust_thread_destructors(NULL); +} +#endif + +static PHP_GSHUTDOWN_FUNCTION(datadog) { +#if ZTS + datadog_thread_gshutdown(); +#endif + if (datadog_globals->agent_config_reader) { + ddog_agent_remote_config_reader_drop(datadog_globals->agent_config_reader); + } + if (datadog_globals->remote_config_state) { + ddog_shutdown_remote_config(datadog_globals->remote_config_state); + } + if (datadog_globals->agent_info_reader) { + ddog_drop_agent_info_reader(datadog_globals->agent_info_reader); + } + if (datadog_globals->telemetry_buffer) { + ddog_sidecar_telemetry_buffer_drop(datadog_globals->telemetry_buffer); + } + + if (datadog_globals->telemetry_cache) { + ddog_sidecar_telemetry_cache_drop(datadog_globals->telemetry_cache); + } + + zend_hash_destroy(&datadog_globals->git_metadata); + + // Drop the per-thread sidecar transport (thread-lifetime, one per thread). + datadog_sidecar_gshutdown(datadog_globals); + + tsrm_mutex_free(datadog_globals->sidecar_universal_service_tags_mutex); + +#ifdef DDTRACE + ddtrace_gshutdown(datadog_globals); +#endif + +#ifdef CXA_THREAD_ATEXIT_WRAPPER + // FrankenPHP calls `ts_free_thread()` in rshutdown + if (!dd_is_main_thread && datadog_active_sapi != DATADOG_PHP_SAPI_FRANKENPHP) { + dd_run_rust_thread_destructors(NULL); + } +#endif +} + +static bool dd_is_compatible_sapi() { + switch (datadog_active_sapi) { + case DATADOG_PHP_SAPI_APACHE2HANDLER: + case DATADOG_PHP_SAPI_CGI_FCGI: + case DATADOG_PHP_SAPI_CLI: + case DATADOG_PHP_SAPI_CLI_SERVER: + case DATADOG_PHP_SAPI_FPM_FCGI: + case DATADOG_PHP_SAPI_FRANKENPHP: + case DATADOG_PHP_SAPI_TEA: + return true; + + default: + return false; + } +} + +static void dd_disable_if_incompatible_sapi_detected(void) { + if (UNEXPECTED(!dd_is_compatible_sapi())) { + LOG(WARN, "Incompatible SAPI detected '%s'; disabling ddtrace", sapi_module.name); + datadog_disable = 1; + } +} + +static PHP_MINIT_FUNCTION(datadog) { + UNUSED(type); + zval *php_version = zend_get_constant_str(ZEND_STRL("PHP_VERSION")); + if (php_version && Z_TYPE_P(php_version) == IS_STRING) { + php_version_rt = (ddog_CharSlice){Z_STRVAL_P(php_version), Z_STRLEN_P(php_version)}; + } else { + zend_error(E_CORE_WARNING, "Failed to get PHP_VERSION constant"); + return FAILURE; + } + + datadog_active_sapi = datadog_php_sapi_from_name(datadog_php_string_view_from_cstr(sapi_module.name)); + +#ifdef CXA_THREAD_ATEXIT_WRAPPER + // FrankenPHP calls `ts_free_thread()` in rshutdown + if (datadog_active_sapi != DATADOG_PHP_SAPI_FRANKENPHP) { + dd_is_main_thread = true; + glibc__cxa_thread_atexit_impl = CXA_THREAD_ATEXIT_PHP; + atexit(dd_clean_main_thread_locals); + } +#endif + + // Reset on every minit for `apachectl graceful`. + dd_activate_once_control = (pthread_once_t)PTHREAD_ONCE_INIT; + + +#if PHP_VERSION_ID < 70300 || (defined(_WIN32) && PHP_VERSION_ID >= 80300 && PHP_VERSION_ID < 80400) + datadog_startup_hrtime(); +#endif + + REGISTER_INI_ENTRIES(); + + zval *datadog_module_zv = zend_hash_str_find(&module_registry, ZEND_STRL("ddtrace")); + if (datadog_module_zv) { + datadog_module = Z_PTR_P(datadog_module_zv); + } + + dd_main_pid = getpid(); + datadog_generate_session_id(); + + // Make sure it's available for appsec, before any early returns + dd_ip_extraction_startup(); + + // config initialization needs to be at the top + // This also initialiyzed logging, so no logs may be emitted before this. + datadog_log_init(); +#ifdef DDTRACE + ddtrace_pre_config_minit(); +#endif + if (!datadog_config_minit(module_number)) { + return FAILURE; + } + + dd_disable_if_incompatible_sapi_detected(); + +#ifdef DDTRACE + ddtrace_minit_early(module_number); +#endif + + /* This allows an extension (e.g. extension=ddtrace.so) to have zend_engine + * hooks too, but not loadable as zend_extension=ddtrace.so. + * See http://www.phpinternalsbook.com/php7/extensions_design/zend_extensions.html#hybrid-extensions + * {{{ */ + zend_register_extension(&dd_zend_extension_entry, datadog_module_entry.handle); + // The original entry is copied into the module registry when the module is + // registered, so we search the module registry to find the right + // zend_module_entry to modify. + zend_module_entry *mod_ptr = + zend_hash_str_find_ptr(&module_registry, PHP_DDTRACE_EXTNAME, sizeof(PHP_DDTRACE_EXTNAME) - 1); + if (mod_ptr == NULL) { + // This shouldn't happen, possibly a bug if it does. + zend_error(E_CORE_WARNING, + "Failed to find ddtrace extension in " + "registered modules. Please open a bug report."); + + return FAILURE; + } + mod_ptr->handle = NULL; + /* }}} */ + + if (datadog_disable) { + return SUCCESS; + } + +#ifndef _WIN32 + datadog_set_coredumpfilter(); +#endif + + datadog_log_minit(); + + datadog_sidecar_minit(); + +#ifdef DDTRACE + ddtrace_minit_late(); +#endif + + datadog_minit_remote_config(); + +#ifndef _WIN32 + datadog_signals_minit(); +#endif + ddtrace_set_container_cgroup_path((ddog_CharSlice){ .ptr = DATADOG_G(cgroup_file), .len = strlen(DATADOG_G(cgroup_file)) }); + + return SUCCESS; +} + +static PHP_MSHUTDOWN_FUNCTION(datadog) { + UNUSED(module_number, type); + + UNREGISTER_INI_ENTRIES(); + +#ifdef DDTRACE + ddtrace_mshutdown(); +#endif + + if (datadog_disable == 1) { + zai_config_mshutdown(); + zai_json_shutdown_bindings(); + return SUCCESS; + } + + datadog_mshutdown_remote_config(); + +#ifndef _WIN32 + datadog_signals_mshutdown(); +#endif + + datadog_log_mshutdown(); + + zai_config_mshutdown(); + zai_json_shutdown_bindings(); + + datadog_sidecar_shutdown(); + + datadog_process_tags_mshutdown(); + + return SUCCESS; +} + +static void dd_rinit_once(void) { + // Collect process tags now that script path is available + if (get_global_DD_EXPERIMENTAL_PROPAGATE_PROCESS_TAGS_ENABLED()) { + datadog_process_tags_first_rinit(); + datadog_sidecar_update_process_tags(); + } + + // Uses config, cannot run earlier +#ifndef _WIN32 + datadog_signals_first_rinit(); +#else + if (get_DD_INSTRUMENTATION_TELEMETRY_ENABLED() && get_DD_CRASHTRACKING_ENABLED()) { + datadog_init_crash_tracking(); + } +#endif + + datadog_startup_logging_first_rinit(); + +#ifdef DDTRACE + ddtrace_first_rinit(); +#endif +} + +static pthread_once_t dd_rinit_once_control = PTHREAD_ONCE_INIT; + +static PHP_RINIT_FUNCTION(datadog) { + UNUSED(module_number, type); + + // Do after env check, so that RC data is not updated before RC init + DATADOG_G(request_initialized) = true; + + if (!DATADOG_G(remote_config_state) && datadog_endpoint) { + DATADOG_G(remote_config_state) = ddog_init_remote_config_state(datadog_endpoint, get_DD_DYNAMIC_INSTRUMENTATION_ENABLED()); + } + + // We need to init RC for the sidecar to write to it immediately + if (DATADOG_G(remote_config_state)) { + datadog_rinit_remote_config(); + } + + datadog_sidecar_rinit(); + + // Things that should only run on the first RINIT after each minit. + pthread_once(&dd_rinit_once_control, dd_rinit_once); + + if (!DATADOG_G(agent_config_reader) && !get_global_DD_TRACE_IGNORE_AGENT_SAMPLING_RATES()) { + if (get_global_DD_TRACE_SIDECAR_TRACE_SENDER()) { + if (datadog_endpoint) { + DATADOG_G(agent_config_reader) = ddog_agent_remote_config_reader_for_endpoint(datadog_endpoint); + } +#if !defined(_WIN32) && defined(DDTRACE) + } else if (ddtrace_coms_agent_config_handle) { + ddog_agent_remote_config_reader_for_anon_shm(ddtrace_coms_agent_config_handle, &DATADOG_G(agent_config_reader)); +#endif + } + } + + datadog_log_rinit(PG(error_log)); + + datadog_agent_info_rinit(); + + // Single combined read: applies env, container-hash, and concentrator config. + datadog_apply_agent_info(); + +#ifdef DDTRACE + ddtrace_rinit(); +#endif + + return SUCCESS; +} + +static void dd_shutdown_observer() { +#if PHP_VERSION_ID >= 80000 && PHP_VERSION_ID < 80200 +#if PHP_VERSION_ID < 80100 +#define RUN_TIME_CACHE_OBSERVER_PATCH_VERSION 18 +#else +#define RUN_TIME_CACHE_OBSERVER_PATCH_VERSION 4 +#endif + + zend_long patch_version = Z_LVAL_P(zend_get_constant_str(ZEND_STRL("PHP_RELEASE_VERSION"))); + if (patch_version < RUN_TIME_CACHE_OBSERVER_PATCH_VERSION) { + // Just do it if we think to be the only observer ... don't want to break other functionalities + if (!dd_has_other_observers) { + // We really should not have to do it. But there is a bug before PHP 8.0.18 and 8.1.4 respectively, causing observer fcall info being freed before stream shutdown (which may still invoke user code) + dd_observer_extension_backup = zend_observer_fcall_op_array_extension; + zend_observer_fcall_op_array_extension = -1; + } + } +#endif + +} + +static PHP_RSHUTDOWN_FUNCTION(datadog) { + UNUSED(module_number, type); + + // We deliberately select to not free some data structures, as to avoid the overhead of freeing them. + // Just proper destruction can have significant and easily measurable overhead on applications. + // Prior to PHP 7.2 fast shutdown was an opcache only feature +#if ZEND_DEBUG || PHP_VERSION_ID < 70200 + bool fast_shutdown = 0; +#elif defined(__SANITIZE_ADDRESS__) + char *force_fast_shutdown = getenv("ZEND_ASAN_FORCE_FAST_SHUTDOWN"); + bool fast_shutdown = ( + is_zend_mm() + || (force_fast_shutdown && ZEND_ATOL(force_fast_shutdown)) + ) && !EG(full_tables_cleanup); +#else + bool fast_shutdown = is_zend_mm() && !EG(full_tables_cleanup); +#endif + + if (DATADOG_G(remote_config_state)) { + datadog_rshutdown_remote_config(); + } + + if (!datadog_disable) { + dd_shutdown_observer(); + } + +#ifdef DDTRACE + ddtrace_rshutdown(fast_shutdown); +#endif + + datadog_sidecar_finalize(true); + DATADOG_G(request_initialized) = false; + + datadog_telemetry_rshutdown(); + datadog_sidecar_rshutdown(); + + datadog_git_rshutdown(); + + if (DATADOG_G(last_service_name)) { + zend_string_release(DATADOG_G(last_service_name)); + DATADOG_G(last_service_name) = NULL; + } + if (DATADOG_G(last_env_name)) { + zend_string_release(DATADOG_G(last_env_name)); + DATADOG_G(last_env_name) = NULL; + } + if (DATADOG_G(last_version)) { + zend_string_release(DATADOG_G(last_version)); + DATADOG_G(last_version) = NULL; + } + + return SUCCESS; +} + +#if PHP_VERSION_ID < 80000 +int datadog_post_deactivate(void) { +#else +zend_result datadog_post_deactivate(void) { +#endif +#ifdef DDTRACE + ddtrace_post_deactivate(); +#endif + + // zai config may be accessed indirectly via other modules RSHUTDOWN, so delay this until the last possible time + zai_config_rshutdown(); + + return SUCCESS; +} + +static PHP_MINFO_FUNCTION(datadog) { + UNUSED(zend_module); + + datadog_phpinfo(); + + DISPLAY_INI_ENTRIES(); +} + +void datadog_internal_handle_fork(void) { + // CHILD PROCESS + datadog_sidecar_handle_fork(); + if (DATADOG_G(agent_config_reader)) { + ddog_agent_remote_config_reader_drop(DATADOG_G(agent_config_reader)); + DATADOG_G(agent_config_reader) = NULL; + } + if (DATADOG_G(remote_config_state)) { + ddog_shutdown_remote_config(DATADOG_G(remote_config_state)); + DATADOG_G(remote_config_state) = NULL; + } + if (DATADOG_G(agent_info_reader)) { + ddog_drop_agent_info_reader(DATADOG_G(agent_info_reader)); + DATADOG_G(agent_info_reader) = NULL; + } + datadog_generate_runtime_id(); + +#ifdef DDTRACE + ddtrace_internal_handle_fork(); +#endif +} + +static const zend_module_dep datadog_module_deps[] = { + ZEND_MOD_REQUIRED("json") + ZEND_MOD_REQUIRED("standard") + ZEND_MOD_OPTIONAL("openetelemetry") // make sure we load after otel to insert the hook function if it doesn't exist yet + ZEND_MOD_END}; + +zend_module_entry datadog_module_entry = {STANDARD_MODULE_HEADER_EX, NULL, + datadog_module_deps, PHP_DDTRACE_EXTNAME, + NULL, PHP_MINIT(datadog), + PHP_MSHUTDOWN(datadog), PHP_RINIT(datadog), + PHP_RSHUTDOWN(datadog), PHP_MINFO(datadog), + PHP_DDTRACE_VERSION, PHP_MODULE_GLOBALS(datadog), + PHP_GINIT(datadog), PHP_GSHUTDOWN(datadog), + datadog_post_deactivate, STANDARD_MODULE_PROPERTIES_EX}; diff --git a/ext/datadog.h b/ext/datadog.h new file mode 100644 index 00000000000..29ede972fd5 --- /dev/null +++ b/ext/datadog.h @@ -0,0 +1,112 @@ +#ifndef DATADOG_H +#define DATADOG_H + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include +#include +#include +#include +#include + +#include "version.h" +#include "compatibility.h" +#include "git.h" +#include "threads.h" + +extern int datadog_disable; +extern zend_module_entry datadog_module_entry; +extern zend_module_entry *datadog_module; // pointer to actually used copy by PHP + +extern datadog_php_sapi datadog_active_sapi; + +extern ddog_CharSlice php_version_rt; + +#if defined(COMPILE_DL_DDTRACE) && defined(__GLIBC__) && __GLIBC_MINOR__ +#define CXA_THREAD_ATEXIT_WRAPPER 1 +#endif + +void datadog_internal_handle_fork(void); +#ifdef CXA_THREAD_ATEXIT_WRAPPER +void dd_run_rust_thread_destructors(void *unused); +#endif + +typedef struct { + uint64_t low; + union { + uint64_t high; + struct { + ZEND_ENDIAN_LOHI( + uint32_t padding // zeroes + , + uint32_t time + ) + }; + }; +} datadog_trace_id; + +#include + +// clang-format off +ZEND_BEGIN_MODULE_GLOBALS(datadog) +#if PHP_VERSION_ID < 70100 + bool zai_vm_interrupt; +#endif + bool reread_remote_configuration; + + ddog_SidecarTransport *sidecar; + ddog_QueueId sidecar_queue_id; + MUTEX_T sidecar_universal_service_tags_mutex; + bool remote_config_writing; // true while RC WRITE mode INI update is in progress + ddog_AgentRemoteConfigReader *agent_config_reader; + ddog_RemoteConfigState *remote_config_state; + ddog_AgentInfoReader *agent_info_reader; + zend_string *last_service_name; + zend_string *last_env_name; + zend_string *last_version; + ddog_Vec_Tag active_global_tags; + + bool request_initialized; + ddog_SidecarActionsBuffer *telemetry_buffer; + ddog_SidecarActionsBuffer *metrics_buffer; + + bool asm_event_emitted; + + HashTable git_metadata; + zend_string *git_commit; + zend_string *git_repository_url; + bool git_resolved; + + ddog_ShmCacheMap *telemetry_cache; + HashTable otel_config_telemetry; + + char *cgroup_file; + zend_bool backtrace_handler_already_run; + +#if DDTRACE + ddtrace_globals ddtrace; +#endif +ZEND_END_MODULE_GLOBALS(datadog) +// clang-format on + +#ifdef ZTS +# if defined(__has_attribute) && __has_attribute(tls_model) +# define ATTR_TLS_GLOBAL_DYNAMIC __attribute__((tls_model("global-dynamic"))) +# else +# define ATTR_TLS_GLOBAL_DYNAMIC +# endif +extern TSRM_TLS void *ATTR_TLS_GLOBAL_DYNAMIC TSRMLS_CACHE; +# define DATADOG_G(v) ZEND_TSRMG(datadog_globals_id, zend_datadog_globals *, v) +# define DATADOG_GLOBALS_PTR() TSRMG_BULK_STATIC(datadog_globals_id, zend_datadog_globals *) +#else +# define DATADOG_G(v) (datadog_globals.v) +# define DATADOG_GLOBALS_PTR() (&datadog_globals) +#endif + +#define PHP_DDTRACE_EXTNAME "ddtrace" +#ifndef PHP_DDTRACE_VERSION +#define PHP_DDTRACE_VERSION "0.0.0-unknown" +#endif + +#endif // DATADOG_H \ No newline at end of file diff --git a/ext/datadog_export.h b/ext/datadog_export.h new file mode 100644 index 00000000000..87e373b9bed --- /dev/null +++ b/ext/datadog_export.h @@ -0,0 +1,26 @@ +#ifndef DATADOG_EXPORT_H +#define DATADOG_EXPORT_H + +// clang-format off +/* Define DATADOG_STATIC before including this header to avoid exporting the + * functions, which usually is what is desired when building a static lib, + * hence the name. + */ +#ifdef DATADOG_STATIC +# define DATADOG_PUBLIC +#else +# ifndef DATADOG_PUBLIC +# ifndef _WIN32 +# define DATADOG_PUBLIC __attribute__((visibility("default"))) +# else +# define DATADOG_PUBLIC __declspec(dllexport) +# endif +# endif +#endif + +#ifndef DATADOG_DEPRECATED +# define DATADOG_DEPRECATED __attribute__ ((__deprecated__)) +#endif +// clang-format on + +#endif /* DDTRACE_EXPORT_H */ diff --git a/ext/ddtrace.h b/ext/ddtrace.h deleted file mode 100644 index ca47bc94e35..00000000000 --- a/ext/ddtrace.h +++ /dev/null @@ -1,243 +0,0 @@ -#ifndef DDTRACE_H -#define DDTRACE_H -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif -#include -#include -#include -#include -#include -#include - -#ifndef _WIN32 -#include -#endif - -#include "ext/version.h" -#include "compatibility.h" -#include "git.h" -#include "threads.h" - -extern zend_module_entry ddtrace_module_entry; -extern zend_class_entry *ddtrace_ce_span_data; -extern zend_class_entry *ddtrace_ce_inferred_span_data; -extern zend_class_entry *ddtrace_ce_root_span_data; -extern zend_class_entry *ddtrace_ce_span_stack; -extern zend_class_entry *ddtrace_ce_fatal_error; -extern zend_class_entry *ddtrace_ce_span_link; -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; - -typedef struct ddtrace_span_ids_t ddtrace_span_ids_t; -typedef struct ddtrace_span_data ddtrace_span_data; -typedef struct ddtrace_inferred_span_data ddtrace_inferred_span_data; -typedef struct ddtrace_root_span_data ddtrace_root_span_data; -typedef struct ddtrace_span_stack ddtrace_span_stack; -typedef struct ddtrace_span_link ddtrace_span_link; -typedef struct ddtrace_span_event ddtrace_span_event; -typedef struct ddtrace_exception_span_event ddtrace_exception_span_event; -typedef struct ddtrace_git_metadata ddtrace_git_metadata; - -typedef struct dd_refcounted_linked dd_refcounted_linked; - -typedef struct { - zend_arena *arena; - dd_refcounted_linked *ephemerals; -} dd_capture_arena; - -extern datadog_php_sapi ddtrace_active_sapi; - -extern ddog_CharSlice php_version_rt; - -static inline zend_array *ddtrace_property_array(zval *zv) { - ZVAL_DEREF(zv); - if (Z_TYPE_P(zv) != IS_ARRAY) { - zval garbage; - ZVAL_COPY_VALUE(&garbage, zv); - array_init(zv); - zval_ptr_dtor(&garbage); - } - SEPARATE_ARRAY(zv); - return Z_ARR_P(zv); -} - -#if defined(COMPILE_DL_DDTRACE) && defined(__GLIBC__) && __GLIBC_MINOR__ -#define CXA_THREAD_ATEXIT_WRAPPER 1 -#endif - -bool ddtrace_tracer_is_limited(void); -// prepare the tracer state to start handling a new trace -void dd_prepare_for_new_trace(void); -void ddtrace_disable_tracing_in_current_request(void); -bool ddtrace_alter_dd_trace_disabled_config(zval *old_value, zval *new_value, zend_string *new_str); -bool ddtrace_alter_sampling_rules_file_config(zval *old_value, zval *new_value, zend_string *new_str); -bool ddtrace_alter_default_propagation_style(zval *old_value, zval *new_value, zend_string *new_str); -bool ddtrace_alter_dd_service(zval *old_value, zval *new_value, zend_string *new_str); -bool ddtrace_alter_dd_env(zval *old_value, zval *new_value, zend_string *new_str); -bool ddtrace_alter_dd_version(zval *old_value, zval *new_value, zend_string *new_str); -void dd_force_shutdown_tracing(bool fast_shutdown); -void dd_internal_handle_fork(void); -#ifdef CXA_THREAD_ATEXIT_WRAPPER -void dd_run_rust_thread_destructors(void *unused); -#endif - -typedef struct { - int type; - zend_string *message; -} ddtrace_error_data; - -typedef struct { - uint64_t low; - union { - uint64_t high; - struct { - ZEND_ENDIAN_LOHI( - uint32_t padding // zeroes - , - uint32_t time - ) - }; - }; -} ddtrace_trace_id; - -// clang-format off -ZEND_BEGIN_MODULE_GLOBALS(ddtrace) - zend_bool api_is_loaded; - zend_bool otel_is_loaded; - zend_bool legacy_tracer_is_loaded; - - uint32_t traces_group_id; - zend_array *additional_global_tags; - zend_array root_span_tags_preset; - zend_array propagated_root_span_tags; - zend_string *tracestate; - zend_array tracestate_unknown_dd_keys; - zend_bool backtrace_handler_already_run; - ddtrace_error_data active_error; - HashTable baggage; -#ifndef _WIN32 - dogstatsd_client dogstatsd_client; -#endif - zend_bool in_shutdown; - -#if PHP_VERSION_ID < 70100 - bool zai_vm_interrupt; -#endif - bool reread_remote_configuration; - bool root_span_data_submitted; - - zend_long default_priority_sampling; - zend_long propagated_priority_sampling; - ddtrace_span_stack *active_stack; // never NULL except tracer is disabled - ddtrace_span_stack *top_closed_stack; - HashTable traced_spans; // tie a span to a specific active execute_data - uint32_t open_spans_count; - uint32_t baggage_extract_count; - uint32_t baggage_inject_count; - uint32_t baggage_malformed_count; - uint32_t baggage_max_item_count; - uint32_t baggage_max_byte_count; - uint32_t baggage_extract_max_item_count; - uint32_t baggage_extract_max_byte_count; - uint32_t closed_spans_count; - uint32_t dropped_spans_count; - int64_t compile_time_microseconds; - ddtrace_trace_id distributed_trace_id; - uint64_t distributed_parent_trace_id; - zend_string *dd_origin; - zend_reference *curl_multi_injecting_spans; - - char *cgroup_file; - ddog_SidecarTransport *sidecar; - ddog_QueueId sidecar_queue_id; - MUTEX_T sidecar_universal_service_tags_mutex; - ddog_AgentRemoteConfigReader *agent_config_reader; - ddog_RemoteConfigState *remote_config_state; - bool remote_config_writing; // true while RC WRITE mode INI update is in progress - ddog_AgentInfoReader *agent_info_reader; - dd_capture_arena debugger_capture_arena; - ddog_Vec_DebuggerPayload exception_debugger_buffer; - HashTable active_rc_hooks; - HashTable *agent_rate_by_service; - zend_string *last_service_name; - zend_string *last_env_name; - zend_string *last_version; - ddog_Vec_Tag active_global_tags; - - bool request_initialized; - HashTable telemetry_spans_created_per_integration; - ddog_SidecarActionsBuffer *telemetry_buffer; - ddog_SidecarActionsBuffer *metrics_buffer; - - bool asm_event_emitted; - -#if PHP_VERSION_ID >= 80000 - HashTable curl_headers; - // Multi-handle API: curl_multi_*() - HashTable curl_multi_handles; -#endif - - HashTable uhook_active_hooks; - HashTable uhook_closure_hooks; - - HashTable git_metadata; - zend_object *git_object; - - ddog_ShmCacheMap *telemetry_cache; - bool inferred_span_created; - - HashTable resource_weak_storage; - dtor_func_t resource_dtor_func; - - HashTable otel_config_telemetry; -ZEND_END_MODULE_GLOBALS(ddtrace) -// clang-format on - -#ifdef ZTS -# if defined(__has_attribute) && __has_attribute(tls_model) -# define ATTR_TLS_GLOBAL_DYNAMIC __attribute__((tls_model("global-dynamic"))) -# else -# define ATTR_TLS_GLOBAL_DYNAMIC -# endif -extern TSRM_TLS void *ATTR_TLS_GLOBAL_DYNAMIC TSRMLS_CACHE; -# define DDTRACE_G(v) ZEND_TSRMG(ddtrace_globals_id, zend_ddtrace_globals *, v) -# define DDTRACE_GLOBALS_PTR() TSRMG_BULK_STATIC(ddtrace_globals_id, zend_ddtrace_globals *) -#else -# define DDTRACE_G(v) (ddtrace_globals.v) -# define DDTRACE_GLOBALS_PTR() (&ddtrace_globals) -#endif - -#define PHP_DDTRACE_EXTNAME "ddtrace" -#ifndef PHP_DDTRACE_VERSION -#define PHP_DDTRACE_VERSION "0.0.0-unknown" -#endif - -#define DDTRACE_CALLBACK_NAME "dd_trace_callback" - -/* The clang formatter does not handle the ZEND macros these mirror, due to the - * missing comma in the usage site. It was making PRs unreviewable, so this - * defines these macros without the comma in the definition site, so that it - * exists at the usage site. - */ -#define DDTRACE_ARG_INFO_SIZE(arg_info) ((uint32_t)(sizeof(arg_info) / sizeof(struct _zend_internal_arg_info) - 1)) - -#define DDTRACE_FENTRY(zend_name, name, arg_info, flags) \ - { #zend_name, name, arg_info, DDTRACE_ARG_INFO_SIZE(arg_info), flags } -#define DDTRACE_RAW_FENTRY(zend_name, name, arg_info, flags) \ - { zend_name, name, arg_info, DDTRACE_ARG_INFO_SIZE(arg_info), flags } - -#define DDTRACE_FE(name, arg_info) DDTRACE_FENTRY(name, zif_##name, arg_info, 0) -#define DDTRACE_NS_FE(name, arg_info) DDTRACE_RAW_FENTRY("DDTrace\\" #name, zif_##name, arg_info, 0) -#define DDTRACE_SUB_NS_FE(ns, name, arg_info) DDTRACE_RAW_FENTRY("DDTrace\\" ns #name, zif_##name, arg_info, 0) -#define DDTRACE_FALIAS(name, alias, arg_info) DDTRACE_RAW_FENTRY(#name, zif_##alias, arg_info, 0) -#define DDTRACE_FE_END ZEND_FE_END - -#include "random.h" - -#define HOST_V6_FORMAT_STR "http://[%s]:%u" -#define HOST_V4_FORMAT_STR "http://%s:%u" - -#endif // DDTRACE_H diff --git a/ext/ddtrace_export.h b/ext/ddtrace_export.h deleted file mode 100644 index 67df58a643d..00000000000 --- a/ext/ddtrace_export.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef DDTRACE_EXPORT_H -#define DDTRACE_EXPORT_H - -// clang-format off -/* Define DDTRACE_STATIC before including this header to avoid exporting the - * functions, which usually is what is desired when building a static lib, - * hence the name. - */ -#ifdef DDTRACE_STATIC -# define DDTRACE_PUBLIC -#else -# ifndef DDTRACE_PUBLIC -# ifndef _WIN32 -# define DDTRACE_PUBLIC __attribute__((visibility("default"))) -# else -# define DDTRACE_PUBLIC __declspec(dllexport) -# endif -# endif -#endif - -#ifndef DDTRACE_DEPRECATED -# define DDTRACE_DEPRECATED __attribute__ ((__deprecated__)) -#endif -// clang-format on - -#endif /* DDTRACE_EXPORT_H */ diff --git a/ext/ddtrace_string.h b/ext/ddtrace_string.h deleted file mode 100644 index 74f037a5e90..00000000000 --- a/ext/ddtrace_string.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef DDTRACE_STRING_H -#define DDTRACE_STRING_H - -#include -#include -#include -#include -#include - -typedef size_t ddtrace_zppstrlen_t; - -struct ddtrace_string { - char *ptr; - ddtrace_zppstrlen_t len; -}; -typedef struct ddtrace_string ddtrace_string; - -#define DDTRACE_STRING_LITERAL(str) \ - (ddtrace_string) { .ptr = str, .len = sizeof(str) - 1 } - -#define DDTRACE_STRING_ZVAL_L(zval_ptr, str) ZVAL_STRINGL(zval_ptr, str.ptr, str.len) - -static inline ddtrace_string ddtrace_string_cstring_ctor(char *ptr) { - ddtrace_string string = { - .ptr = ptr, - .len = ptr ? strlen(ptr) : 0, - }; - return string; -} - -static inline zend_string *ddtrace_zend_string_init(ddog_CharSlice str) { - return zend_string_init(str.ptr, str.len, 0); -} - -#endif // DDTRACE_STRING_H diff --git a/ext/dogstatsd.c b/ext/dogstatsd.c deleted file mode 100644 index 5a009039263..00000000000 --- a/ext/dogstatsd.c +++ /dev/null @@ -1,52 +0,0 @@ -#include "dogstatsd.h" - -#include "configuration.h" -#include "ddtrace.h" - -ZEND_EXTERN_MODULE_GLOBALS(ddtrace); - -#define DEFAULT_UDS_PATH "/var/run/datadog/dsd.socket" - -char *ddtrace_dogstatsd_url(void) { - zend_string *url = get_DD_DOGSTATSD_URL(); - if (ZSTR_LEN(url) > 0 && zai_config_memoized_entries[DDTRACE_CONFIG_DD_DOGSTATSD_URL].name_index != ZAI_CONFIG_ORIGIN_DEFAULT) { - return zend_strndup(ZSTR_VAL(url), ZSTR_LEN(url) + 1); - } - - zend_string *hostname = get_DD_DOGSTATSD_HOST(); - if (ZSTR_LEN(hostname) == 0 || zai_config_memoized_entries[DDTRACE_CONFIG_DD_DOGSTATSD_HOST].name_index == ZAI_CONFIG_ORIGIN_DEFAULT) { - if (zai_config_memoized_entries[DDTRACE_CONFIG_DD_AGENT_HOST].name_index == ZAI_CONFIG_ORIGIN_DEFAULT) { - hostname = ZSTR_EMPTY_ALLOC(); - } else { - hostname = get_global_DD_AGENT_HOST(); - } - } - - if (ZSTR_LEN(hostname) > 7 && strncmp(ZSTR_VAL(hostname), "unix://", 7) == 0) { - return zend_strndup(ZSTR_VAL(hostname), ZSTR_LEN(hostname)); - } - - if (ZSTR_LEN(hostname) > 0) { - bool isIPv6 = memchr(ZSTR_VAL(hostname), ':', ZSTR_LEN(hostname)); - - int port = get_DD_DOGSTATSD_PORT(); - if (port <= 0 || port > 65535) { - port = 8125; - } - char *formatted_url; - asprintf(&formatted_url, isIPv6 ? HOST_V6_FORMAT_STR : HOST_V4_FORMAT_STR, ZSTR_VAL(hostname), (uint32_t)port); - return formatted_url; - } - - if (access(DEFAULT_UDS_PATH, F_OK) == SUCCESS) { - return zend_strndup(ZEND_STRL("unix://" DEFAULT_UDS_PATH)); - } - - int64_t port = get_global_DD_TRACE_AGENT_PORT(); - if (port <= 0 || port > 65535 || zai_config_memoized_entries[DDTRACE_CONFIG_DD_TRACE_AGENT_PORT].name_index == ZAI_CONFIG_ORIGIN_DEFAULT) { - port = 8125; - } - char *formatted_url; - asprintf(&formatted_url, HOST_V4_FORMAT_STR, "localhost", (uint32_t)port); - return formatted_url; -} diff --git a/ext/dogstatsd.h b/ext/dogstatsd.h deleted file mode 100644 index 2e310d67ed7..00000000000 --- a/ext/dogstatsd.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef DDTRACE_DOGSTATSD_H -#define DDTRACE_DOGSTATSD_H - -char *ddtrace_dogstatsd_url(void); - -#endif // DDTRACE_DOGSTATSD_H diff --git a/ext/endpoints.c b/ext/endpoints.c new file mode 100644 index 00000000000..ce046036fd3 --- /dev/null +++ b/ext/endpoints.c @@ -0,0 +1,103 @@ +#include "endpoints.h" +#include "configuration.h" +#include "datadog.h" + +ZEND_EXTERN_MODULE_GLOBALS(datadog); + +#define DEFAULT_DOGSTATSD_UDS_PATH "/var/run/datadog/dsd.socket" +#define DEFAULT_AGENT_UDS_PATH "/var/run/datadog/apm.socket" + +#define HOST_V6_FORMAT_STR "http://[%s]:%u" +#define HOST_V4_FORMAT_STR "http://%s:%u" + +char *datadog_agent_url(void) { + zend_string *url = get_global_DD_TRACE_AGENT_URL(); + if (ZSTR_LEN(url) > 0) { + char *dup = zend_strndup(ZSTR_VAL(url), ZSTR_LEN(url) + 1); + + // mess around with backslashes to support our test cases providing something like "file://C:\dir\test.out" + const char *fileprefix = "file://"; + if (strncmp(ZSTR_VAL(url), fileprefix, strlen(fileprefix)) == 0 && strchr(ZSTR_VAL(url), '\\')) { + for (size_t i = strlen(fileprefix); i < ZSTR_LEN(url); ++i) { + if (dup[i] == '\\') { + dup[i] = '/'; + } + } + } + + return dup; + } + + zend_string *hostname = get_global_DD_AGENT_HOST(); + if (ZSTR_LEN(hostname) > 7 && strncmp(ZSTR_VAL(hostname), "unix://", 7) == 0) { + return zend_strndup(ZSTR_VAL(hostname), ZSTR_LEN(hostname)); + } + + if (ZSTR_LEN(hostname) > 0 && zai_config_memoized_entries[DATADOG_CONFIG_DD_AGENT_HOST].name_index != ZAI_CONFIG_ORIGIN_DEFAULT) { + bool isIPv6 = memchr(ZSTR_VAL(hostname), ':', ZSTR_LEN(hostname)); + + int64_t port = get_global_DD_TRACE_AGENT_PORT(); + if (port <= 0 || port > 65535) { + port = 8126; + } + char *formatted_url; + asprintf(&formatted_url, isIPv6 ? HOST_V6_FORMAT_STR : HOST_V4_FORMAT_STR, ZSTR_VAL(hostname), (uint32_t)port); + return formatted_url; + } + + if (access(DEFAULT_AGENT_UDS_PATH, F_OK) == SUCCESS) { + return zend_strndup(ZEND_STRL("unix://" DEFAULT_AGENT_UDS_PATH)); + } + + int64_t port = get_global_DD_TRACE_AGENT_PORT(); + if (port <= 0 || port > 65535) { + port = 8126; + } + char *formatted_url; + asprintf(&formatted_url, HOST_V4_FORMAT_STR, "localhost", (uint32_t)port); + return formatted_url; +} + +char *datadog_dogstatsd_url(void) { + zend_string *url = get_DD_DOGSTATSD_URL(); + if (ZSTR_LEN(url) > 0 && zai_config_memoized_entries[DATADOG_CONFIG_DD_DOGSTATSD_URL].name_index != ZAI_CONFIG_ORIGIN_DEFAULT) { + return zend_strndup(ZSTR_VAL(url), ZSTR_LEN(url) + 1); + } + + zend_string *hostname = get_DD_DOGSTATSD_HOST(); + if (ZSTR_LEN(hostname) == 0 || zai_config_memoized_entries[DATADOG_CONFIG_DD_DOGSTATSD_HOST].name_index == ZAI_CONFIG_ORIGIN_DEFAULT) { + if (zai_config_memoized_entries[DATADOG_CONFIG_DD_AGENT_HOST].name_index == ZAI_CONFIG_ORIGIN_DEFAULT) { + hostname = ZSTR_EMPTY_ALLOC(); + } else { + hostname = get_global_DD_AGENT_HOST(); + } + } + + if (ZSTR_LEN(hostname) > 7 && strncmp(ZSTR_VAL(hostname), "unix://", 7) == 0) { + return zend_strndup(ZSTR_VAL(hostname), ZSTR_LEN(hostname)); + } + + if (ZSTR_LEN(hostname) > 0) { + bool isIPv6 = memchr(ZSTR_VAL(hostname), ':', ZSTR_LEN(hostname)); + + int port = get_DD_DOGSTATSD_PORT(); + if (port <= 0 || port > 65535) { + port = 8125; + } + char *formatted_url; + asprintf(&formatted_url, isIPv6 ? HOST_V6_FORMAT_STR : HOST_V4_FORMAT_STR, ZSTR_VAL(hostname), (uint32_t)port); + return formatted_url; + } + + if (access(DEFAULT_DOGSTATSD_UDS_PATH, F_OK) == SUCCESS) { + return zend_strndup(ZEND_STRL("unix://" DEFAULT_DOGSTATSD_UDS_PATH)); + } + + int64_t port = get_global_DD_TRACE_AGENT_PORT(); + if (port <= 0 || port > 65535 || zai_config_memoized_entries[DATADOG_CONFIG_DD_TRACE_AGENT_PORT].name_index == ZAI_CONFIG_ORIGIN_DEFAULT) { + port = 8125; + } + char *formatted_url; + asprintf(&formatted_url, HOST_V4_FORMAT_STR, "localhost", (uint32_t)port); + return formatted_url; +} diff --git a/ext/endpoints.h b/ext/endpoints.h new file mode 100644 index 00000000000..17ae3976ae0 --- /dev/null +++ b/ext/endpoints.h @@ -0,0 +1,7 @@ +#ifndef DATADOG_ENDPOINTS_H +#define DATADOG_ENDPOINTS_H + +char *datadog_agent_url(void); +char *datadog_dogstatsd_url(void); + +#endif // DATADOG_ENDPOINTS_H diff --git a/ext/excluded_modules.c b/ext/excluded_modules.c index 4bad02a8041..3384dcbbc9d 100644 --- a/ext/excluded_modules.c +++ b/ext/excluded_modules.c @@ -8,10 +8,10 @@ #include #include "configuration.h" -bool ddtrace_is_excluded_module(zend_module_entry *module, char *error) { +bool datadog_is_excluded_module(zend_module_entry *module, char *error) { #if PHP_VERSION_ID >= 80000 if (strcmp("ionCube Loader", module->name) == 0) { - snprintf(error, DDTRACE_EXCLUDED_MODULES_ERROR_MAX_LEN, + snprintf(error, DATADOG_EXCLUDED_MODULES_ERROR_MAX_LEN, "Found incompatible ionCube Loader extension"); return true; } @@ -23,7 +23,7 @@ bool ddtrace_is_excluded_module(zend_module_entry *module, char *error) { @see: https://xdebug.org/docs/compat */ #if PHP_VERSION_ID < 70100 - snprintf(error, DDTRACE_EXCLUDED_MODULES_ERROR_MAX_LEN, + snprintf(error, DATADOG_EXCLUDED_MODULES_ERROR_MAX_LEN, "Found incompatible Xdebug version %s", module->version); return true; #endif @@ -45,7 +45,7 @@ bool ddtrace_is_excluded_module(zend_module_entry *module, char *error) { */ int compare = php_version_compare(module->version, "2.9.5"); if (compare == -1) { - snprintf(error, DDTRACE_EXCLUDED_MODULES_ERROR_MAX_LEN, + snprintf(error, DATADOG_EXCLUDED_MODULES_ERROR_MAX_LEN, "Found incompatible Xdebug version %s; ddtrace requires Xdebug 2.9.5 or greater", module->version); return true; @@ -54,16 +54,16 @@ bool ddtrace_is_excluded_module(zend_module_entry *module, char *error) { return false; } -void ddtrace_excluded_modules_startup() { +void datadog_excluded_modules_startup() { zend_module_entry *module; - ddtrace_has_excluded_module = false; + datadog_has_excluded_module = false; bool inject_force = get_global_DD_INJECT_FORCE(); ZEND_HASH_FOREACH_PTR(&module_registry, module) { - char error[DDTRACE_EXCLUDED_MODULES_ERROR_MAX_LEN + 1]; - if (module && module->name && module->version && ddtrace_is_excluded_module(module, error)) { - ddtrace_has_excluded_module = true; + char error[DATADOG_EXCLUDED_MODULES_ERROR_MAX_LEN + 1]; + if (module && module->name && module->version && datadog_is_excluded_module(module, error)) { + datadog_has_excluded_module = true; if (inject_force) { LOG(WARN, error); } else { @@ -73,10 +73,10 @@ void ddtrace_excluded_modules_startup() { } ZEND_HASH_FOREACH_END(); - if (ddtrace_has_excluded_module) { + if (datadog_has_excluded_module) { if (inject_force) { LOG(WARN, "Found incompatible extension(s); ignoring since 'datadog.inject_force' is enabled"); - ddtrace_has_excluded_module = false; + datadog_has_excluded_module = false; } else { LOG(ERROR, "Found incompatible extension(s); disabling conflicting functionality"); } diff --git a/ext/excluded_modules.h b/ext/excluded_modules.h index 083956fd3e1..68b3d3be74b 100644 --- a/ext/excluded_modules.h +++ b/ext/excluded_modules.h @@ -1,14 +1,14 @@ -#ifndef DDTRACE_EXCLUDED_MODULES_H -#define DDTRACE_EXCLUDED_MODULES_H +#ifndef DATADOG_EXCLUDED_MODULES_H +#define DATADOG_EXCLUDED_MODULES_H #include #include -#define DDTRACE_EXCLUDED_MODULES_ERROR_MAX_LEN 255 +#define DATADOG_EXCLUDED_MODULES_ERROR_MAX_LEN 255 -extern bool ddtrace_has_excluded_module; +extern bool datadog_has_excluded_module; -void ddtrace_excluded_modules_startup(); -bool ddtrace_is_excluded_module(zend_module_entry *module, char *error); +void datadog_excluded_modules_startup(); +bool datadog_is_excluded_module(zend_module_entry *module, char *error); #endif // DDTRACE_EXCLUDED_MODULES_H diff --git a/ext/ffi_utils.h b/ext/ffi_utils.h new file mode 100644 index 00000000000..5ee2c166e76 --- /dev/null +++ b/ext/ffi_utils.h @@ -0,0 +1,27 @@ +#include +#include + +static inline ddog_CharSlice dd_zend_string_to_CharSlice(zend_string *str) { + if (str == NULL) { + return (ddog_CharSlice){ .len = 0, .ptr = NULL }; + } + return (ddog_CharSlice){ .len = str->len, .ptr = str->val }; +} + +static inline ddog_CharSlice dd_zai_string_to_CharSlice(zai_string str) { + return (ddog_CharSlice){ .len = str.len, .ptr = str.ptr }; +} + +static inline zend_string *dd_CharSlice_to_zend_string(ddog_CharSlice slice) { + return zend_string_init(slice.ptr, slice.len, 0); +} + +static inline bool datadog_ffi_try(const char *msg, ddog_MaybeError maybe_error) { + if (maybe_error.tag == DDOG_OPTION_ERROR_SOME_ERROR) { + ddog_CharSlice error = ddog_Error_message(&maybe_error.some); + LOG(ERROR, "%s: %.*s", msg, (int) error.len, error.ptr); + ddog_MaybeError_drop(maybe_error); + return false; + } + return true; +} diff --git a/ext/git.c b/ext/git.c index 0bdd5b5aeed..37766734a3f 100644 --- a/ext/git.c +++ b/ext/git.c @@ -1,6 +1,6 @@ #include "git.h" #include "configuration.h" -#include "ddtrace.h" +#include "datadog.h" #include #include @@ -9,7 +9,7 @@ #define getcwd _getcwd #endif -ZEND_EXTERN_MODULE_GLOBALS(ddtrace); +ZEND_EXTERN_MODULE_GLOBALS(datadog); #ifndef PATH_MAX #define PATH_MAX 4096 @@ -20,8 +20,6 @@ typedef struct _git_metadata { zend_string *property_repository; } git_metadata_t; -ddtrace_git_metadata empty_git_object = { 0 }; - int remove_trailing_newline(char *str) { size_t len = strlen(str); while (len > 0 && (str[len - 1] == '\n' || str[len - 1] == '\r')) { @@ -165,34 +163,6 @@ zend_string* remove_credentials(zend_string *repo_url) { return zend_string_copy(repo_url); } -bool add_git_info(zend_string *commit_sha, zend_string *repository_url) { - size_t commit_sha_len = commit_sha ? ZSTR_LEN(commit_sha) : 0; - size_t repository_url_len = repository_url ? ZSTR_LEN(repository_url) : 0; - - if (commit_sha_len == 0 && repository_url_len == 0) { - return false; - } - - zval git_obj; - object_init_ex(&git_obj, ddtrace_ce_git_metadata); - ddtrace_git_metadata *git_metadata = (ddtrace_git_metadata *) Z_OBJ(git_obj); - DDTRACE_G(git_object) = &git_metadata->std; - - if (commit_sha_len != 0) { - ZVAL_STR_COPY(&git_metadata->property_commit, commit_sha); - } else { - ZVAL_NULL(&git_metadata->property_commit); - } - - if (repository_url_len != 0) { - ZVAL_STR(&git_metadata->property_repository, remove_credentials(repository_url)); - } else { - ZVAL_NULL(&git_metadata->property_repository); - } - - return true; -} - zend_string* get_directory_from_path_translated() { const char *path_translated = SG(request_info).path_translated; if (path_translated) { @@ -240,22 +210,7 @@ void cache_git_metadata(zend_string *cwd, zend_string *commit_sha, zend_string * git_metadata_t *git_metadata = pemalloc(sizeof(git_metadata_t), 1); git_metadata->property_commit = commit_sha && ZSTR_LEN(commit_sha) > 0 ? zend_string_copy(commit_sha) : NULL; git_metadata->property_repository = repository_url && ZSTR_LEN(repository_url) > 0 ? zend_string_copy(repository_url) : NULL; - zend_hash_update_ptr(&DDTRACE_G(git_metadata), cwd, git_metadata); -} - -bool process_git_info(zend_string *git_dir, zend_string *cwd) { - zend_string *commit_sha = get_commit_sha(ZSTR_VAL(git_dir)); - zend_string *repository_url = get_repository_url(ZSTR_VAL(git_dir)); - - bool success = add_git_info(commit_sha, repository_url); - if (success) { - cache_git_metadata(cwd, commit_sha, repository_url); - } - - if (commit_sha) zend_string_release(commit_sha); - if (repository_url) zend_string_release(repository_url); - - return success; + zend_hash_update_ptr(&DATADOG_G(git_metadata), cwd, git_metadata); } void replace_git_metadata(git_metadata_t *git_metadata, zend_string *commit_sha, zend_string *repository_url) { @@ -273,7 +228,7 @@ void refresh_git_metadata_if_needed(zend_string *cwd, git_metadata_t *git_metada zend_string *git_dir = find_git_dir(ZSTR_VAL(cwd)); if (!git_dir) { // Git directory no longer exists - invalidate cached entry - zend_hash_del(&DDTRACE_G(git_metadata), cwd); + zend_hash_del(&DATADOG_G(git_metadata), cwd); return; } zend_string *commit_sha = get_commit_sha(ZSTR_VAL(git_dir)); @@ -290,7 +245,7 @@ void refresh_git_metadata_if_needed(zend_string *cwd, git_metadata_t *git_metada replace_git_metadata(git_metadata, commit_sha, repository_url); } else if (git_metadata->property_commit) { // If we previously had a commit SHA but now can't read it, the git folder became invalid - zend_hash_del(&DDTRACE_G(git_metadata), cwd); + zend_hash_del(&DATADOG_G(git_metadata), cwd); } zend_string_release(git_dir); @@ -299,83 +254,113 @@ void refresh_git_metadata_if_needed(zend_string *cwd, git_metadata_t *git_metada void update_git_metadata(void) { zend_string *cwd; git_metadata_t *git_metadata; - ZEND_HASH_FOREACH_STR_KEY_PTR(&DDTRACE_G(git_metadata), cwd, git_metadata) { + ZEND_HASH_FOREACH_STR_KEY_PTR(&DATADOG_G(git_metadata), cwd, git_metadata) { refresh_git_metadata_if_needed(cwd, git_metadata); } ZEND_HASH_FOREACH_END(); } -bool inject_from_env() { - zend_string *commit_sha = get_DD_GIT_COMMIT_SHA(); - zend_string *repository_url = get_DD_GIT_REPOSITORY_URL(); - return add_git_info(commit_sha, repository_url); +void datadog_git_metadata_dtor(zval *val) { + git_metadata_t *git_metadata = Z_PTR_P(val); + if (git_metadata->property_commit) zend_string_release(git_metadata->property_commit); + if (git_metadata->property_repository) zend_string_release(git_metadata->property_repository); + pefree(git_metadata, 1); } -bool inject_from_global_tags() { - bool success = false; - zend_array *global_tags = get_DD_TAGS(); - zval *commit_sha = zend_hash_str_find(global_tags, ZEND_STRL("git.commit.sha")); - zval *repository_url = zend_hash_str_find(global_tags, ZEND_STRL("git.repository_url")); - if (commit_sha && repository_url && Z_TYPE_P(commit_sha) == IS_STRING && Z_TYPE_P(repository_url) == IS_STRING) { - success = add_git_info(Z_STR_P(commit_sha), Z_STR_P(repository_url)); +bool datadog_get_git_metadata(zend_string **out_commit, zend_string **out_repo) { + if (DATADOG_G(git_resolved)) { + *out_commit = DATADOG_G(git_commit); + *out_repo = DATADOG_G(git_repository_url); + return *out_commit != NULL || *out_repo != NULL; } - return success; -} -bool inject_from_git_dir() { - zend_string *cwd = get_current_working_directory(); - if (!cwd) return false; + DATADOG_G(git_resolved) = true; - update_git_metadata(); + zend_string *commit = NULL, *repo = NULL; - git_metadata_t *git_metadata = zend_hash_find_ptr(&DDTRACE_G(git_metadata), cwd); - if (git_metadata) { - add_git_info(git_metadata->property_commit, git_metadata->property_repository); - zend_string_release(cwd); - return true; + // From env vars + { + zend_string *env_commit = get_DD_GIT_COMMIT_SHA(); + zend_string *env_repo = get_DD_GIT_REPOSITORY_URL(); + if (ZSTR_LEN(env_commit) > 0 || ZSTR_LEN(env_repo) > 0) { + if (ZSTR_LEN(env_commit) > 0) { + commit = zend_string_copy(env_commit); + } + if (ZSTR_LEN(env_repo) > 0) { + repo = remove_credentials(env_repo); + } + goto cache; + } } - zend_string *git_dir = find_git_dir(ZSTR_VAL(cwd)); - if (!git_dir) { - zend_string_release(cwd); - return false; + // From global tags + { + zend_array *global_tags = get_DD_TAGS(); + zval *commit_zv = zend_hash_str_find(global_tags, ZEND_STRL("git.commit.sha")); + zval *repo_zv = zend_hash_str_find(global_tags, ZEND_STRL("git.repository_url")); + if (commit_zv && repo_zv && Z_TYPE_P(commit_zv) == IS_STRING && Z_TYPE_P(repo_zv) == IS_STRING) { + commit = zend_string_copy(Z_STR_P(commit_zv)); + repo = remove_credentials(Z_STR_P(repo_zv)); + goto cache; + } } - bool success = process_git_info(git_dir, cwd); - - zend_string_release(git_dir); - zend_string_release(cwd); - - return success; -} - -void ddtrace_inject_git_metadata(zval *carrier) { - if (DDTRACE_G(git_object) == &empty_git_object.std) { - return; - } + // From git directory + { + zend_string *cwd = get_current_working_directory(); + if (cwd) { + update_git_metadata(); - if (DDTRACE_G(git_object) || inject_from_env() || inject_from_global_tags() || inject_from_git_dir()) { - ZVAL_OBJ_COPY(carrier, DDTRACE_G(git_object)); - } else { - DDTRACE_G(git_object) = &empty_git_object.std; + git_metadata_t *meta = zend_hash_find_ptr(&DATADOG_G(git_metadata), cwd); + if (meta) { + if (meta->property_commit) { + commit = zend_string_copy(meta->property_commit); + } + if (meta->property_repository) { + repo = remove_credentials(meta->property_repository); + } + zend_string_release(cwd); + } else { + zend_string *git_dir = find_git_dir(ZSTR_VAL(cwd)); + if (git_dir) { + zend_string *raw_commit = get_commit_sha(ZSTR_VAL(git_dir)); + zend_string *raw_repo = get_repository_url(ZSTR_VAL(git_dir)); + + if ((raw_commit && ZSTR_LEN(raw_commit) > 0) || (raw_repo && ZSTR_LEN(raw_repo) > 0)) { + if (raw_commit && ZSTR_LEN(raw_commit) > 0) { + commit = zend_string_copy(raw_commit); + } + if (raw_repo && ZSTR_LEN(raw_repo) > 0) { + repo = remove_credentials(raw_repo); + } + cache_git_metadata(cwd, raw_commit, raw_repo); + } + + if (raw_commit) zend_string_release(raw_commit); + if (raw_repo) zend_string_release(raw_repo); + zend_string_release(git_dir); + } + zend_string_release(cwd); + } + } } -} -void ddtrace_git_metadata_dtor(zval *val) { - git_metadata_t *git_metadata = (git_metadata_t *) Z_PTR_P(val); - if (git_metadata->property_commit) zend_string_release(git_metadata->property_commit); - if (git_metadata->property_repository) zend_string_release(git_metadata->property_repository); - pefree(git_metadata, 1); +cache: + DATADOG_G(git_commit) = commit; + DATADOG_G(git_repository_url) = repo; + *out_commit = commit; + *out_repo = repo; + return commit != NULL || repo != NULL; } -void ddtrace_clean_git_object(void) { - if (DDTRACE_G(git_object) == &empty_git_object.std) { - DDTRACE_G(git_object) = NULL; - return; +void datadog_git_rshutdown(void) { + if (DATADOG_G(git_commit)) { + zend_string_release(DATADOG_G(git_commit)); + DATADOG_G(git_commit) = NULL; } - - if (DDTRACE_G(git_object)) { - zend_object_release(DDTRACE_G(git_object)); - DDTRACE_G(git_object) = NULL; + if (DATADOG_G(git_repository_url)) { + zend_string_release(DATADOG_G(git_repository_url)); + DATADOG_G(git_repository_url) = NULL; } + DATADOG_G(git_resolved) = false; } diff --git a/ext/git.h b/ext/git.h index f1febd284f5..38fd6915f1d 100644 --- a/ext/git.h +++ b/ext/git.h @@ -1,10 +1,13 @@ -#ifndef DD_GIT_H -#define DD_GIT_H +#ifndef DATADOG_GIT_H +#define DATADOG_GIT_H #include #include -void ddtrace_inject_git_metadata(zval *git_metadata_zv); -void ddtrace_git_metadata_dtor(zval *val); -void ddtrace_clean_git_object(void); +// Returns git strings for the current request, caching on first call. +// Output strings are borrowed (owned by DATADOG_G, caller must not release). +// Returns true if at least one string is non-NULL. +bool datadog_get_git_metadata(zend_string **out_commit, zend_string **out_repo); +void datadog_git_rshutdown(void); +void datadog_git_metadata_dtor(zval *val); -#endif // DD_GIT_H \ No newline at end of file +#endif // DATADOG_GIT_H \ No newline at end of file diff --git a/ext/handlers_api.h b/ext/handlers_api.h index 4012569dd43..25f1004bac4 100644 --- a/ext/handlers_api.h +++ b/ext/handlers_api.h @@ -1,5 +1,5 @@ -#ifndef DDTRACE_HANDLERS_API_H -#define DDTRACE_HANDLERS_API_H +#ifndef DATADOG_HANDLERS_API_H +#define DATADOG_HANDLERS_API_H // This api is used by both the tracer and profiler. diff --git a/ext/handlers_pcntl.c b/ext/handlers_pcntl.c index acff140cfe4..2b643aa5979 100644 --- a/ext/handlers_pcntl.c +++ b/ext/handlers_pcntl.c @@ -1,19 +1,17 @@ #include #include -#include - #ifndef _WIN32 -#include "coms.h" +#include #endif -#include "ddtrace.h" -#include "span.h" -#include "configuration.h" -#include "random.h" -#include "sidecar.h" -#include "handlers_internal.h" // For 'ddtrace_replace_internal_function' +#include +#include +#include +#include +#include +#include -ZEND_EXTERN_MODULE_GLOBALS(ddtrace); +ZEND_EXTERN_MODULE_GLOBALS(datadog); static zif_handler dd_pcntl_fork_handler = NULL; #if PHP_VERSION_ID >= 80100 @@ -23,38 +21,31 @@ static zif_handler dd_pcntl_rfork_handler = NULL; static zif_handler dd_pcntl_forkx_handler = NULL; #endif -#if defined(__SANITIZE_ADDRESS__) && !defined(_WIN32) -#define JOIN_BGS_BEFORE_FORK 1 -#endif static void dd_prefork() { -#if JOIN_BGS_BEFORE_FORK - if (!get_global_DD_TRACE_SIDECAR_TRACE_SENDER()) { - ddtrace_coms_flush_shutdown_writer_synchronous(); - } +#ifdef DDTRACE + ddtrace_internal_handle_prefork(); #endif } static void dd_handle_fork(zval *return_value) { if (Z_LVAL_P(return_value) == 0) { - dd_internal_handle_fork(); + datadog_internal_handle_fork(); } else { -#if JOIN_BGS_BEFORE_FORK - if (!get_global_DD_TRACE_SIDECAR_TRACE_SENDER()) { - ddtrace_coms_restart_writer(); - } +#ifdef DDTRACE + ddtrace_internal_handle_postfork(); #endif } } -ZEND_FUNCTION(ddtrace_pcntl_fork) { +ZEND_FUNCTION(datadog_pcntl_fork) { dd_prefork(); dd_pcntl_fork_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU); dd_handle_fork(return_value); } #if PHP_VERSION_ID >= 80100 -ZEND_FUNCTION(ddtrace_pcntl_rfork) { +ZEND_FUNCTION(datadog_pcntl_rfork) { dd_prefork(); dd_pcntl_rfork_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU); dd_handle_fork(return_value); @@ -62,7 +53,7 @@ ZEND_FUNCTION(ddtrace_pcntl_rfork) { #endif #if PHP_VERSION_ID >= 80200 -ZEND_FUNCTION(ddtrace_pcntl_forkx) { +ZEND_FUNCTION(datadog_pcntl_forkx) { dd_prefork(); dd_pcntl_forkx_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU); dd_handle_fork(return_value); @@ -78,7 +69,7 @@ ZEND_FUNCTION(ddtrace_pcntl_forkx) { * * @see http://www.phpinternalsbook.com/php7/memory_management/zend_memory_manager.html#common-errors-and-mistakes */ -void ddtrace_pcntl_handlers_startup(void) { +void datadog_pcntl_handlers_startup(void) { // if we cannot find ext/pcntl then do not instrument it zend_string *pcntl = zend_string_init(ZEND_STRL("pcntl"), 1); bool pcntl_loaded = zend_hash_exists(&module_registry, pcntl); @@ -88,12 +79,12 @@ void ddtrace_pcntl_handlers_startup(void) { } datadog_php_zif_handler handlers[] = { - {ZEND_STRL("pcntl_fork"), &dd_pcntl_fork_handler, ZEND_FN(ddtrace_pcntl_fork)}, + {ZEND_STRL("pcntl_fork"), &dd_pcntl_fork_handler, ZEND_FN(datadog_pcntl_fork)}, #if PHP_VERSION_ID >= 80100 - {ZEND_STRL("pcntl_rfork"), &dd_pcntl_rfork_handler, ZEND_FN(ddtrace_pcntl_rfork)}, + {ZEND_STRL("pcntl_rfork"), &dd_pcntl_rfork_handler, ZEND_FN(datadog_pcntl_rfork)}, #endif #if PHP_VERSION_ID >= 80200 - {ZEND_STRL("pcntl_forkx"), &dd_pcntl_forkx_handler, ZEND_FN(ddtrace_pcntl_forkx)}, + {ZEND_STRL("pcntl_forkx"), &dd_pcntl_forkx_handler, ZEND_FN(datadog_pcntl_forkx)}, #endif }; size_t handlers_len = sizeof handlers / sizeof handlers[0]; diff --git a/ext/handlers_signal.c b/ext/handlers_signal.c index 092d899f8e6..f32af38e219 100644 --- a/ext/handlers_signal.c +++ b/ext/handlers_signal.c @@ -34,7 +34,7 @@ static void dd_handle_signal(zif_handler original_function, INTERNAL_FUNCTION_PA sigprocmask(SIG_UNBLOCK, &x, NULL); // ensures no double-processing when the signal was delivered normally. if (REMOTE_CONFIG_NEEDS_POLLING_AFTER_SIGNAL) { - ddtrace_check_for_new_config_now(); + datadog_check_for_new_config_now(); } } @@ -110,7 +110,7 @@ BLOCK(BLOCKSIGFN) BLOCKMETH(BLOCKSIGMETH) -void ddtrace_signal_block_handlers_startup() { +void datadog_signal_block_handlers_startup() { #define BLOCKFNENTRY(function) { ZEND_STRL(#function), &dd_handle_signal_zif_##function, ZEND_FN(dd_handle_signal_##function) }, datadog_php_zif_handler handlers[] = { BLOCK(BLOCKFNENTRY) }; diff --git a/ext/logging.c b/ext/logging.c index c0e2f9fb717..216e666df13 100644 --- a/ext/logging.c +++ b/ext/logging.c @@ -1,12 +1,13 @@ #include "logging.h" -#include "sidecar.h" #include #include #include #include +#include "ffi_utils.h" #include "configuration.h" +#include #include
#ifndef _WIN32 @@ -24,7 +25,7 @@ static void dd_log_set_level(bool debug) { } } else if (runtime_config_first_init) { ddog_set_log_level(dd_zend_string_to_CharSlice(get_DD_TRACE_LOG_LEVEL()), once); - } else if (zend_string_equals_literal_ci(Z_STR(zai_config_memoized_entries[DDTRACE_CONFIG_DD_TRACE_LOG_LEVEL].decoded_value), "error")) { + } else if (zend_string_equals_literal_ci(Z_STR(zai_config_memoized_entries[DATADOG_CONFIG_DD_TRACE_LOG_LEVEL].decoded_value), "error")) { ddog_set_error_log_level(once); // optimized handling without parsing } else { ddog_set_log_level(dd_zend_string_to_CharSlice(get_global_DD_TRACE_LOG_LEVEL()), once); @@ -32,14 +33,14 @@ static void dd_log_set_level(bool debug) { } // We need to ensure that logging is initialized (i.e. set) at least once per thread. -void ddtrace_log_ginit(void) { +void datadog_log_ginit(void) { dd_log_set_level(get_global_DD_TRACE_DEBUG()); } -_Atomic(int) ddtrace_error_log_fd = -1; -_Atomic(uintmax_t) dd_error_log_fd_rotated = 0; +_Atomic(int) datadog_error_log_fd = -1; +static _Atomic(uintmax_t) dd_error_log_fd_rotated = 0; -void ddtrace_log_minit(void) { +void datadog_log_minit(void) { if (ZSTR_LEN(get_global_DD_TRACE_LOG_FILE())) { int fd = VCWD_OPEN_MODE(ZSTR_VAL(get_global_DD_TRACE_LOG_FILE()), O_RDWR | O_APPEND, 0666); if (fd < 0) { @@ -52,18 +53,18 @@ void ddtrace_log_minit(void) { fchmod(fd, 0666); // ignore umask #endif } - atomic_store(&ddtrace_error_log_fd, fd); + atomic_store(&datadog_error_log_fd, fd); time_t now; time(&now); atomic_store(&dd_error_log_fd_rotated, (uintmax_t) now); } - // no need to call dd_log_set_level here, ddtrace_config_minit() inits the debug config + // no need to call dd_log_set_level here, datadog_config_minit() inits the debug config } -void ddtrace_log_rinit(char *error_log) { - if (atomic_load(&ddtrace_error_log_fd) != -1) { +void datadog_log_rinit(char *error_log) { + if (atomic_load(&datadog_error_log_fd) != -1) { return; } @@ -87,13 +88,13 @@ void ddtrace_log_rinit(char *error_log) { time(&now); atomic_store(&dd_error_log_fd_rotated, (uintmax_t) now); int expected = -1; - if (!atomic_compare_exchange_strong_int(&ddtrace_error_log_fd, &expected, desired)) { + if (!atomic_compare_exchange_strong_int(&datadog_error_log_fd, &expected, desired)) { // if it didn't exchange, then we need to free it close(desired); } } -int ddtrace_get_fd_path(int fd, char *buf) { +int datadog_get_fd_path(int fd, char *buf) { #ifdef _WIN32 intptr_t handle = _get_osfhandle(fd); if (handle == INVALID_HANDLE_VALUE) { @@ -113,15 +114,15 @@ int ddtrace_get_fd_path(int fd, char *buf) { #endif } -void ddtrace_log_mshutdown(void) { - int error_log_fd = atomic_load(&ddtrace_error_log_fd); - atomic_store(&ddtrace_error_log_fd, -1); +void datadog_log_mshutdown(void) { + int error_log_fd = atomic_load(&datadog_error_log_fd); + atomic_store(&datadog_error_log_fd, -1); if (error_log_fd != -1) { close(error_log_fd); } } -int ddtrace_log_with_time(int fd, const char *msg, int msg_len) { +int datadog_log_with_time(int fd, const char *msg, int msg_len) { // todo: we only need 20-ish for the main part, but how much for the timezone? // Wish PHP printed -hhmm or +hhmm instead of the name char *msgbuf = malloc(msg_len + 70); @@ -144,7 +145,7 @@ int ddtrace_log_with_time(int fd, const char *msg, int msg_len) { uintmax_t last_check = atomic_exchange(&dd_error_log_fd_rotated, (uintmax_t) now); if (last_check < (uintmax_t)now - 60) { // 1x/min char pathbuf[MAXPATHLEN]; - if (ddtrace_get_fd_path(fd, pathbuf) >= 0) { + if (datadog_get_fd_path(fd, pathbuf) >= 0) { int new_fd = VCWD_OPEN_MODE(pathbuf, O_RDWR | O_APPEND, 0666); if (new_fd < 0) { // Retry with CREAT to only apply fchmod() on CREAT @@ -164,10 +165,10 @@ int ddtrace_log_with_time(int fd, const char *msg, int msg_len) { return ret; } -#undef ddtrace_bgs_logf -int ddtrace_bgs_logf(const char *fmt, ...) { +#undef datadog_signal_safe_logf +int datadog_signal_safe_logf(const char *fmt, ...) { int ret = 0; - int error_log_fd = atomic_load(&ddtrace_error_log_fd); + int error_log_fd = atomic_load(&datadog_error_log_fd); if (error_log_fd != -1) { va_list args, args_copy; va_start(args, fmt); @@ -180,7 +181,7 @@ int ddtrace_bgs_logf(const char *fmt, ...) { vsnprintf(msgbuf, needed_len, fmt, args); va_end(args); - ret = ddtrace_log_with_time(error_log_fd, msgbuf, needed_len); + ret = datadog_log_with_time(error_log_fd, msgbuf, needed_len); free(msgbuf); } @@ -188,11 +189,11 @@ int ddtrace_bgs_logf(const char *fmt, ...) { return ret; } -static void ddtrace_log_callback(ddog_CharSlice msg) { +static void dd_log_callback(ddog_CharSlice msg) { char *message = (char*)msg.ptr; - int error_log_fd = atomic_load(&ddtrace_error_log_fd); + int error_log_fd = atomic_load(&datadog_error_log_fd); if (error_log_fd != -1) { - ddtrace_log_with_time(error_log_fd, message, (int)msg.len); + datadog_log_with_time(error_log_fd, message, (int)msg.len); } else { // Temporarily disable user abort to prevent zend_bailout() from being // called inside php_log_err(). This callback is invoked from Rust while @@ -221,11 +222,11 @@ static void ddtrace_log_callback(ddog_CharSlice msg) { } -void ddtrace_log_init(void) { - ddog_log_callback = ddtrace_log_callback; +void datadog_log_init(void) { + ddog_log_callback = dd_log_callback; } -bool ddtrace_alter_dd_trace_debug(zval *old_value, zval *new_value, zend_string *new_str) { +bool datadog_alter_dd_trace_debug(zval *old_value, zval *new_value, zend_string *new_str) { UNUSED(old_value, new_str); dd_log_set_level(Z_TYPE_P(new_value) == IS_TRUE); @@ -233,7 +234,7 @@ bool ddtrace_alter_dd_trace_debug(zval *old_value, zval *new_value, zend_string return true; } -bool ddtrace_alter_dd_trace_log_level(zval *old_value, zval *new_value, zend_string *new_str) { +bool datadog_alter_dd_trace_log_level(zval *old_value, zval *new_value, zend_string *new_str) { UNUSED(old_value, new_str); if (runtime_config_first_init ? get_DD_TRACE_DEBUG() : get_global_DD_TRACE_DEBUG()) { return true; diff --git a/ext/logging.h b/ext/logging.h index 14b7260f7f6..a34cb7b0bde 100644 --- a/ext/logging.h +++ b/ext/logging.h @@ -9,24 +9,20 @@ #include #endif -extern _Atomic(int) ddtrace_error_log_fd; +extern _Atomic(int) datadog_error_log_fd; /* These are used by the background sender; use other log component from PHP thread. * {{{ */ -void ddtrace_log_minit(void); -void ddtrace_log_ginit(void); -void ddtrace_log_rinit(char *error_log); -void ddtrace_log_mshutdown(void); -int ddtrace_get_fd_path(int fd, char *buf); +void datadog_log_minit(void); +void datadog_log_ginit(void); +void datadog_log_rinit(char *error_log); +void datadog_log_mshutdown(void); +int datadog_get_fd_path(int fd, char *buf); -int ddtrace_bgs_logf(const char *fmt, ...); -/* variadic functions cannot be inlined; we use a macro to essentially inline - * the part we care about: the early return */ -#define ddtrace_bgs_logf(fmt, ...) (get_global_DD_TRACE_DEBUG_CURL_OUTPUT() ? ddtrace_bgs_logf(fmt, __VA_ARGS__) : 0) -/* }}} */ +int datadog_signal_safe_logf(const char *fmt, ...); -void ddtrace_log_init(void); -bool ddtrace_alter_dd_trace_debug(zval *old_value, zval *new_value, zend_string *new_str); -bool ddtrace_alter_dd_trace_log_level(zval *old_value, zval *new_value, zend_string *new_str); +void datadog_log_init(void); +bool datadog_alter_dd_trace_debug(zval *old_value, zval *new_value, zend_string *new_str); +bool datadog_alter_dd_trace_log_level(zval *old_value, zval *new_value, zend_string *new_str); #endif // DD_LOGGING_H diff --git a/ext/macros.h b/ext/macros.h deleted file mode 100644 index 1420bb00804..00000000000 --- a/ext/macros.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef DD_MACROS_H -#define DD_MACROS_H - -#ifndef _XOPEN_SOURCE -#if defined(__linux__) || defined(__OpenBSD__) || defined(__NetBSD__) -#define _XOPEN_SOURCE 700 -#elif defined(__APPLE__) && defined(__MACH__) -#define _XOPEN_SOURCE -#elif defined(__FreeBSD__) -// intentionally left blank, don't define _XOPEN_SOURCE -#elif defined(AIX) -// intentionally left blank, don't define _XOPEN_SOURCE -#else -#define _XOPEN_SOURCE -#endif -#endif //_XOPEN_SOURCE - -#endif // DD_MACROS_H diff --git a/ext/otel_config.c b/ext/otel_config.c index c03fdd42904..dd061ff1f44 100644 --- a/ext/otel_config.c +++ b/ext/otel_config.c @@ -1,17 +1,17 @@ #include "otel_config.h" #include -#include "ddtrace.h" +#include "datadog.h" #include -#include "sidecar.h" -#include "telemetry.h" +#include +#include #include "configuration.h" -ZEND_EXTERN_MODULE_GLOBALS(ddtrace); +ZEND_EXTERN_MODULE_GLOBALS(datadog); -static void report_otel_cfg_telemetry_invalid(const char *otel_cfg, const char *dd_cfg, bool pre_rinit) { - if (!pre_rinit && DDTRACE_G(sidecar) && get_DD_INSTRUMENTATION_TELEMETRY_ENABLED()) { - ddog_sidecar_telemetry_register_metric(&DDTRACE_G(sidecar), DDOG_CHARSLICE_C("otel.env.invalid"), DDOG_METRIC_TYPE_COUNT, DDOG_METRIC_NAMESPACE_TRACERS); - ddog_SidecarActionsBuffer *buffer = ddtrace_telemetry_buffer(); +void datadog_report_otel_cfg_telemetry_invalid(const char *otel_cfg, const char *dd_cfg, bool pre_rinit) { + if (!pre_rinit && DATADOG_G(sidecar) && get_DD_INSTRUMENTATION_TELEMETRY_ENABLED()) { + ddog_sidecar_telemetry_register_metric(&DATADOG_G(sidecar), DDOG_CHARSLICE_C("otel.env.invalid"), DDOG_METRIC_TYPE_COUNT, DDOG_METRIC_NAMESPACE_TRACERS); + ddog_SidecarActionsBuffer *buffer = datadog_telemetry_buffer(); ddog_CharSlice tags; tags.len = asprintf((char **)&tags.ptr, "config_opentelemetry:%s,config_datadog:%s", otel_cfg, dd_cfg); ddog_sidecar_telemetry_add_span_metric_point_buffer(buffer, DDOG_CHARSLICE_C("otel.env.invalid"), 1, tags); @@ -19,10 +19,10 @@ static void report_otel_cfg_telemetry_invalid(const char *otel_cfg, const char * } } -static bool get_otel_value(zai_str str, zai_env_buffer *buf, bool pre_rinit) { +bool datadog_get_otel_value(zai_str str, zai_env_buffer *buf, bool pre_rinit) { if (!pre_rinit && zai_sapi_getenv(str, buf) == ZAI_ENV_SUCCESS) return true; zai_option_str sys = zai_sys_getenv(str); - if (zai_option_str_is_some(sys)) { buf->ptr = sys.ptr; buf->len = sys.len; return true; } + if (zai_option_str_is_some(sys)) { buf->ptr = (char *) sys.ptr; buf->len = sys.len; return true; } zval *cfg = cfg_get_entry(str.ptr, str.len); if (cfg) { @@ -55,7 +55,7 @@ static bool get_otel_value(zai_str str, zai_env_buffer *buf, bool pre_rinit) { static bool ddtrace_conf_otel_resource_attributes_special(const char *tag, int len, zai_env_buffer *buf, bool pre_rinit) { ZAI_ENV_BUFFER_INIT(local, ZAI_ENV_MAX_BUFSIZ); - if (!get_otel_value((zai_str)ZAI_STRL("OTEL_RESOURCE_ATTRIBUTES"), &local, pre_rinit)) { + if (!datadog_get_otel_value((zai_str)ZAI_STRL("OTEL_RESOURCE_ATTRIBUTES"), &local, pre_rinit)) { return false; } @@ -87,80 +87,17 @@ bool ddtrace_conf_otel_resource_attributes_version(zai_env_buffer *buf, bool pre } bool ddtrace_conf_otel_service_name(zai_env_buffer *buf, bool pre_rinit) { - return get_otel_value((zai_str)ZAI_STRL("OTEL_SERVICE_NAME"), buf, pre_rinit) + return datadog_get_otel_value((zai_str)ZAI_STRL("OTEL_SERVICE_NAME"), buf, pre_rinit) || ddtrace_conf_otel_resource_attributes_special(ZEND_STRL("service.name"), buf, pre_rinit); } bool ddtrace_conf_otel_log_level(zai_env_buffer *buf, bool pre_rinit) { - return get_otel_value((zai_str)ZAI_STRL("OTEL_LOG_LEVEL"), buf, pre_rinit); -} - -bool ddtrace_conf_otel_propagators(zai_env_buffer *buf, bool pre_rinit) { - ZAI_ENV_BUFFER_INIT(local, ZAI_ENV_MAX_BUFSIZ); - if (!get_otel_value((zai_str)ZAI_STRL("OTEL_PROPAGATORS"), &local, pre_rinit)) { - return false; - } - memcpy(buf->ptr, local.ptr, strlen(local.ptr) + 1); - char *off = (char *)zend_memnstr(buf->ptr, ZEND_STRL("b3"), buf->ptr + strlen(buf->ptr)); - if (off && (!off[strlen("b3")] || off[strlen("b3")] == ',') && strlen(buf->ptr) < buf->len - 100) { - memmove(off + strlen("b3 single header"), off + strlen("b3"), buf->ptr + strlen(buf->ptr) - (off + strlen("b3")) + 1); - memcpy(off, "b3 single header", strlen("b3 single header")); - } - return true; -} - -bool ddtrace_conf_otel_sample_rate(zai_env_buffer *buf, bool pre_rinit) { - if (!get_otel_value((zai_str)ZAI_STRL("OTEL_TRACES_SAMPLER"), buf, pre_rinit)) { - return false; - } - - if (strcmp(buf->ptr, "always_on") == 0 || strcmp(buf->ptr, "parentbased_always_on") == 0) { - buf->ptr = "1"; buf->len = 1; - return true; - } - if (strcmp(buf->ptr, "always_off") == 0 || strcmp(buf->ptr, "parentbased_always_off") == 0) { - buf->ptr = "0"; buf->len = 1; - return true; - } - if (strcmp(buf->ptr, "traceidratio") == 0 || strcmp(buf->ptr, "parentbased_traceidratio") == 0) { - if (get_otel_value((zai_str)ZAI_STRL("OTEL_TRACES_SAMPLER_ARG"), buf, pre_rinit)) { - return true; - } - LOG_ONCE(WARN, "OTEL_TRACES_SAMPLER is %s, but is missing OTEL_TRACES_SAMPLER_ARG", buf->ptr); - } else { - LOG_ONCE(WARN, "OTEL_TRACES_SAMPLER has invalid value: %s", buf->ptr); - } - report_otel_cfg_telemetry_invalid("otel_traces_sampler", "dd_trace_sample_rate", pre_rinit); - return false; -} - -bool ddtrace_conf_otel_traces_exporter(zai_env_buffer *buf, bool pre_rinit) { - if (get_otel_value((zai_str)ZAI_STRL("OTEL_TRACES_EXPORTER"), buf, pre_rinit)) { - if (strcmp(buf->ptr, "none") == 0) { - buf->ptr = "0"; buf->len = 1; - return true; - } - LOG_ONCE(WARN, "OTEL_TRACES_EXPORTER has invalid value: %s", buf->ptr); - report_otel_cfg_telemetry_invalid("otel_traces_exporter", "dd_trace_enabled", pre_rinit); - } - return false; -} - -bool ddtrace_conf_otel_metrics_exporter(zai_env_buffer *buf, bool pre_rinit) { - if (get_otel_value((zai_str)ZAI_STRL("OTEL_METRICS_EXPORTER"), buf, pre_rinit)) { - if (strcmp(buf->ptr, "none") == 0) { - buf->ptr = "0"; buf->len = 1; - return true; - } - LOG_ONCE(WARN, "OTEL_METRICS_EXPORTER has invalid value: %s", buf->ptr); - report_otel_cfg_telemetry_invalid("otel_metrics_exporter", "dd_integration_metrics_enabled", pre_rinit); - } - return false; + return datadog_get_otel_value((zai_str)ZAI_STRL("OTEL_LOG_LEVEL"), buf, pre_rinit); } bool ddtrace_conf_otel_resource_attributes_tags(zai_env_buffer *buf, bool pre_rinit) { ZAI_ENV_BUFFER_INIT(local, ZAI_ENV_MAX_BUFSIZ); - if (!get_otel_value((zai_str)ZAI_STRL("OTEL_RESOURCE_ATTRIBUTES"), &local, pre_rinit)) { + if (!datadog_get_otel_value((zai_str)ZAI_STRL("OTEL_RESOURCE_ATTRIBUTES"), &local, pre_rinit)) { return false; } diff --git a/ext/otel_config.h b/ext/otel_config.h index a7840b6d78e..0dffecbd601 100644 --- a/ext/otel_config.h +++ b/ext/otel_config.h @@ -3,14 +3,13 @@ #include +void datadog_report_otel_cfg_telemetry_invalid(const char *otel_cfg, const char *dd_cfg, bool pre_rinit); +bool datadog_get_otel_value(zai_str str, zai_env_buffer *buf, bool pre_rinit); + bool ddtrace_conf_otel_resource_attributes_env(zai_env_buffer *buf, bool pre_rinit); bool ddtrace_conf_otel_resource_attributes_version(zai_env_buffer *buf, bool pre_rinit); bool ddtrace_conf_otel_service_name(zai_env_buffer *buf, bool pre_rinit); bool ddtrace_conf_otel_log_level(zai_env_buffer *buf, bool pre_rinit); -bool ddtrace_conf_otel_propagators(zai_env_buffer *buf, bool pre_rinit); -bool ddtrace_conf_otel_sample_rate(zai_env_buffer *buf, bool pre_rinit); -bool ddtrace_conf_otel_traces_exporter(zai_env_buffer *buf, bool pre_rinit); -bool ddtrace_conf_otel_metrics_exporter(zai_env_buffer *buf, bool pre_rinit); bool ddtrace_conf_otel_resource_attributes_tags(zai_env_buffer *buf, bool pre_rinit); #endif // DD_OTEL_CONFIG_H diff --git a/ext/patch_zend_call_known_function.c b/ext/patch_zend_call_known_function.c new file mode 100644 index 00000000000..e201ca0a350 --- /dev/null +++ b/ext/patch_zend_call_known_function.c @@ -0,0 +1,126 @@ +#include +#ifndef _WIN32 +#include +#endif +#include + +// On PHP 8.0.0-8.0.16 and 8.1.0-8.1.2 call_attribute_constructor would stack allocate a dummy frame, which could have become inaccessible upon access. +// Thus, we implement the fix which was applied to PHP itself as well: we move the stack allocated data to the VM stack. +// See also https://github.com/php/php-src/commit/f7c3f6e7e25471da9cfb2ba082a77cc3c85bc6ed +static void dd_patched_zend_call_known_function( + zend_function *fn, zend_object *object, zend_class_entry *called_scope, zval *retval_ptr, + uint32_t param_count, zval *params, HashTable *named_params) +{ + zval retval; + zend_fcall_info fci; + zend_fcall_info_cache fcic; + + // If current_execute_data is on the stack, move it to the VM stack + zend_execute_data *execute_data = EG(current_execute_data); + if (execute_data) { + bool is_stack_ex = (uintptr_t)&retval + 0xfffff > (uintptr_t)execute_data && (uintptr_t)&retval - 0xfffff < (uintptr_t)execute_data; + bool is_stack_func = (uintptr_t)&retval + 0xfffff > (uintptr_t)EX(func) && (uintptr_t)&retval - 0xfffff < (uintptr_t)EX(func); + if (is_stack_ex || is_stack_func) { + zend_execute_data *call = zend_vm_stack_push_call_frame_ex( + ZEND_MM_ALIGNED_SIZE_EX(sizeof(zend_execute_data), sizeof(zval)) + + (is_stack_func ? ZEND_MM_ALIGNED_SIZE_EX(sizeof(zend_op), sizeof(zval)) + ZEND_MM_ALIGNED_SIZE_EX(sizeof(zend_function), sizeof(zval)) : 0), + 0, EX(func), 0, NULL); + + memcpy(call, execute_data, sizeof(zend_execute_data)); + if (is_stack_func) { + zend_op *opline = (zend_op *)(call + 1); + memcpy(opline, EX(opline), sizeof(zend_op)); + zend_function *func = (zend_function *)(opline + 1); + memcpy(func, EX(func), sizeof(zend_function)); + func->common.fn_flags |= ZEND_ACC_CALL_VIA_TRAMPOLINE; // See https://github.com/php/php-src/commit/2f6a06ccb0ef78e6122bb9e67f9b8b1ad07776e1 + + call->opline = opline; + call->func = func; + } else { + call->opline = EX(opline); + } + + EG(current_execute_data) = call; + } + } + + // here follows the original implementation of zend_call_known_function + + fci.size = sizeof(fci); + fci.object = object; + fci.retval = retval_ptr ? retval_ptr : &retval; + fci.param_count = param_count; + fci.params = params; + fci.named_params = named_params; + ZVAL_UNDEF(&fci.function_name); /* Unused */ + + fcic.function_handler = fn; + fcic.object = object; + fcic.called_scope = called_scope; + + zend_result result = zend_call_function(&fci, &fcic); + if (UNEXPECTED(result == FAILURE)) { + if (!EG(exception)) { + zend_error_noreturn(E_CORE_ERROR, "Couldn't execute method %s%s%s", + fn->common.scope ? ZSTR_VAL(fn->common.scope->name) : "", + fn->common.scope ? "::" : "", ZSTR_VAL(fn->common.function_name)); + } + } + + if (!retval_ptr) { + zval_ptr_dtor(&retval); + } +} + +// We need to hijack zend_call_known_function as that's what's being called by call_attribute_constructor, and call_attribute_constructor itself is not exported. +void datadog_patch_zend_call_known_function(void) { +#ifdef _WIN32 + SYSTEM_INFO si; + GetSystemInfo(&si); + size_t page_size = (size_t)si.dwPageSize; +#else + size_t page_size = sysconf(_SC_PAGESIZE); +#endif + void *page = (void *)(~(page_size - 1) & (uintptr_t)zend_call_known_function); + // 20 is the largest size of a trampoline we have to inject + if ((((uintptr_t)zend_call_known_function + 20) & page_size) < 20) { + page_size <<= 1; // if overlapping pages, use two + } + +#ifdef _WIN32 + DWORD old_protection; + if (!VirtualProtect(page, page_size, PAGE_READWRITE, &old_protection)) +#else + if (mprotect(page, page_size, PROT_READ | PROT_WRITE) != 0) +#endif + { // Some architectures enforce W^X (either write _or_ execute, but not both). + LOG(ERROR, "Could not alter the memory protection for zend_call_known_function. Tracer execution continues, but may crash when encountering attributes."); + return; // Make absolutely sure we can write + } + +#ifdef __aarch64__ + // x13 is a scratch register + uint32_t absolute_jump_instrs[] = { + 0x1000006D, // adr x13, 12 (load address from memory after this) + 0xF94001AD, // ldr x13, [x13] + 0xD61F01A0, // br x13 + }; + // The magical 12 is sizeof(absolute_jump_instrs) and hardcoded in the assembly above. + memcpy(zend_call_known_function, absolute_jump_instrs, 12); + *(void **)(12 + (uintptr_t)zend_call_known_function) = dd_patched_zend_call_known_function; +#else + // $r10 doesn't really have special meaning + uint8_t absolute_jump_instrs[] = { + 0x49, 0xBA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov $r10, imm_addr + 0x41, 0xFF, 0xE2 // jmp $r10 + }; + *(void **)&absolute_jump_instrs[2] = dd_patched_zend_call_known_function; + memcpy(zend_call_known_function, absolute_jump_instrs, sizeof(absolute_jump_instrs)); +#endif + +#ifdef _WIN32 + VirtualProtect(page, page_size, old_protection, &old_protection /* dummy, but must be valid */); +#else + mprotect(page, page_size, PROT_READ | PROT_EXEC); +#endif +} diff --git a/ext/phpinfo.c b/ext/phpinfo.c new file mode 100644 index 00000000000..1b959484a37 --- /dev/null +++ b/ext/phpinfo.c @@ -0,0 +1,95 @@ +#include "phpinfo.h" +#include "datadog.h" +#include "startup_logging.h" +#include +#include +#include +#include + +static size_t datadog_info_print(const char *str) { return php_output_write(str, strlen(str)); } + +static void dd_info_tracer_config(void) { + smart_str buf = {0}; + datadog_startup_logging_json(&buf, PHP_JSON_PRETTY_PRINT); + php_info_print_table_row(2, "DATADOG TRACER CONFIGURATION", ZSTR_VAL(buf.s)); + smart_str_free(&buf); +} + +static void dd_info_diagnostics_row(const char *key, const char *value) { + if (sapi_module.phpinfo_as_text) { + php_info_print_table_row(2, key, value); + return; + } + datadog_info_print(""); + datadog_info_print(key); + datadog_info_print(""); + datadog_info_print(value); + datadog_info_print(""); +} + +static void dd_info_diagnostics_table(void) { + php_info_print_table_start(); + php_info_print_table_colspan_header(2, "Diagnostics"); + + HashTable *ht; + ALLOC_HASHTABLE(ht); + zend_hash_init(ht, 8, NULL, ZVAL_PTR_DTOR, 0); + + datadog_startup_diagnostics(ht, false); + + zend_string *key; + zval *val; + ZEND_HASH_FOREACH_STR_KEY_VAL_IND(ht, key, val) { + switch (Z_TYPE_P(val)) { + case IS_STRING: + dd_info_diagnostics_row(ZSTR_VAL(key), Z_STRVAL_P(val)); + break; + case IS_NULL: + dd_info_diagnostics_row(ZSTR_VAL(key), "NULL"); + break; + case IS_TRUE: + case IS_FALSE: + dd_info_diagnostics_row(ZSTR_VAL(key), Z_TYPE_P(val) == IS_TRUE ? "true" : "false"); + break; + default: + dd_info_diagnostics_row(ZSTR_VAL(key), "{unknown type}"); + break; + } + } + ZEND_HASH_FOREACH_END(); + + php_info_print_table_row(2, "Diagnostic checks", zend_hash_num_elements(ht) == 0 ? "passed" : "failed"); + + zend_hash_destroy(ht); + FREE_HASHTABLE(ht); + + php_info_print_table_end(); +} + +void datadog_phpinfo() { + php_info_print_box_start(0); + datadog_info_print("Datadog PHP tracer extension"); + if (!sapi_module.phpinfo_as_text) { + datadog_info_print("
For help, check out "); + datadog_info_print( + "the documentation."); + } else { + datadog_info_print( + "\nFor help, check out the documentation at " + "https://docs.datadoghq.com/tracing/languages/php/"); + } + datadog_info_print(!sapi_module.phpinfo_as_text ? "

" : "\n"); + datadog_info_print("(c) Datadog 2020\n"); + php_info_print_box_end(); + + php_info_print_table_start(); + php_info_print_table_row(2, "Datadog tracing support", datadog_disable ? "disabled" : "enabled"); + php_info_print_table_row(2, "Version", PHP_DDTRACE_VERSION); + dd_info_tracer_config(); + php_info_print_table_end(); + + if (!datadog_disable) { + dd_info_diagnostics_table(); + } +} \ No newline at end of file diff --git a/ext/phpinfo.h b/ext/phpinfo.h new file mode 100644 index 00000000000..f1a591b6b04 --- /dev/null +++ b/ext/phpinfo.h @@ -0,0 +1,6 @@ +#ifndef DATADOG_PHPINFO_H +#define DATADOG_PHPINFO_H + +void datadog_phpinfo(void); + +#endif // DATADOG_PHPINFO_H \ No newline at end of file diff --git a/ext/process_tags.c b/ext/process_tags.c index 8f269027ba6..8146081ccd4 100644 --- a/ext/process_tags.c +++ b/ext/process_tags.c @@ -10,7 +10,7 @@ #include #include #include "process_tags.h" -#include "configuration.h" +#include #include "Zend/zend_smart_str.h" #include "components-rs/ddtrace.h" #include "SAPI.h" @@ -207,7 +207,7 @@ static int cmp_process_tag_by_key(const void *tag1, const void* tag2) { } static void recompute_base_hash(void) { - if (!ddtrace_process_tags_enabled() || !process_tags.serialized) { + if (!datadog_process_tags_enabled() || !process_tags.serialized) { return; } @@ -238,7 +238,7 @@ static void recompute_base_hash(void) { } static void serialize_process_tags(void) { - if (!ddtrace_process_tags_enabled() || !process_tags.count) { + if (!datadog_process_tags_enabled() || !process_tags.count) { return; } @@ -290,8 +290,8 @@ static void init_process_tags(void) { serialize_process_tags(); } -void ddtrace_process_tags_set_container_tags_hash(zend_string *container_tags_hash) { - if (!container_tags_hash || !ddtrace_process_tags_enabled()) { +void datadog_process_tags_set_container_tags_hash(zend_string *container_tags_hash) { + if (!container_tags_hash || !datadog_process_tags_enabled()) { return; } @@ -304,12 +304,12 @@ void ddtrace_process_tags_set_container_tags_hash(zend_string *container_tags_ha recompute_base_hash(); } -zend_string *ddtrace_process_tags_get_serialized(void) { - return (ddtrace_process_tags_enabled() && process_tags.serialized) ? process_tags.serialized : ZSTR_EMPTY_ALLOC(); +zend_string *datadog_process_tags_get_serialized(void) { + return (datadog_process_tags_enabled() && process_tags.serialized) ? process_tags.serialized : ZSTR_EMPTY_ALLOC(); } -const ddog_Vec_Tag *ddtrace_process_tags_get_vec(void) { - if (ddtrace_process_tags_enabled() && process_tags.vec.ptr) { +const ddog_Vec_Tag *datadog_process_tags_get_vec(void) { + if (datadog_process_tags_enabled() && process_tags.vec.ptr) { return &process_tags.vec; } @@ -320,22 +320,22 @@ const ddog_Vec_Tag *ddtrace_process_tags_get_vec(void) { return &empty_vec; } -zend_string *ddtrace_process_tags_get_base_hash(void) { - return (ddtrace_process_tags_enabled() && process_tags.base_hash) ? process_tags.base_hash : NULL; +zend_string *datadog_process_tags_get_base_hash(void) { + return (datadog_process_tags_enabled() && process_tags.base_hash) ? process_tags.base_hash : NULL; } -bool ddtrace_process_tags_enabled(void){ +bool datadog_process_tags_enabled(void){ return zai_config_is_initialized() ? get_DD_EXPERIMENTAL_PROPAGATE_PROCESS_TAGS_ENABLED() : get_global_DD_EXPERIMENTAL_PROPAGATE_PROCESS_TAGS_ENABLED(); } -void ddtrace_process_tags_first_rinit(void) { +void datadog_process_tags_first_rinit(void) { init_process_tags(); } -void ddtrace_process_tags_reload(void) { +void datadog_process_tags_reload(void) { clear_process_tags(); init_process_tags(); } -void ddtrace_process_tags_mshutdown(void) { +void datadog_process_tags_mshutdown(void) { clear_process_tags(); } diff --git a/ext/process_tags.h b/ext/process_tags.h index 0840b6b951d..af916dc654b 100644 --- a/ext/process_tags.h +++ b/ext/process_tags.h @@ -3,34 +3,34 @@ #include #include "Zend/zend_types.h" -#include "ddtrace_export.h" +#include "datadog_export.h" #include "components-rs/common.h" // Called at first RINIT to collect process tags -void ddtrace_process_tags_first_rinit(void); +void datadog_process_tags_first_rinit(void); // Reload process tags in current request -void ddtrace_process_tags_reload(void); +void datadog_process_tags_reload(void); // Called at MSHUTDOWN to free resources -void ddtrace_process_tags_mshutdown(void); +void datadog_process_tags_mshutdown(void); // Check if process tags propagation is enabled -bool ddtrace_process_tags_enabled(void); +bool datadog_process_tags_enabled(void); // Get the serialized process tags (comma-separated, sorted) // Returns NULL if disabled or not yet collected -DDTRACE_PUBLIC zend_string *ddtrace_process_tags_get_serialized(void); +DATADOG_PUBLIC zend_string *datadog_process_tags_get_serialized(void); // Get a pointer to the process tags Vec // Returns a pointer to an empty Vec if disabled or not yet collected -const ddog_Vec_Tag *ddtrace_process_tags_get_vec(void); +const ddog_Vec_Tag *datadog_process_tags_get_vec(void); // Set the container tags hash -void ddtrace_process_tags_set_container_tags_hash(zend_string *hash); +void datadog_process_tags_set_container_tags_hash(zend_string *hash); // Get the base hash which is the hash of container_tags and process_tags // Returns NULL if disabled or not yet computed -zend_string *ddtrace_process_tags_get_base_hash(void); +zend_string *datadog_process_tags_get_base_hash(void); #endif // DD_PROCESS_TAGS_H diff --git a/ext/remote_config.c b/ext/remote_config.c index a6600b6f620..d0c2bd6fa4c 100644 --- a/ext/remote_config.c +++ b/ext/remote_config.c @@ -1,14 +1,11 @@ #include "remote_config.h" -#include "ddtrace.h" +#include "datadog.h" +#include "ffi_utils.h" #include "sidecar.h" -#include "hook/uhook.h" -#include "span.h" #include -#include #include -#include #include "threads.h" -#include "live_debugger.h" +#include #ifndef _WIN32 #include #endif @@ -19,55 +16,55 @@ #define zend_vm_interrupt zai_vm_interrupt #endif -ZEND_EXTERN_MODULE_GLOBALS(ddtrace); +ZEND_EXTERN_MODULE_GLOBALS(datadog); static void (*dd_prev_interrupt_function)(zend_execute_data *execute_data); static void dd_vm_interrupt(zend_execute_data *execute_data) { if (dd_prev_interrupt_function) { dd_prev_interrupt_function(execute_data); } - if (DDTRACE_G(remote_config_state) && DDTRACE_G(reread_remote_configuration)) { + if (DATADOG_G(remote_config_state) && DATADOG_G(reread_remote_configuration)) { LOG(INFO, "Rereading remote configurations after interrupt"); - DDTRACE_G(reread_remote_configuration) = 0; - ddog_process_remote_configs(DDTRACE_G(remote_config_state)); + DATADOG_G(reread_remote_configuration) = 0; + ddog_process_remote_configs(DATADOG_G(remote_config_state)); } } // We need this exported to call it via CreateRemoteThread on Windows -DDTRACE_PUBLIC void ddtrace_set_all_thread_vm_interrupt(void) { +DATADOG_PUBLIC void datadog_set_all_thread_vm_interrupt(void) { // broadcast interrupt to all threads on ZTS #if ZTS - tsrm_mutex_lock(ddtrace_threads_mutex); + tsrm_mutex_lock(datadog_threads_mutex); void *TSRMLS_CACHE; // EG() accesses a variable named TSRMLS_CACHE. Make use of variable shadowing in scopes... - ZEND_HASH_FOREACH_PTR(&ddtrace_tls_bases, TSRMLS_CACHE) { + ZEND_HASH_FOREACH_PTR(&datadog_tls_bases, TSRMLS_CACHE) { #endif #if PHP_VERSION_ID >= 80200 zend_atomic_bool_store_ex(&EG(vm_interrupt), 1); #elif PHP_VERSION_ID >= 70100 EG(vm_interrupt) = 1; #else - DDTRACE_G(zai_vm_interrupt) = 1; + DATADOG_G(zai_vm_interrupt) = 1; #endif - DDTRACE_G(reread_remote_configuration) = 1; + DATADOG_G(reread_remote_configuration) = 1; #if ZTS } ZEND_HASH_FOREACH_END(); - tsrm_mutex_unlock(ddtrace_threads_mutex); + tsrm_mutex_unlock(datadog_threads_mutex); #endif } -void ddtrace_check_for_new_config_now(void) { - if (DDTRACE_G(remote_config_state) && !DDTRACE_G(reread_remote_configuration) && ddog_process_remote_configs(DDTRACE_G(remote_config_state))) { +void datadog_check_for_new_config_now(void) { + if (DATADOG_G(remote_config_state) && !DATADOG_G(reread_remote_configuration) && ddog_process_remote_configs(DATADOG_G(remote_config_state))) { // If we blocked the signal, notify the other threads too - ddtrace_set_all_thread_vm_interrupt(); + datadog_set_all_thread_vm_interrupt(); } } #ifndef _WIN32 static void dd_sigvtalarm_handler(int signal, siginfo_t *siginfo, void *ctx) { UNUSED(signal, siginfo, ctx); - ddtrace_set_all_thread_vm_interrupt(); + datadog_set_all_thread_vm_interrupt(); } #endif @@ -99,16 +96,16 @@ static zend_string *dd_dynamic_configuration_update(ddog_CharSlice config, zend_ } } else { ZEND_ASSERT(mode == DDOG_DYNAMIC_CONFIG_UPDATE_MODE_WRITE); - DDTRACE_G(remote_config_writing) = true; + DATADOG_G(remote_config_writing) = true; zend_alter_ini_entry(name, value, ZEND_INI_USER, ZEND_INI_STAGE_RUNTIME); - DDTRACE_G(remote_config_writing) = false; + DATADOG_G(remote_config_writing) = false; zend_string_release(value); } zend_string_release(name); return ret; } -void ddtrace_minit_remote_config(void) { +void datadog_minit_remote_config(void) { ddog_setup_remote_config(dd_dynamic_configuration_update, &ddtrace_live_debugger_setup); dd_prev_interrupt_function = zend_interrupt_function; zend_interrupt_function = dd_vm_interrupt; @@ -121,7 +118,7 @@ void ddtrace_minit_remote_config(void) { #endif } -void ddtrace_mshutdown_remote_config(void) { +void datadog_mshutdown_remote_config(void) { #ifndef _WIN32 struct sigaction act = {0}; act.sa_handler = SIG_IGN; @@ -129,12 +126,10 @@ void ddtrace_mshutdown_remote_config(void) { #endif } -void ddtrace_rinit_remote_config(void) { - zend_hash_init(&DDTRACE_G(active_rc_hooks), 8, NULL, NULL, 0); - DDTRACE_G(reread_remote_configuration) = 0; +void datadog_rinit_remote_config(void) { + DATADOG_G(reread_remote_configuration) = 0; } -void ddtrace_rshutdown_remote_config(void) { - ddog_rshutdown_remote_config(DDTRACE_G(remote_config_state)); - zend_hash_destroy(&DDTRACE_G(active_rc_hooks)); +void datadog_rshutdown_remote_config(void) { + ddog_rshutdown_remote_config(DATADOG_G(remote_config_state)); } diff --git a/ext/remote_config.h b/ext/remote_config.h index 88e04808c5b..e615515b833 100644 --- a/ext/remote_config.h +++ b/ext/remote_config.h @@ -1,15 +1,15 @@ #ifndef DD_REMOTE_CONFIG_H #define DD_REMOTE_CONFIG_H -#include "ddtrace_export.h" +#include "datadog_export.h" -void ddtrace_minit_remote_config(void); -void ddtrace_mshutdown_remote_config(void); -void ddtrace_rinit_remote_config(void); -void ddtrace_rshutdown_remote_config(void); -void ddtrace_check_for_new_config_now(void); +void datadog_minit_remote_config(void); +void datadog_mshutdown_remote_config(void); +void datadog_rinit_remote_config(void); +void datadog_rshutdown_remote_config(void); +void datadog_check_for_new_config_now(void); -DDTRACE_PUBLIC void ddtrace_set_all_thread_vm_interrupt(void); +DATADOG_PUBLIC void datadog_set_all_thread_vm_interrupt(void); #endif diff --git a/ext/sidecar.c b/ext/sidecar.c index 9ea81ab2220..0cb22765c04 100644 --- a/ext/sidecar.c +++ b/ext/sidecar.c @@ -1,42 +1,43 @@ #include #include
-#include "ddtrace.h" -#include "auto_flush.h" -#include "compat_string.h" +#include "datadog.h" #include "configuration.h" -#include "ddtrace_export.h" -#include "dogstatsd.h" +#include "datadog_export.h" +#include "endpoints.h" #include "logging.h" #include #include #include #include #include "sidecar.h" -#include "live_debugger.h" #include "telemetry.h" #include "process_tags.h" -#include "serializer.h" #include "remote_config.h" -#include "process_tags.h" +#include "string_utils.h" +#include "ffi_utils.h" +#include +#include +#include #ifndef _WIN32 -#include "coms.h" +#include +#include #endif -ZEND_EXTERN_MODULE_GLOBALS(ddtrace); +ZEND_EXTERN_MODULE_GLOBALS(datadog); -ddog_Endpoint *ddtrace_endpoint; -ddog_Endpoint *dogstatsd_endpoint; // always set when ddtrace_endpoint is set -struct ddog_InstanceId *ddtrace_sidecar_instance_id; +ddog_Endpoint *datadog_endpoint; +ddog_Endpoint *dogstatsd_endpoint; // always set when datadog_endpoint is set +struct ddog_InstanceId *datadog_sidecar_instance_id; // Best-effort pointer for the signal handler (SIGTERM/SIGINT). Set to the first // per-thread connection; never cleared until MSHUTDOWN. Not atomic: concurrent // shutdown is already a best-effort race for signal handlers, so atomicity of // the pointer load alone would not prevent the underlying use-after-free. -ddog_SidecarTransport *ddtrace_sidecar_for_signal = NULL; +ddog_SidecarTransport *datadog_sidecar_for_signal = NULL; // Connection mode tracking -dd_sidecar_active_mode_t ddtrace_sidecar_active_mode = DD_SIDECAR_CONNECTION_NONE; -int32_t ddtrace_sidecar_master_pid = 0; +dd_sidecar_active_mode_t datadog_sidecar_active_mode = DD_SIDECAR_CONNECTION_NONE; +int32_t datadog_sidecar_master_pid = 0; static inline void dd_set_endpoint_test_token(ddog_Endpoint *endpoint) { if (zai_config_is_initialized()) { @@ -49,63 +50,63 @@ static inline void dd_set_endpoint_test_token(ddog_Endpoint *endpoint) { } // Set the globals that stay unchanged in case of fork -static void ddtrace_set_non_resettable_sidecar_globals(void) { - ddtrace_endpoint = ddtrace_sidecar_agent_endpoint(); +static void dd_set_non_resettable_sidecar_globals(void) { + datadog_endpoint = datadog_sidecar_agent_endpoint(); if (get_global_DD_TRACE_AGENTLESS() && ZSTR_LEN(get_global_DD_API_KEY())) { dogstatsd_endpoint = ddog_endpoint_from_api_key(dd_zend_string_to_CharSlice(get_global_DD_API_KEY())); } else { - char *dogstatsd_url = ddtrace_dogstatsd_url(); + char *dogstatsd_url = datadog_dogstatsd_url(); dogstatsd_endpoint = ddog_endpoint_from_url((ddog_CharSlice) {.ptr = dogstatsd_url, .len = strlen(dogstatsd_url)}); free(dogstatsd_url); } } // Build the process-level instance ID (one per PHP process, reset after fork). -static void ddtrace_set_resettable_sidecar_globals(void) { +static void dd_set_resettable_sidecar_globals(void) { uint8_t formatted_run_time_id[36]; - ddtrace_format_runtime_id(&formatted_run_time_id); + datadog_format_runtime_id(&formatted_run_time_id); ddog_CharSlice runtime_id = (ddog_CharSlice) {.ptr = (char *) formatted_run_time_id, .len = sizeof(formatted_run_time_id)}; - ddog_CharSlice session_id = (ddog_CharSlice) {.ptr = (char *) ddtrace_formatted_session_id, .len = sizeof(ddtrace_formatted_session_id)}; - ddtrace_sidecar_instance_id = ddog_sidecar_instanceId_build(session_id, runtime_id); + ddog_CharSlice session_id = (ddog_CharSlice) {.ptr = (char *) datadog_formatted_session_id, .len = sizeof(datadog_formatted_session_id)}; + datadog_sidecar_instance_id = ddog_sidecar_instanceId_build(session_id, runtime_id); } static void dd_free_endpoints(void) { - ddog_endpoint_drop(ddtrace_endpoint); + ddog_endpoint_drop(datadog_endpoint); ddog_endpoint_drop(dogstatsd_endpoint); - ddtrace_endpoint = NULL; + datadog_endpoint = NULL; dogstatsd_endpoint = NULL; } -DDTRACE_PUBLIC const uint8_t *ddtrace_get_formatted_session_id(void) { - if (ddtrace_is_empty_session_id(ddtrace_formatted_session_id)) { +DATADOG_PUBLIC const uint8_t *datadog_get_formatted_session_id(void) { + if (datadog_is_empty_session_id(datadog_formatted_session_id)) { return NULL; } - return ddtrace_formatted_session_id; + return datadog_formatted_session_id; } -DDTRACE_PUBLIC struct telemetry_rc_info ddtrace_get_telemetry_rc_info(void) { +DATADOG_PUBLIC struct telemetry_rc_info datadog_get_telemetry_rc_info(void) { struct telemetry_rc_info info = { - .service_name = DDTRACE_G(last_service_name), - .env_name = DDTRACE_G(last_env_name), + .service_name = DATADOG_G(last_service_name), + .env_name = DATADOG_G(last_env_name), }; - if (DDTRACE_G(remote_config_state)) { - info.rc_path = ddog_remote_config_get_path(DDTRACE_G(remote_config_state)); + if (DATADOG_G(remote_config_state)) { + info.rc_path = ddog_remote_config_get_path(DATADOG_G(remote_config_state)); } return info; } -DDTRACE_PUBLIC uint64_t ddtrace_get_sidecar_queue_id(void) { - return DDTRACE_G(sidecar_queue_id); +DATADOG_PUBLIC uint64_t datadog_get_sidecar_queue_id(void) { + return DATADOG_G(sidecar_queue_id); } static void dd_sidecar_post_connect(ddog_SidecarTransport **transport, bool is_fork, const char *logpath) { - ddog_CharSlice session_id = (ddog_CharSlice) {.ptr = (char *) ddtrace_formatted_session_id, .len = sizeof(ddtrace_formatted_session_id)}; - ddog_CharSlice root_session_id = ddtrace_is_empty_session_id(ddtrace_formatted_root_session_id) ? DDOG_CHARSLICE_C("") : (ddog_CharSlice) {.ptr = (char *) ddtrace_formatted_root_session_id, .len = sizeof(ddtrace_formatted_root_session_id)}; - ddog_CharSlice parent_session_id = ddtrace_is_empty_session_id(ddtrace_formatted_parent_session_id) ? DDOG_CHARSLICE_C("") : (ddog_CharSlice) {.ptr = (char *) ddtrace_formatted_parent_session_id, .len = sizeof(ddtrace_formatted_parent_session_id)}; - const ddog_Vec_Tag *process_tags = ddtrace_process_tags_get_vec(); - ddog_sidecar_session_set_config(transport, session_id, ddtrace_endpoint, dogstatsd_endpoint, + ddog_CharSlice session_id = (ddog_CharSlice) {.ptr = (char *) datadog_formatted_session_id, .len = sizeof(datadog_formatted_session_id)}; + ddog_CharSlice root_session_id = datadog_is_empty_session_id(datadog_formatted_root_session_id) ? DDOG_CHARSLICE_C("") : (ddog_CharSlice) {.ptr = (char *) datadog_formatted_root_session_id, .len = sizeof(datadog_formatted_root_session_id)}; + ddog_CharSlice parent_session_id = datadog_is_empty_session_id(datadog_formatted_parent_session_id) ? DDOG_CHARSLICE_C("") : (ddog_CharSlice) {.ptr = (char *) datadog_formatted_parent_session_id, .len = sizeof(datadog_formatted_parent_session_id)}; + const ddog_Vec_Tag *process_tags = datadog_process_tags_get_vec(); + ddog_sidecar_session_set_config(transport, session_id, datadog_endpoint, dogstatsd_endpoint, DDOG_CHARSLICE_C("php"), php_version_rt, DDOG_CHARSLICE_C(PHP_DDTRACE_VERSION), @@ -119,11 +120,11 @@ static void dd_sidecar_post_connect(ddog_SidecarTransport **transport, bool is_f get_global_DD_TRACE_AGENT_STACK_BACKLOG() * get_global_DD_TRACE_AGENT_MAX_PAYLOAD_SIZE(), get_global_DD_TRACE_DEBUG() ? DDOG_CHARSLICE_C("debug") : dd_zend_string_to_CharSlice(get_global_DD_TRACE_LOG_LEVEL()), (ddog_CharSlice){ .ptr = logpath, .len = strlen(logpath) }, - ddtrace_set_all_thread_vm_interrupt, - DDTRACE_REMOTE_CONFIG_PRODUCTS.ptr, - DDTRACE_REMOTE_CONFIG_PRODUCTS.len, - DDTRACE_REMOTE_CONFIG_CAPABILITIES.ptr, - DDTRACE_REMOTE_CONFIG_CAPABILITIES.len, + datadog_set_all_thread_vm_interrupt, + DATADOG_REMOTE_CONFIG_PRODUCTS.ptr, + DATADOG_REMOTE_CONFIG_PRODUCTS.len, + DATADOG_REMOTE_CONFIG_CAPABILITIES.ptr, + DATADOG_REMOTE_CONFIG_CAPABILITIES.len, get_global_DD_REMOTE_CONFIG_ENABLED(), is_fork, process_tags, @@ -134,56 +135,54 @@ static void dd_sidecar_post_connect(ddog_SidecarTransport **transport, bool is_f ); if (get_global_DD_INSTRUMENTATION_TELEMETRY_ENABLED()) { - ddtrace_telemetry_register_services(transport); + datadog_telemetry_register_services(transport); } } -void ddtrace_sidecar_update_process_tags(void) { - if (!DDTRACE_G(sidecar)) { +void datadog_sidecar_update_process_tags(void) { + if (!DATADOG_G(sidecar)) { return; } - const ddog_Vec_Tag *process_tags = ddtrace_process_tags_get_vec(); + const ddog_Vec_Tag *process_tags = datadog_process_tags_get_vec(); if (!process_tags || process_tags->len == 0) { return; } - ddog_sidecar_session_set_process_tags(&DDTRACE_G(sidecar), process_tags); + ddog_sidecar_session_set_process_tags(&DATADOG_G(sidecar), process_tags); } -static ddog_SidecarTransport *dd_sidecar_connection_factory_ex(bool is_fork); -static ddog_SidecarTransport *dd_sidecar_connection_factory_thread(void); -static void ddtrace_sidecar_setup_thread_mode(bool appsec_activation, bool appsec_config); +static void datadog_sidecar_setup_thread_mode(bool appsec_activation, bool appsec_config); static void dd_sidecar_on_reconnect(ddog_SidecarTransport *transport) { - if (!ddtrace_endpoint || !dogstatsd_endpoint) { + if (!datadog_endpoint || !dogstatsd_endpoint) { return; } char logpath[MAXPATHLEN]; - int error_fd = atomic_load(&ddtrace_error_log_fd); - if (error_fd == -1 || ddtrace_get_fd_path(error_fd, logpath) < 0) { + int error_fd = atomic_load(&datadog_error_log_fd); + if (error_fd == -1 || datadog_get_fd_path(error_fd, logpath) < 0) { *logpath = 0; } dd_sidecar_post_connect(&transport, false, logpath); - tsrm_mutex_lock(DDTRACE_G(sidecar_universal_service_tags_mutex)); + tsrm_mutex_lock(DATADOG_G(sidecar_universal_service_tags_mutex)); - if (DDTRACE_G(sidecar_queue_id) && DDTRACE_G(last_service_name)) { - ddog_CharSlice service_name = dd_zend_string_to_CharSlice(DDTRACE_G(last_service_name)); - ddog_CharSlice env_name = dd_zend_string_to_CharSlice(DDTRACE_G(last_env_name)); - ddog_CharSlice version = dd_zend_string_to_CharSlice(DDTRACE_G(last_version)); - ddtrace_ffi_try("Failed sending config data", - ddog_sidecar_set_universal_service_tags(&transport, ddtrace_sidecar_instance_id, &DDTRACE_G(sidecar_queue_id), service_name, - env_name, version, &DDTRACE_G(active_global_tags), ddtrace_dynamic_instrumentation_state())); + if (DATADOG_G(sidecar_queue_id) && DATADOG_G(last_service_name)) { + ddog_CharSlice service_name = dd_zend_string_to_CharSlice(DATADOG_G(last_service_name)); + ddog_CharSlice env_name = dd_zend_string_to_CharSlice(DATADOG_G(last_env_name)); + ddog_CharSlice version = dd_zend_string_to_CharSlice(DATADOG_G(last_version)); + datadog_ffi_try("Failed sending config data", + ddog_sidecar_set_universal_service_tags(&transport, datadog_sidecar_instance_id, &DATADOG_G(sidecar_queue_id), service_name, + env_name, version, &DATADOG_G(active_global_tags), ddtrace_dynamic_instrumentation_state())); } - tsrm_mutex_unlock(DDTRACE_G(sidecar_universal_service_tags_mutex)); + tsrm_mutex_unlock(DATADOG_G(sidecar_universal_service_tags_mutex)); } static ddog_SidecarTransport *dd_sidecar_connect(bool as_worker, bool is_fork) { - if (!ddtrace_endpoint) { + if (!datadog_endpoint) { return NULL; } ZEND_ASSERT(dogstatsd_endpoint != NULL); @@ -198,29 +197,29 @@ static ddog_SidecarTransport *dd_sidecar_connect(bool as_worker, bool is_fork) { #else char logpath[MAXPATHLEN]; #endif - int error_fd = atomic_load(&ddtrace_error_log_fd); - if (error_fd == -1 || ddtrace_get_fd_path(error_fd, logpath) < 0) { + int error_fd = atomic_load(&datadog_error_log_fd); + if (error_fd == -1 || datadog_get_fd_path(error_fd, logpath) < 0) { *logpath = 0; } ddog_SidecarTransport *sidecar_transport; if (as_worker) { - if (!ddtrace_ffi_try("Failed connecting to the sidecar as worker", - ddog_sidecar_connect_worker((int32_t)ddtrace_sidecar_master_pid, &sidecar_transport))) { + if (!datadog_ffi_try("Failed connecting to the sidecar as worker", + ddog_sidecar_connect_worker((int32_t)datadog_sidecar_master_pid, &sidecar_transport))) { #ifdef _WIN32 int32_t current_pid = (int32_t)GetCurrentProcessId(); #else int32_t current_pid = (int32_t)getpid(); #endif // If we're an orphaned child, promote this process to master so traces can still be submitted. - if (current_pid != ddtrace_sidecar_master_pid) { + if (current_pid != datadog_sidecar_master_pid) { LOG(INFO, "Parent's sidecar listener gone (child PID=%d, master=%d), promoting to master", - current_pid, ddtrace_sidecar_master_pid); - ddtrace_sidecar_master_pid = current_pid; - if (!ddtrace_ffi_try("Failed starting sidecar master listener as orphaned child", - ddog_sidecar_connect_master((int32_t)ddtrace_sidecar_master_pid)) || - !ddtrace_ffi_try("Failed connecting to new sidecar master as orphaned child", - ddog_sidecar_connect_worker((int32_t)ddtrace_sidecar_master_pid, &sidecar_transport))) { + current_pid, datadog_sidecar_master_pid); + datadog_sidecar_master_pid = current_pid; + if (!datadog_ffi_try("Failed starting sidecar master listener as orphaned child", + ddog_sidecar_connect_master((int32_t)datadog_sidecar_master_pid)) || + !datadog_ffi_try("Failed connecting to new sidecar master as orphaned child", + ddog_sidecar_connect_worker((int32_t)datadog_sidecar_master_pid, &sidecar_transport))) { dd_free_endpoints(); return NULL; } @@ -230,17 +229,17 @@ static ddog_SidecarTransport *dd_sidecar_connect(bool as_worker, bool is_fork) { return NULL; } } - ddtrace_sidecar_active_mode = DD_SIDECAR_CONNECTION_THREAD; + datadog_sidecar_active_mode = DD_SIDECAR_CONNECTION_THREAD; } else { - if (!ddtrace_ffi_try("Failed connecting to the sidecar (subprocess mode)", + if (!datadog_ffi_try("Failed connecting to the sidecar (subprocess mode)", ddog_sidecar_connect_php(&sidecar_transport, logpath, dd_zend_string_to_CharSlice(get_global_DD_TRACE_LOG_LEVEL()), get_global_DD_INSTRUMENTATION_TELEMETRY_ENABLED(), dd_sidecar_on_reconnect, - ddtrace_endpoint, (uint64_t)get_global_DD_TRACE_SIDECAR_BACKPRESSURE_BYTES(), (uint64_t)get_global_DD_TRACE_SIDECAR_BACKPRESSURE_QUEUE()))) { + datadog_endpoint, (uint64_t)get_global_DD_TRACE_SIDECAR_BACKPRESSURE_BYTES(), (uint64_t)get_global_DD_TRACE_SIDECAR_BACKPRESSURE_QUEUE()))) { return NULL; } - ddtrace_sidecar_active_mode = DD_SIDECAR_CONNECTION_SUBPROCESS; + datadog_sidecar_active_mode = DD_SIDECAR_CONNECTION_SUBPROCESS; } dd_sidecar_post_connect(&sidecar_transport, is_fork, logpath); @@ -248,22 +247,22 @@ static ddog_SidecarTransport *dd_sidecar_connect(bool as_worker, bool is_fork) { return sidecar_transport; } -static void ddtrace_sidecar_setup_thread_mode(bool appsec_activation, bool appsec_config) { +static void datadog_sidecar_setup_thread_mode(bool appsec_activation, bool appsec_config) { #ifndef _WIN32 int32_t current_pid = (int32_t)getpid(); #else int32_t current_pid = (int32_t)GetCurrentProcessId(); #endif - bool is_child_process = (ddtrace_sidecar_master_pid != 0 && current_pid != ddtrace_sidecar_master_pid); + bool is_child_process = (datadog_sidecar_master_pid != 0 && current_pid != datadog_sidecar_master_pid); - bool listener_available = ddog_sidecar_is_master_listener_active(ddtrace_sidecar_master_pid); + bool listener_available = ddog_sidecar_is_master_listener_active(datadog_sidecar_master_pid); if (is_child_process || listener_available) { - DDTRACE_G(sidecar) = dd_sidecar_connect(true, false); - if (DDTRACE_G(sidecar)) { + DATADOG_G(sidecar) = dd_sidecar_connect(true, false); + if (DATADOG_G(sidecar)) { if (is_child_process) { LOG(INFO, "Worker connected to sidecar master listener (worker PID=%d, master PID=%d)", - (int32_t)current_pid, ddtrace_sidecar_master_pid); + (int32_t)current_pid, datadog_sidecar_master_pid); } return; } @@ -274,35 +273,30 @@ static void ddtrace_sidecar_setup_thread_mode(bool appsec_activation, bool appse } LOG(WARN, "Cannot connect to master sidecar listener from worker (child PID=%d, master PID=%d)", - (int32_t)current_pid, ddtrace_sidecar_master_pid); + (int32_t)current_pid, datadog_sidecar_master_pid); return; } - if (!ddtrace_ffi_try("Failed starting sidecar master listener", ddog_sidecar_connect_master((int32_t)ddtrace_sidecar_master_pid))) { + if (!datadog_ffi_try("Failed starting sidecar master listener", ddog_sidecar_connect_master((int32_t)datadog_sidecar_master_pid))) { LOG(WARN, "Failed to start sidecar master listener"); - if (ddtrace_endpoint) { + if (datadog_endpoint) { dd_free_endpoints(); } return; } - LOG(INFO, "Started sidecar master listener thread (PID=%d)", ddtrace_sidecar_master_pid); + LOG(INFO, "Started sidecar master listener thread (PID=%d)", datadog_sidecar_master_pid); - DDTRACE_G(sidecar) = dd_sidecar_connect(true, false); - if (!DDTRACE_G(sidecar)) { + DATADOG_G(sidecar) = dd_sidecar_connect(true, false); + if (!DATADOG_G(sidecar)) { LOG(WARN, "Failed to connect master process to sidecar"); - return; - } - - if (get_global_DD_INSTRUMENTATION_TELEMETRY_ENABLED()) { - ddtrace_telemetry_first_init(); } } -ddog_SidecarTransport *ddtrace_sidecar_connect(bool is_fork) { - if (ddtrace_sidecar_active_mode == DD_SIDECAR_CONNECTION_SUBPROCESS) { +ddog_SidecarTransport *datadog_sidecar_connect(bool is_fork) { + if (datadog_sidecar_active_mode == DD_SIDECAR_CONNECTION_SUBPROCESS) { return dd_sidecar_connect(false, is_fork); - } else if (ddtrace_sidecar_active_mode == DD_SIDECAR_CONNECTION_THREAD) { + } else if (datadog_sidecar_active_mode == DD_SIDECAR_CONNECTION_THREAD) { return dd_sidecar_connect(true, is_fork); } @@ -332,7 +326,7 @@ ddog_SidecarTransport *ddtrace_sidecar_connect(bool is_fork) { transport = dd_sidecar_connect(false, is_fork); if (!transport) { - if (ddtrace_endpoint) { + if (datadog_endpoint) { LOG(WARN, "Subprocess connection failed, falling back to thread mode"); transport = dd_sidecar_connect(true, is_fork); @@ -349,11 +343,21 @@ ddog_SidecarTransport *ddtrace_sidecar_connect(bool is_fork) { return transport; } -static ddog_SidecarTransport *ddtrace_sidecar_connect_callback(void) { - return ddtrace_sidecar_connect(false); +static ddog_SidecarTransport *datadog_sidecar_connect_callback(void) { + return datadog_sidecar_connect(false); +} + +bool datadog_sidecar_should_enable(bool *appsec_activation, bool *appsec_config) { + datadog_sidecar_configure_appsec(appsec_activation, appsec_config); + bool enable_sidecar = *appsec_activation; + if (!enable_sidecar) { + enable_sidecar = get_global_DD_INSTRUMENTATION_TELEMETRY_ENABLED() || + get_global_DD_TRACE_SIDECAR_TRACE_SENDER(); + } + return enable_sidecar; } -bool ddtrace_sidecar_maybe_enable_appsec(bool *appsec_activation, bool *appsec_config) { +void datadog_sidecar_configure_appsec(bool *appsec_activation, bool *appsec_config) { *appsec_activation = false; *appsec_config = false; @@ -364,173 +368,161 @@ bool ddtrace_sidecar_maybe_enable_appsec(bool *appsec_activation, bool *appsec_c #if defined(__linux__) || defined(__APPLE__) zend_module_entry *appsec_module = zend_hash_str_find_ptr(&module_registry, "ddappsec", sizeof("ddappsec") - 1); if (!appsec_module) { - return false; + return; } void *handle = dlsym(appsec_module->handle, "dd_appsec_maybe_enable_helper"); if (!handle) { - return false; + return; } bool (*dd_appsec_maybe_enable_helper)(typeof(&ddog_sidecar_enable_appsec), bool *, bool *) = handle; - return dd_appsec_maybe_enable_helper(ddog_sidecar_enable_appsec, appsec_activation, appsec_config); -#else - return false; + dd_appsec_maybe_enable_helper(ddog_sidecar_enable_appsec, appsec_activation, appsec_config); #endif } -bool ddtrace_sidecar_should_enable(bool *appsec_activation, bool *appsec_config) { - bool enable_sidecar = ddtrace_sidecar_maybe_enable_appsec(appsec_activation, appsec_config); - if (!enable_sidecar) { - enable_sidecar = get_global_DD_INSTRUMENTATION_TELEMETRY_ENABLED() || - get_global_DD_TRACE_SIDECAR_TRACE_SENDER(); - } - return enable_sidecar; -} -void ddtrace_sidecar_setup(bool appsec_activation, bool appsec_config) { - ddtrace_set_non_resettable_sidecar_globals(); - ddtrace_set_resettable_sidecar_globals(); +void datadog_sidecar_setup(bool appsec_activation, bool appsec_config) { + dd_set_non_resettable_sidecar_globals(); + dd_set_resettable_sidecar_globals(); ddog_init_remote_config(get_global_DD_INSTRUMENTATION_TELEMETRY_ENABLED(), appsec_activation, appsec_config); zend_long mode = get_global_DD_TRACE_SIDECAR_CONNECTION_MODE(); if (mode == DD_TRACE_SIDECAR_CONNECTION_MODE_THREAD) { - ddtrace_sidecar_setup_thread_mode(appsec_activation, appsec_config); + datadog_sidecar_setup_thread_mode(appsec_activation, appsec_config); } else { - DDTRACE_G(sidecar) = dd_sidecar_connect(false, false); + DATADOG_G(sidecar) = dd_sidecar_connect(false, false); - if (!DDTRACE_G(sidecar)) { - if (mode == DD_TRACE_SIDECAR_CONNECTION_MODE_AUTO && ddtrace_endpoint) { + if (!DATADOG_G(sidecar)) { + if (mode == DD_TRACE_SIDECAR_CONNECTION_MODE_AUTO && datadog_endpoint) { LOG(WARN, "Subprocess connection failed, falling back to thread mode"); - ddtrace_sidecar_setup_thread_mode(appsec_activation, appsec_config); - } else if (ddtrace_endpoint) { + datadog_sidecar_setup_thread_mode(appsec_activation, appsec_config); + } else if (datadog_endpoint) { dd_free_endpoints(); } - } else if (get_global_DD_INSTRUMENTATION_TELEMETRY_ENABLED()) { - ddtrace_telemetry_first_init(); } } // Record the first established connection for best-effort signal-handler use. - if (DDTRACE_G(sidecar) && !ddtrace_sidecar_for_signal) { - ddtrace_sidecar_for_signal = DDTRACE_G(sidecar); + if (DATADOG_G(sidecar) && !datadog_sidecar_for_signal) { + datadog_sidecar_for_signal = DATADOG_G(sidecar); } } -void ddtrace_sidecar_minit(void) { +void datadog_sidecar_minit(void) { #ifdef _WIN32 - ddtrace_sidecar_master_pid = (int32_t)GetCurrentProcessId(); + datadog_sidecar_master_pid = (int32_t)GetCurrentProcessId(); #else - ddtrace_sidecar_master_pid = (int32_t)getpid(); + datadog_sidecar_master_pid = (int32_t)getpid(); #endif zend_long mode = get_global_DD_TRACE_SIDECAR_CONNECTION_MODE(); if (mode == DD_TRACE_SIDECAR_CONNECTION_MODE_THREAD) { - ddtrace_ffi_try("Starting sidecar master listener in MINIT", - ddog_sidecar_connect_master(ddtrace_sidecar_master_pid)); + datadog_ffi_try("Starting sidecar master listener in MINIT", + ddog_sidecar_connect_master(datadog_sidecar_master_pid)); } } -void ddtrace_sidecar_handle_fork(void) { +void datadog_sidecar_handle_fork(void) { #ifndef _WIN32 bool appsec_activation = false; bool appsec_config = false; - bool enable_sidecar = ddtrace_sidecar_should_enable(&appsec_activation, &appsec_config); + bool enable_sidecar = datadog_sidecar_should_enable(&appsec_activation, &appsec_config); if (!enable_sidecar) { return; } - ddtrace_force_new_instance_id(); + datadog_force_new_instance_id(); // After fork only one thread (the one that called fork) survives, so we only // need to drop and reconnect the current thread's transport. - if (DDTRACE_G(sidecar)) { - ddog_sidecar_transport_drop(DDTRACE_G(sidecar)); - DDTRACE_G(sidecar) = NULL; + if (DATADOG_G(sidecar)) { + ddog_sidecar_transport_drop(DATADOG_G(sidecar)); + DATADOG_G(sidecar) = NULL; } - ddtrace_sidecar_for_signal = NULL; + datadog_sidecar_for_signal = NULL; - if (ddtrace_sidecar_active_mode == DD_SIDECAR_CONNECTION_THREAD) { - ddtrace_ffi_try("Failed clearing inherited listener state", + if (datadog_sidecar_active_mode == DD_SIDECAR_CONNECTION_THREAD) { + datadog_ffi_try("Failed clearing inherited listener state", ddog_sidecar_clear_inherited_listener()); - DDTRACE_G(sidecar) = dd_sidecar_connect(true, true); - if (DDTRACE_G(sidecar)) { + DATADOG_G(sidecar) = dd_sidecar_connect(true, true); + if (DATADOG_G(sidecar)) { LOG(INFO, "Child process reconnected to parent's sidecar listener after fork (child PID=%d, parent=%d)", - (int32_t)getpid(), ddtrace_sidecar_master_pid); + (int32_t)getpid(), datadog_sidecar_master_pid); } else { LOG(INFO, "Parent's sidecar listener not available after fork (child PID=%d, parent=%d), starting new master", - (int32_t)getpid(), ddtrace_sidecar_master_pid); + (int32_t)getpid(), datadog_sidecar_master_pid); - ddtrace_sidecar_master_pid = (int32_t)getpid(); - if (!ddtrace_ffi_try("Failed starting sidecar master listener in child process", - ddog_sidecar_connect_master((int32_t)ddtrace_sidecar_master_pid))) { - if (ddtrace_endpoint) { + datadog_sidecar_master_pid = (int32_t)getpid(); + if (!datadog_ffi_try("Failed starting sidecar master listener in child process", + ddog_sidecar_connect_master((int32_t)datadog_sidecar_master_pid))) { + if (datadog_endpoint) { dd_free_endpoints(); } return; } - DDTRACE_G(sidecar) = dd_sidecar_connect(true, false); - if (!DDTRACE_G(sidecar)) { + DATADOG_G(sidecar) = dd_sidecar_connect(true, false); + if (!DATADOG_G(sidecar)) { LOG(WARN, "Failed to connect to new sidecar master in child process (PID=%d)", (int32_t)getpid()); } } - } else if (ddtrace_sidecar_active_mode == DD_SIDECAR_CONNECTION_SUBPROCESS) { - DDTRACE_G(sidecar) = ddtrace_sidecar_connect(true); - if (!DDTRACE_G(sidecar)) { - if (ddtrace_endpoint) { + } else if (datadog_sidecar_active_mode == DD_SIDECAR_CONNECTION_SUBPROCESS) { + DATADOG_G(sidecar) = datadog_sidecar_connect(true); + if (!DATADOG_G(sidecar)) { + if (datadog_endpoint) { dd_free_endpoints(); } } else { - ddtrace_sidecar_submit_root_span_data(); + datadog_sidecar_submit_root_span_data(); } } - if (DDTRACE_G(sidecar)) { - ddtrace_sidecar_for_signal = DDTRACE_G(sidecar); + if (DATADOG_G(sidecar)) { + datadog_sidecar_for_signal = DATADOG_G(sidecar); } #endif } -void ddtrace_sidecar_ensure_active(void) { - if (DDTRACE_G(sidecar)) { - ddtrace_sidecar_reconnect(&DDTRACE_G(sidecar), ddtrace_sidecar_connect_callback); - } else if (ddtrace_endpoint) { +void datadog_sidecar_ensure_active(void) { + if (DATADOG_G(sidecar)) { + datadog_sidecar_reconnect(&DATADOG_G(sidecar), datadog_sidecar_connect_callback); + } else if (datadog_endpoint) { // First RINIT on this thread: the process-level setup already ran (endpoint is // set), so establish this thread's own connection now. - DDTRACE_G(sidecar) = ddtrace_sidecar_connect(false); - if (DDTRACE_G(sidecar) && !ddtrace_sidecar_for_signal) { - ddtrace_sidecar_for_signal = DDTRACE_G(sidecar); + DATADOG_G(sidecar) = datadog_sidecar_connect(false); + if (DATADOG_G(sidecar) && !datadog_sidecar_for_signal) { + datadog_sidecar_for_signal = DATADOG_G(sidecar); } } } -void ddtrace_sidecar_finalize(bool clear_id) { - if (!DDTRACE_G(sidecar)) { +void datadog_sidecar_finalize(bool clear_id) { + if (!DATADOG_G(sidecar) || !DATADOG_G(request_initialized)) { return; } if (get_global_DD_INSTRUMENTATION_TELEMETRY_ENABLED()) { - ddtrace_telemetry_finalize(); + datadog_telemetry_finalize(); } - tsrm_mutex_lock(DDTRACE_G(sidecar_universal_service_tags_mutex)); - ddog_QueueId queue_id = DDTRACE_G(sidecar_queue_id); - DDTRACE_G(sidecar_queue_id) = 0; - tsrm_mutex_unlock(DDTRACE_G(sidecar_universal_service_tags_mutex)); + tsrm_mutex_lock(DATADOG_G(sidecar_universal_service_tags_mutex)); + ddog_QueueId queue_id = DATADOG_G(sidecar_queue_id); + DATADOG_G(sidecar_queue_id) = 0; + tsrm_mutex_unlock(DATADOG_G(sidecar_universal_service_tags_mutex)); if (clear_id) { - ddtrace_ffi_try("Failed removing application from sidecar", - ddog_sidecar_application_remove(&DDTRACE_G(sidecar), ddtrace_sidecar_instance_id, &queue_id)); + datadog_ffi_try("Failed removing application from sidecar", + ddog_sidecar_application_remove(&DATADOG_G(sidecar), datadog_sidecar_instance_id, &queue_id)); } } -void ddtrace_sidecar_shutdown(void) { - ddtrace_sidecar_for_signal = NULL; +void datadog_sidecar_shutdown(void) { + datadog_sidecar_for_signal = NULL; // In thread mode, drop the main thread's connection before shutting down the // listener to avoid deadlock. GSHUTDOWN owns transport cleanup for all other @@ -541,47 +533,47 @@ void ddtrace_sidecar_shutdown(void) { #else int32_t current_pid = (int32_t)getpid(); #endif - if (ddtrace_sidecar_active_mode == DD_SIDECAR_CONNECTION_THREAD && - ddtrace_sidecar_master_pid != 0 && - current_pid == ddtrace_sidecar_master_pid) { + if (datadog_sidecar_active_mode == DD_SIDECAR_CONNECTION_THREAD && + datadog_sidecar_master_pid != 0 && + current_pid == datadog_sidecar_master_pid) { - if (DDTRACE_G(sidecar)) { - ddog_sidecar_transport_drop(DDTRACE_G(sidecar)); - DDTRACE_G(sidecar) = NULL; + if (DATADOG_G(sidecar)) { + ddog_sidecar_transport_drop(DATADOG_G(sidecar)); + DATADOG_G(sidecar) = NULL; } - ddtrace_ffi_try("Failed shutting down master listener", + datadog_ffi_try("Failed shutting down master listener", ddog_sidecar_shutdown_master_listener()); } // Process-level instance ID (dropped once at MSHUTDOWN, not per-thread). - if (ddtrace_sidecar_instance_id) { - ddog_sidecar_instanceId_drop(ddtrace_sidecar_instance_id); - ddtrace_sidecar_instance_id = NULL; + if (datadog_sidecar_instance_id) { + ddog_sidecar_instanceId_drop(datadog_sidecar_instance_id); + datadog_sidecar_instance_id = NULL; } - if (ddtrace_endpoint) { + if (datadog_endpoint) { dd_free_endpoints(); } - ddtrace_sidecar_active_mode = DD_SIDECAR_CONNECTION_NONE; + datadog_sidecar_active_mode = DD_SIDECAR_CONNECTION_NONE; } -void ddtrace_force_new_instance_id(void) { - if (ddtrace_sidecar_instance_id) { - ddog_sidecar_instanceId_drop(ddtrace_sidecar_instance_id); - ddtrace_set_resettable_sidecar_globals(); +void datadog_force_new_instance_id(void) { + if (datadog_sidecar_instance_id) { + ddog_sidecar_instanceId_drop(datadog_sidecar_instance_id); + dd_set_resettable_sidecar_globals(); } } -ddog_Endpoint *ddtrace_sidecar_agent_endpoint(void) { +ddog_Endpoint *datadog_sidecar_agent_endpoint(void) { ddog_Endpoint *agent_endpoint; if (get_global_DD_TRACE_AGENTLESS() && ZSTR_LEN(get_global_DD_API_KEY())) { agent_endpoint = ddog_endpoint_from_api_key(dd_zend_string_to_CharSlice(get_global_DD_API_KEY())); } else { - char *agent_url = ddtrace_agent_url(); - agent_endpoint = ddtrace_parse_agent_url((ddog_CharSlice) {.ptr = agent_url, .len = strlen(agent_url)}); + char *agent_url = datadog_agent_url(); + agent_endpoint = datadog_parse_agent_url((ddog_CharSlice) {.ptr = agent_url, .len = strlen(agent_url)}); if (!agent_endpoint) { LOG(ERROR, "Invalid DD_TRACE_AGENT_URL: %s. A proper agent URL must be unix:///path/to/agent.sock or http://hostname:port/.", agent_url); } @@ -595,7 +587,7 @@ ddog_Endpoint *ddtrace_sidecar_agent_endpoint(void) { return agent_endpoint; } -void ddtrace_sidecar_push_tag(ddog_Vec_Tag *vec, ddog_CharSlice key, ddog_CharSlice value) { +void datadog_sidecar_push_tag(ddog_Vec_Tag *vec, ddog_CharSlice key, ddog_CharSlice value) { ddog_Vec_Tag_PushResult tag_result = ddog_Vec_Tag_push(vec, key, value); if (tag_result.tag == DDOG_VEC_TAG_PUSH_RESULT_ERR) { zend_string *msg = dd_CharSlice_to_zend_string(ddog_Error_message(&tag_result.err)); @@ -605,37 +597,37 @@ void ddtrace_sidecar_push_tag(ddog_Vec_Tag *vec, ddog_CharSlice key, ddog_CharSl } } -void ddtrace_sidecar_push_tags(ddog_Vec_Tag *vec, zval *tags) { +void datadog_sidecar_push_tags(ddog_Vec_Tag *vec, zval *tags) { // Global tags (https://github.com/DataDog/php-datadogstatsd/blob/0efdd1c38f6d3dd407efbb899ad1fd2e5cd18085/src/DogStatsd.php#L113-L125) ddtrace_span_data *span = ddtrace_active_span(); zend_string *env; if (span) { - env = ddtrace_convert_to_str(&span->property_env); + env = datadog_convert_to_str(&span->property_env); } else { env = zend_string_copy(get_DD_ENV()); } if (ZSTR_LEN(env) > 0) { - ddtrace_sidecar_push_tag(vec, DDOG_CHARSLICE_C("env"), dd_zend_string_to_CharSlice(env)); + datadog_sidecar_push_tag(vec, DDOG_CHARSLICE_C("env"), dd_zend_string_to_CharSlice(env)); } zend_string_release(env); zend_string *service = ddtrace_active_service_name(); if (ZSTR_LEN(service) > 0) { - ddtrace_sidecar_push_tag(vec, DDOG_CHARSLICE_C("service"), dd_zend_string_to_CharSlice(service)); + datadog_sidecar_push_tag(vec, DDOG_CHARSLICE_C("service"), dd_zend_string_to_CharSlice(service)); } zend_string_release(service); zend_string *version; if (span) { - version = ddtrace_convert_to_str(&span->property_version); + version = datadog_convert_to_str(&span->property_version); } else { version = zend_string_copy(get_DD_VERSION()); } if (ZSTR_LEN(version) > 0) { - ddtrace_sidecar_push_tag(vec, DDOG_CHARSLICE_C("version"), dd_zend_string_to_CharSlice(version)); + datadog_sidecar_push_tag(vec, DDOG_CHARSLICE_C("version"), dd_zend_string_to_CharSlice(version)); } zend_string_release(version); if (ZSTR_LEN(get_DD_TRACE_AGENT_TEST_SESSION_TOKEN())) { - ddtrace_sidecar_push_tag(vec, DDOG_CHARSLICE_C("x-datadog-test-session-token"), dd_zend_string_to_CharSlice(get_DD_TRACE_AGENT_TEST_SESSION_TOKEN())); + datadog_sidecar_push_tag(vec, DDOG_CHARSLICE_C("x-datadog-test-session-token"), dd_zend_string_to_CharSlice(get_DD_TRACE_AGENT_TEST_SESSION_TOKEN())); } // Specific tags @@ -650,78 +642,78 @@ void ddtrace_sidecar_push_tags(ddog_Vec_Tag *vec, zval *tags) { continue; } zval value_str; - ddtrace_convert_to_string(&value_str, tag_val); - ddtrace_sidecar_push_tag(vec, dd_zend_string_to_CharSlice(key), dd_zend_string_to_CharSlice(Z_STR(value_str))); + datadog_convert_to_string(&value_str, tag_val); + datadog_sidecar_push_tag(vec, dd_zend_string_to_CharSlice(key), dd_zend_string_to_CharSlice(Z_STR(value_str))); zend_string_release(Z_STR(value_str)); } ZEND_HASH_FOREACH_END(); } -void ddtrace_sidecar_dogstatsd_count(zend_string *metric, zend_long value, zval *tags) { - if (!DDTRACE_G(sidecar) || !get_DD_INTEGRATION_METRICS_ENABLED()) { +void datadog_sidecar_dogstatsd_count(zend_string *metric, zend_long value, zval *tags) { + if (!DATADOG_G(sidecar)) { return; } ddog_Vec_Tag vec = ddog_Vec_Tag_new(); - ddtrace_sidecar_push_tags(&vec, tags); - ddtrace_ffi_try("Failed sending dogstatsd count metric", - ddog_sidecar_dogstatsd_count(&DDTRACE_G(sidecar), ddtrace_sidecar_instance_id, dd_zend_string_to_CharSlice(metric), value, &vec)); + datadog_sidecar_push_tags(&vec, tags); + datadog_ffi_try("Failed sending dogstatsd count metric", + ddog_sidecar_dogstatsd_count(&DATADOG_G(sidecar), datadog_sidecar_instance_id, dd_zend_string_to_CharSlice(metric), value, &vec)); ddog_Vec_Tag_drop(vec); } -void ddtrace_sidecar_dogstatsd_distribution(zend_string *metric, double value, zval *tags) { - if (!DDTRACE_G(sidecar) || !get_DD_INTEGRATION_METRICS_ENABLED()) { +void datadog_sidecar_dogstatsd_distribution(zend_string *metric, double value, zval *tags) { + if (!DATADOG_G(sidecar)) { return; } ddog_Vec_Tag vec = ddog_Vec_Tag_new(); - ddtrace_sidecar_push_tags(&vec, tags); - ddtrace_ffi_try("Failed sending dogstatsd distribution metric", - ddog_sidecar_dogstatsd_distribution(&DDTRACE_G(sidecar), ddtrace_sidecar_instance_id, dd_zend_string_to_CharSlice(metric), value, &vec)); + datadog_sidecar_push_tags(&vec, tags); + datadog_ffi_try("Failed sending dogstatsd distribution metric", + ddog_sidecar_dogstatsd_distribution(&DATADOG_G(sidecar), datadog_sidecar_instance_id, dd_zend_string_to_CharSlice(metric), value, &vec)); ddog_Vec_Tag_drop(vec); } -void ddtrace_sidecar_dogstatsd_gauge(zend_string *metric, double value, zval *tags) { - if (!DDTRACE_G(sidecar) || !get_DD_INTEGRATION_METRICS_ENABLED()) { +void datadog_sidecar_dogstatsd_gauge(zend_string *metric, double value, zval *tags) { + if (!DATADOG_G(sidecar)) { return; } ddog_Vec_Tag vec = ddog_Vec_Tag_new(); - ddtrace_sidecar_push_tags(&vec, tags); - ddtrace_ffi_try("Failed sending dogstatsd gauge metric", - ddog_sidecar_dogstatsd_gauge(&DDTRACE_G(sidecar), ddtrace_sidecar_instance_id, dd_zend_string_to_CharSlice(metric), value, &vec)); + datadog_sidecar_push_tags(&vec, tags); + datadog_ffi_try("Failed sending dogstatsd gauge metric", + ddog_sidecar_dogstatsd_gauge(&DATADOG_G(sidecar), datadog_sidecar_instance_id, dd_zend_string_to_CharSlice(metric), value, &vec)); ddog_Vec_Tag_drop(vec); } -void ddtrace_sidecar_dogstatsd_histogram(zend_string *metric, double value, zval *tags) { - if (!DDTRACE_G(sidecar) || !get_DD_INTEGRATION_METRICS_ENABLED()) { +void datadog_sidecar_dogstatsd_histogram(zend_string *metric, double value, zval *tags) { + if (!DATADOG_G(sidecar)) { return; } ddog_Vec_Tag vec = ddog_Vec_Tag_new(); - ddtrace_sidecar_push_tags(&vec, tags); - ddtrace_ffi_try("Failed sending dogstatsd histogram metric", - ddog_sidecar_dogstatsd_histogram(&DDTRACE_G(sidecar), ddtrace_sidecar_instance_id, dd_zend_string_to_CharSlice(metric), value, &vec)); + datadog_sidecar_push_tags(&vec, tags); + datadog_ffi_try("Failed sending dogstatsd histogram metric", + ddog_sidecar_dogstatsd_histogram(&DATADOG_G(sidecar), datadog_sidecar_instance_id, dd_zend_string_to_CharSlice(metric), value, &vec)); ddog_Vec_Tag_drop(vec); } -void ddtrace_sidecar_dogstatsd_set(zend_string *metric, zend_long value, zval *tags) { - if (!DDTRACE_G(sidecar) || !get_DD_INTEGRATION_METRICS_ENABLED()) { +void datadog_sidecar_dogstatsd_set(zend_string *metric, zend_long value, zval *tags) { + if (!DATADOG_G(sidecar)) { return; } ddog_Vec_Tag vec = ddog_Vec_Tag_new(); - ddtrace_sidecar_push_tags(&vec, tags); - ddtrace_ffi_try("Failed sending dogstatsd set metric", - ddog_sidecar_dogstatsd_set(&DDTRACE_G(sidecar), ddtrace_sidecar_instance_id, dd_zend_string_to_CharSlice(metric), value, &vec)); + datadog_sidecar_push_tags(&vec, tags); + datadog_ffi_try("Failed sending dogstatsd set metric", + ddog_sidecar_dogstatsd_set(&DATADOG_G(sidecar), datadog_sidecar_instance_id, dd_zend_string_to_CharSlice(metric), value, &vec)); ddog_Vec_Tag_drop(vec); } -void ddtrace_sidecar_submit_root_span_data_direct_defaults(ddog_SidecarTransport **transport, ddtrace_root_span_data *root) { - ddtrace_sidecar_submit_root_span_data_direct(transport, root, get_DD_SERVICE(), get_DD_ENV(), get_DD_VERSION()); +void datadog_sidecar_submit_root_span_data_direct_defaults(ddog_SidecarTransport **transport, ddtrace_root_span_data *root) { + datadog_sidecar_submit_root_span_data_direct(transport, root, get_DD_SERVICE(), get_DD_ENV(), get_DD_VERSION()); } -void ddtrace_sidecar_submit_root_span_data_direct(ddog_SidecarTransport **transport, ddtrace_root_span_data *root, zend_string *cfg_service, zend_string *cfg_env, zend_string *cfg_version) { +void datadog_sidecar_submit_root_span_data_direct(ddog_SidecarTransport **transport, ddtrace_root_span_data *root, zend_string *cfg_service, zend_string *cfg_env, zend_string *cfg_version) { if (!*transport) { return; } @@ -775,127 +767,109 @@ void ddtrace_sidecar_submit_root_span_data_direct(ddog_SidecarTransport **transp } ddog_CharSlice version_slice = dd_zend_string_to_CharSlice(version_string); - const ddog_Vec_Tag *process_tags = ddtrace_process_tags_get_vec(); + const ddog_Vec_Tag *process_tags = datadog_process_tags_get_vec(); bool changed = true; - if (DDTRACE_G(remote_config_state)) { - changed = ddog_remote_configs_service_env_change(DDTRACE_G(remote_config_state), service_slice, env_slice, version_slice, &DDTRACE_G(active_global_tags), process_tags); + if (DATADOG_G(remote_config_state)) { + changed = ddog_remote_configs_service_env_change(DATADOG_G(remote_config_state), service_slice, env_slice, version_slice, &DATADOG_G(active_global_tags), process_tags); } // Force resend on reconnect - if (changed || !root || *transport != DDTRACE_G(sidecar)) { - tsrm_mutex_lock(DDTRACE_G(sidecar_universal_service_tags_mutex)); - if (DDTRACE_G(last_service_name)) { - zend_string_release(DDTRACE_G(last_service_name)); + if (changed || !root || *transport != DATADOG_G(sidecar)) { + tsrm_mutex_lock(DATADOG_G(sidecar_universal_service_tags_mutex)); + if (DATADOG_G(last_service_name)) { + zend_string_release(DATADOG_G(last_service_name)); } - DDTRACE_G(last_service_name) = service_string; - if (DDTRACE_G(last_env_name)) { - zend_string_release(DDTRACE_G(last_env_name)); + DATADOG_G(last_service_name) = service_string; + if (DATADOG_G(last_env_name)) { + zend_string_release(DATADOG_G(last_env_name)); } - DDTRACE_G(last_env_name) = env_string; - if (DDTRACE_G(last_version)) { - zend_string_release(DDTRACE_G(last_version)); + DATADOG_G(last_env_name) = env_string; + if (DATADOG_G(last_version)) { + zend_string_release(DATADOG_G(last_version)); } - DDTRACE_G(last_version) = version_string; - tsrm_mutex_unlock(DDTRACE_G(sidecar_universal_service_tags_mutex)); + DATADOG_G(last_version) = version_string; + tsrm_mutex_unlock(DATADOG_G(sidecar_universal_service_tags_mutex)); // This must not be in mutex, as a reconnect may happen here - ddtrace_ffi_try("Failed sending config data", - ddog_sidecar_set_universal_service_tags(transport, ddtrace_sidecar_instance_id, &DDTRACE_G(sidecar_queue_id), service_slice, env_slice, version_slice, &DDTRACE_G(active_global_tags), ddtrace_dynamic_instrumentation_state())); + datadog_ffi_try("Failed sending config data", + ddog_sidecar_set_universal_service_tags(transport, datadog_sidecar_instance_id, &DATADOG_G(sidecar_queue_id), service_slice, env_slice, version_slice, &DATADOG_G(active_global_tags), ddtrace_dynamic_instrumentation_state())); } else { zend_string_release(service_string); zend_string_release(env_string); zend_string_release(version_string); } - if ((changed || !root) && DDTRACE_G(telemetry_buffer)) { - ddtrace_ffi_try("Failed flushing filtered telemetry buffer", - ddog_sidecar_telemetry_filter_flush(transport, ddtrace_sidecar_instance_id, &DDTRACE_G(sidecar_queue_id), ddtrace_telemetry_buffer(), ddtrace_telemetry_cache(), service_slice, env_slice)); + if ((changed || !root) && DATADOG_G(telemetry_buffer)) { + datadog_ffi_try("Failed flushing filtered telemetry buffer", + ddog_sidecar_telemetry_filter_flush(transport, datadog_sidecar_instance_id, &DATADOG_G(sidecar_queue_id), datadog_telemetry_buffer(), datadog_telemetry_cache(), service_slice, env_slice)); } - if (DDTRACE_G(remote_config_state)) { + if (DATADOG_G(remote_config_state)) { // Must happen after ddog_sidecar_set_universal_service_tags (session state fully initialized) - ddog_process_remote_configs(DDTRACE_G(remote_config_state)); + ddog_process_remote_configs(DATADOG_G(remote_config_state)); } } -void ddtrace_sidecar_submit_root_span_data(void) { +void datadog_sidecar_submit_root_span_data(void) { if (DDTRACE_G(active_stack)) { ddtrace_root_span_data *root = DDTRACE_G(active_stack)->root_span; if (root) { - ddtrace_sidecar_submit_root_span_data_direct_defaults(&DDTRACE_G(sidecar), root); + datadog_sidecar_submit_root_span_data_direct_defaults(&DATADOG_G(sidecar), root); } } } -void ddtrace_sidecar_send_debugger_data(ddog_Vec_DebuggerPayload payloads) { - LOGEV(DEBUG, UNUSED(log); ddog_log_debugger_data(&payloads);); - ddog_sidecar_send_debugger_data(&DDTRACE_G(sidecar), ddtrace_sidecar_instance_id, DDTRACE_G(sidecar_queue_id), payloads); -} - -void ddtrace_sidecar_send_debugger_datum(ddog_DebuggerPayload *payload) { - LOGEV(DEBUG, UNUSED(log); ddog_log_debugger_datum(payload);); - ddog_sidecar_send_debugger_datum(&DDTRACE_G(sidecar), ddtrace_sidecar_instance_id, DDTRACE_G(sidecar_queue_id), payload); -} - -void ddtrace_sidecar_activate(void) { - DDTRACE_G(sidecar_queue_id) = ddog_sidecar_queueId_generate(); +void datadog_sidecar_activate(void) { + DATADOG_G(sidecar_queue_id) = ddog_sidecar_queueId_generate(); - DDTRACE_G(active_global_tags) = ddog_Vec_Tag_new(); + DATADOG_G(active_global_tags) = ddog_Vec_Tag_new(); zend_string *tag; zval *value; ZEND_HASH_FOREACH_STR_KEY_VAL(get_DD_TAGS(), tag, value) { - UNUSED(ddog_Vec_Tag_push(&DDTRACE_G(active_global_tags), dd_zend_string_to_CharSlice(tag), dd_zend_string_to_CharSlice(Z_STR_P(value)))); + UNUSED(ddog_Vec_Tag_push(&DATADOG_G(active_global_tags), dd_zend_string_to_CharSlice(tag), dd_zend_string_to_CharSlice(Z_STR_P(value)))); } ZEND_HASH_FOREACH_END(); } -void ddtrace_sidecar_rinit(void) { +void datadog_sidecar_rinit(void) { if (get_DD_TRACE_GIT_METADATA_ENABLED()) { - zval git_object; - ZVAL_UNDEF(&git_object); - ddtrace_inject_git_metadata(&git_object); - if (Z_TYPE(git_object) == IS_OBJECT) { - ddtrace_git_metadata *git_metadata = (ddtrace_git_metadata *) Z_OBJ(git_object); - if (Z_TYPE(git_metadata->property_commit) == IS_STRING) { - UNUSED(ddog_Vec_Tag_push(&DDTRACE_G(active_global_tags), DDOG_CHARSLICE_C("git.commit.sha"), - dd_zend_string_to_CharSlice(Z_STR(git_metadata->property_commit)))); + zend_string *commit = NULL, *repo = NULL; + if (datadog_get_git_metadata(&commit, &repo)) { + if (commit) { + UNUSED(ddog_Vec_Tag_push(&DATADOG_G(active_global_tags), DDOG_CHARSLICE_C("git.commit.sha"), + dd_zend_string_to_CharSlice(commit))); } - if (Z_TYPE(git_metadata->property_repository) == IS_STRING) { - UNUSED(ddog_Vec_Tag_push(&DDTRACE_G(active_global_tags), DDOG_CHARSLICE_C("git.repository_url"), - dd_zend_string_to_CharSlice(Z_STR(git_metadata->property_repository)))); + if (repo) { + UNUSED(ddog_Vec_Tag_push(&DATADOG_G(active_global_tags), DDOG_CHARSLICE_C("git.repository_url"), + dd_zend_string_to_CharSlice(repo))); } - OBJ_RELEASE(&git_metadata->std); } } - ddtrace_sidecar_submit_root_span_data_direct_defaults(&DDTRACE_G(sidecar), NULL); + datadog_sidecar_submit_root_span_data_direct_defaults(&DATADOG_G(sidecar), NULL); } -void ddtrace_sidecar_rshutdown(void) { - ddog_Vec_Tag_drop(DDTRACE_G(active_global_tags)); +void datadog_sidecar_rshutdown(void) { + ddog_Vec_Tag_drop(DATADOG_G(active_global_tags)); } -void ddtrace_sidecar_gshutdown(zend_ddtrace_globals *ddtrace_globals) { - // NOTE: do not use DDTRACE_G() in this function; it may be called from the - // main thread via ts_free_id() - if (ddtrace_globals->sidecar) { - if (ddtrace_globals->sidecar == ddtrace_sidecar_for_signal) { - ddtrace_sidecar_for_signal = NULL; +void datadog_sidecar_gshutdown(zend_datadog_globals *datadog_globals) { + if (datadog_globals->sidecar) { + if (datadog_globals->sidecar == datadog_sidecar_for_signal) { + datadog_sidecar_for_signal = NULL; } - // Drain any accumulated background-sender metrics before the transport goes away. - ddtrace_telemetry_flush_bgs_metrics_final(ddtrace_globals); - ddog_sidecar_transport_drop(ddtrace_globals->sidecar); - ddtrace_globals->sidecar = NULL; + ddog_sidecar_transport_drop(datadog_globals->sidecar); + datadog_globals->sidecar = NULL; } } -bool ddtrace_alter_test_session_token(zval *old_value, zval *new_value, zend_string *new_str) { +bool datadog_alter_test_session_token(zval *old_value, zval *new_value, zend_string *new_str) { UNUSED(old_value, new_str); - if (DDTRACE_G(sidecar)) { - ddog_endpoint_set_test_token(ddtrace_endpoint, dd_zend_string_to_CharSlice(Z_STR_P(new_value))); - ddtrace_ffi_try("Failed updating test session token", - ddog_sidecar_set_test_session_token(&DDTRACE_G(sidecar), dd_zend_string_to_CharSlice(Z_STR_P(new_value)))); + if (DATADOG_G(sidecar)) { + ddog_endpoint_set_test_token(datadog_endpoint, dd_zend_string_to_CharSlice(Z_STR_P(new_value))); + datadog_ffi_try("Failed updating test session token", + ddog_sidecar_set_test_session_token(&DATADOG_G(sidecar), dd_zend_string_to_CharSlice(Z_STR_P(new_value)))); } #ifndef _WIN32 ddtrace_coms_set_test_session_token(Z_STRVAL_P(new_value), Z_STRLEN_P(new_value)); @@ -904,25 +878,25 @@ bool ddtrace_alter_test_session_token(zval *old_value, zval *new_value, zend_str } bool ddtrace_exception_debugging_is_active(void) { - return DDTRACE_G(sidecar) && ddtrace_sidecar_instance_id && get_DD_EXCEPTION_REPLAY_ENABLED(); + return DATADOG_G(sidecar) && datadog_sidecar_instance_id && get_DD_EXCEPTION_REPLAY_ENABLED(); } -ddog_crasht_Metadata ddtrace_setup_crashtracking_metadata(ddog_Vec_Tag *tags) { - ddtrace_sidecar_push_tags(tags, NULL); +ddog_crasht_Metadata datadog_setup_crashtracking_metadata(ddog_Vec_Tag *tags) { + datadog_sidecar_push_tags(tags, NULL); - ddtrace_sidecar_push_tag(tags, DDOG_CHARSLICE_C("is_crash"), DDOG_CHARSLICE_C("true")); - ddtrace_sidecar_push_tag(tags, DDOG_CHARSLICE_C("severity"), DDOG_CHARSLICE_C("crash")); - ddtrace_sidecar_push_tag(tags, DDOG_CHARSLICE_C("library_version"), DDOG_CHARSLICE_C(PHP_DDTRACE_VERSION)); - ddtrace_sidecar_push_tag(tags, DDOG_CHARSLICE_C("language"), DDOG_CHARSLICE_C("php")); - ddtrace_sidecar_push_tag(tags, DDOG_CHARSLICE_C("runtime"), DDOG_CHARSLICE_C("php")); - ddtrace_sidecar_push_tag(tags, DDOG_CHARSLICE_C("runtime-id"), (ddog_CharSlice) {.ptr = (char *) ddtrace_formatted_session_id, .len = sizeof(ddtrace_formatted_session_id)}); + datadog_sidecar_push_tag(tags, DDOG_CHARSLICE_C("is_crash"), DDOG_CHARSLICE_C("true")); + datadog_sidecar_push_tag(tags, DDOG_CHARSLICE_C("severity"), DDOG_CHARSLICE_C("crash")); + datadog_sidecar_push_tag(tags, DDOG_CHARSLICE_C("library_version"), DDOG_CHARSLICE_C(PHP_DDTRACE_VERSION)); + datadog_sidecar_push_tag(tags, DDOG_CHARSLICE_C("language"), DDOG_CHARSLICE_C("php")); + datadog_sidecar_push_tag(tags, DDOG_CHARSLICE_C("runtime"), DDOG_CHARSLICE_C("php")); + datadog_sidecar_push_tag(tags, DDOG_CHARSLICE_C("runtime-id"), (ddog_CharSlice) {.ptr = (char *) datadog_formatted_session_id, .len = sizeof(datadog_formatted_session_id)}); const char *runtime_version = zend_get_module_version("Reflection"); - ddtrace_sidecar_push_tag(tags, DDOG_CHARSLICE_C("runtime_version"), (ddog_CharSlice) {.ptr = (char *) runtime_version, .len = strlen(runtime_version)}); + datadog_sidecar_push_tag(tags, DDOG_CHARSLICE_C("runtime_version"), (ddog_CharSlice) {.ptr = (char *) runtime_version, .len = strlen(runtime_version)}); - zend_string *process_tags = ddtrace_process_tags_get_serialized(); + zend_string *process_tags = datadog_process_tags_get_serialized(); if (ZSTR_LEN(process_tags)) { - ddtrace_sidecar_push_tag(tags, DDOG_CHARSLICE_C("process_tags"), (ddog_CharSlice) {.ptr = ZSTR_VAL(process_tags), .len = ZSTR_LEN(process_tags)}); + datadog_sidecar_push_tag(tags, DDOG_CHARSLICE_C("process_tags"), (ddog_CharSlice) {.ptr = ZSTR_VAL(process_tags), .len = ZSTR_LEN(process_tags)}); } return (ddog_crasht_Metadata){ diff --git a/ext/sidecar.h b/ext/sidecar.h index 8db3a57db5f..a7ed1697467 100644 --- a/ext/sidecar.h +++ b/ext/sidecar.h @@ -1,10 +1,10 @@ -#ifndef DD_SIDECAR_H -#define DD_SIDECAR_H +#ifndef DATADOG_SIDECAR_H +#define DATADOG_SIDECAR_H #include #include #include -#include "ddtrace_export.h" -#include "ddtrace.h" +#include "datadog_export.h" +#include #include "zend_string.h" // Connection mode tracking @@ -14,92 +14,64 @@ typedef enum { DD_SIDECAR_CONNECTION_THREAD = 2 } dd_sidecar_active_mode_t; -static inline bool ddtrace_is_empty_session_id(uint8_t id[36]) { +static inline bool datadog_is_empty_session_id(uint8_t id[36]) { return memcmp(id, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 36) == 0; } -// ddtrace_sidecar_instance_id is a process global — one identity per PHP process. -extern struct ddog_InstanceId *ddtrace_sidecar_instance_id; +// datadog_sidecar_instance_id is a process global — one identity per PHP process. +extern struct ddog_InstanceId *datadog_sidecar_instance_id; // Best-effort pointer used only by the signal handler (SIGTERM/SIGINT), which cannot call // TSRMLS_FETCH() safely. Set to the first thread's connection; never cleared until MSHUTDOWN. // Not atomic: concurrent shutdown is a pre-existing best-effort race for signal handlers. -extern ddog_SidecarTransport *ddtrace_sidecar_for_signal; -extern ddog_Endpoint *ddtrace_endpoint; -extern dd_sidecar_active_mode_t ddtrace_sidecar_active_mode; -extern int32_t ddtrace_sidecar_master_pid; +extern ddog_SidecarTransport *datadog_sidecar_for_signal; +extern ddog_Endpoint *datadog_endpoint; +extern dd_sidecar_active_mode_t datadog_sidecar_active_mode; +extern int32_t datadog_sidecar_master_pid; -DDTRACE_PUBLIC const uint8_t *ddtrace_get_formatted_session_id(void); +DATADOG_PUBLIC const uint8_t *datadog_get_formatted_session_id(void); struct telemetry_rc_info { const char *rc_path; zend_string *service_name; zend_string *env_name; // caller does not own the data }; -DDTRACE_PUBLIC struct telemetry_rc_info ddtrace_get_telemetry_rc_info(void); +DATADOG_PUBLIC struct telemetry_rc_info datadog_get_telemetry_rc_info(void); // Connection functions -ddog_SidecarTransport *ddtrace_sidecar_connect(bool is_fork); +ddog_SidecarTransport *datadog_sidecar_connect(bool is_fork); // Lifecycle functions -void ddtrace_sidecar_minit(void); -void ddtrace_sidecar_setup(bool appsec_activation, bool appsec_config); -void ddtrace_sidecar_handle_fork(void); -bool ddtrace_sidecar_maybe_enable_appsec(bool *appsec_activation, bool *appsec_config); -bool ddtrace_sidecar_should_enable(bool *appsec_activation, bool *appsec_config); -void ddtrace_sidecar_ensure_active(void); -void ddtrace_sidecar_update_process_tags(void); -void ddtrace_sidecar_finalize(bool clear_id); -void ddtrace_sidecar_shutdown(void); -void ddtrace_force_new_instance_id(void); -void ddtrace_sidecar_submit_root_span_data(void); -void ddtrace_sidecar_push_tag(ddog_Vec_Tag *vec, ddog_CharSlice key, ddog_CharSlice value); -void ddtrace_sidecar_push_tags(ddog_Vec_Tag *vec, zval *tags); -ddog_Endpoint *ddtrace_sidecar_agent_endpoint(void); -void ddtrace_sidecar_submit_root_span_data_direct_defaults(ddog_SidecarTransport **transport, ddtrace_root_span_data *root); -void ddtrace_sidecar_submit_root_span_data_direct(ddog_SidecarTransport **transport, ddtrace_root_span_data *root, zend_string *cfg_service, zend_string *cfg_env, zend_string *cfg_version); - -void ddtrace_sidecar_send_debugger_data(ddog_Vec_DebuggerPayload payloads); -void ddtrace_sidecar_send_debugger_datum(ddog_DebuggerPayload *payload); - -void ddtrace_sidecar_activate(void); -void ddtrace_sidecar_rinit(void); -void ddtrace_sidecar_rshutdown(void); -void ddtrace_sidecar_gshutdown(zend_ddtrace_globals *ddtrace_globals); - -void ddtrace_sidecar_dogstatsd_count(zend_string *metric, zend_long value, zval *tags); -void ddtrace_sidecar_dogstatsd_distribution(zend_string *metric, double value, zval *tags); -void ddtrace_sidecar_dogstatsd_gauge(zend_string *metric, double value, zval *tags); -void ddtrace_sidecar_dogstatsd_histogram(zend_string *metric, double value, zval *tags); -void ddtrace_sidecar_dogstatsd_set(zend_string *metric, zend_long value, zval *tags); - -bool ddtrace_alter_test_session_token(zval *old_value, zval *new_value, zend_string *new_str); - -static inline ddog_CharSlice dd_zend_string_to_CharSlice(zend_string *str) { - if (str == NULL) { - return (ddog_CharSlice){ .len = 0, .ptr = NULL }; - } - return (ddog_CharSlice){ .len = str->len, .ptr = str->val }; -} - -static inline ddog_CharSlice dd_zai_string_to_CharSlice(zai_string str) { - return (ddog_CharSlice){ .len = str.len, .ptr = str.ptr }; -} - -static inline zend_string *dd_CharSlice_to_zend_string(ddog_CharSlice slice) { - return zend_string_init(slice.ptr, slice.len, 0); -} - -static inline bool ddtrace_ffi_try(const char *msg, ddog_MaybeError maybe_error) { - if (maybe_error.tag == DDOG_OPTION_ERROR_SOME_ERROR) { - ddog_CharSlice error = ddog_Error_message(&maybe_error.some); - LOG(ERROR, "%s: %.*s", msg, (int) error.len, error.ptr); - ddog_MaybeError_drop(maybe_error); - return false; - } - return true; -} +void datadog_sidecar_minit(void); +void datadog_sidecar_setup(bool appsec_activation, bool appsec_config); +void datadog_sidecar_handle_fork(void); +bool datadog_sidecar_should_enable(bool *appsec_activation, bool *appsec_config); +void datadog_sidecar_configure_appsec(bool *appsec_activation, bool *appsec_config); +void datadog_sidecar_ensure_active(void); +void datadog_sidecar_update_process_tags(void); +void datadog_sidecar_finalize(bool clear_id); +void datadog_sidecar_shutdown(void); +void datadog_force_new_instance_id(void); +void datadog_sidecar_submit_root_span_data(void); +void datadog_sidecar_push_tag(ddog_Vec_Tag *vec, ddog_CharSlice key, ddog_CharSlice value); +void datadog_sidecar_push_tags(ddog_Vec_Tag *vec, zval *tags); +ddog_Endpoint *datadog_sidecar_agent_endpoint(void); +void datadog_sidecar_submit_root_span_data_direct_defaults(ddog_SidecarTransport **transport, ddtrace_root_span_data *root); +void datadog_sidecar_submit_root_span_data_direct(ddog_SidecarTransport **transport, ddtrace_root_span_data *root, zend_string *cfg_service, zend_string *cfg_env, zend_string *cfg_version); + +void datadog_sidecar_activate(void); +void datadog_sidecar_rinit(void); +void datadog_sidecar_rshutdown(void); +void datadog_sidecar_gshutdown(zend_datadog_globals *datadog_globals); + +void datadog_sidecar_dogstatsd_count(zend_string *metric, zend_long value, zval *tags); +void datadog_sidecar_dogstatsd_distribution(zend_string *metric, double value, zval *tags); +void datadog_sidecar_dogstatsd_gauge(zend_string *metric, double value, zval *tags); +void datadog_sidecar_dogstatsd_histogram(zend_string *metric, double value, zval *tags); +void datadog_sidecar_dogstatsd_set(zend_string *metric, zend_long value, zval *tags); + +bool datadog_alter_test_session_token(zval *old_value, zval *new_value, zend_string *new_str); bool ddtrace_exception_debugging_is_active(void); -ddog_crasht_Metadata ddtrace_setup_crashtracking_metadata(ddog_Vec_Tag *tags); +ddog_crasht_Metadata datadog_setup_crashtracking_metadata(ddog_Vec_Tag *tags); -#endif // DD_SIDECAR_H +#endif // DATADOG_SIDECAR_H diff --git a/ext/signals.c b/ext/signals.c index cb5b3c797b1..8ee13756509 100644 --- a/ext/signals.c +++ b/ext/signals.c @@ -3,10 +3,10 @@ #include "crashtracking_frames.h" #ifdef HAVE_CONFIG_H -#include "config.h" +#include #endif -#include "php_config.h" +#include #if HAVE_SIGACTION @@ -15,13 +15,13 @@ #include #include "configuration.h" -#include "ddtrace.h" +#include "datadog.h" +#include "ffi_utils.h" #include "sidecar.h" -#include "auto_flush.h" -#include "ext/version.h" +#include "version.h" #include #include "logging.h" -#undef ddtrace_bgs_logf +#undef datadog_signal_safe_logf #include #include @@ -33,12 +33,12 @@ #endif #if defined HAVE_EXECINFO_H && defined backtrace_size_t && defined HAVE_BACKTRACE -#define DDTRACE_HAVE_BACKTRACE 1 +#define DATADOG_HAVE_BACKTRACE 1 #else -#define DDTRACE_HAVE_BACKTRACE 0 +#define DATADOG_HAVE_BACKTRACE 0 #endif -#if DDTRACE_HAVE_BACKTRACE +#if DATADOG_HAVE_BACKTRACE #include #endif @@ -57,38 +57,39 @@ static char crashtracker_socket_path[100] = {0}; static char *dd_signal_async_stack; static size_t dd_signal_async_stack_size; -ZEND_EXTERN_MODULE_GLOBALS(ddtrace); +ZEND_EXTERN_MODULE_GLOBALS(datadog); static void dd_sigsegv_handler(int sig) { - if (!DDTRACE_G(backtrace_handler_already_run)) { - DDTRACE_G(backtrace_handler_already_run) = true; - ddtrace_bgs_logf("[crash] Segmentation fault encountered"); + if (!DATADOG_G(backtrace_handler_already_run)) { + DATADOG_G(backtrace_handler_already_run) = true; + datadog_signal_safe_logf("[crash] Segmentation fault encountered"); -#if HAVE_SIGACTION +#if HAVE_SIGACTION && defined(DDTRACE) bool health_metrics_enabled = get_DD_TRACE_HEALTH_METRICS_ENABLED(); if (health_metrics_enabled) { + // TODO: emit in sidecar dogstatsd_client *client = &DDTRACE_G(dogstatsd_client); const char *metric = "datadog.tracer.uncaught_exceptions"; const char *tags = "class:sigsegv"; dogstatsd_client_status status = dogstatsd_client_count(client, metric, "1", tags); if (status == DOGSTATSD_CLIENT_OK) { - ddtrace_bgs_logf("[crash] sigsegv health metric sent"); + datadog_signal_safe_logf("[crash] sigsegv health metric sent"); } } #endif -#if DDTRACE_HAVE_BACKTRACE - ddtrace_bgs_logf("Datadog PHP Trace extension (DEBUG MODE)"); - ddtrace_bgs_logf("Received Signal %d", sig); +#if DATADOG_HAVE_BACKTRACE + datadog_signal_safe_logf("Datadog PHP Trace extension (DEBUG MODE)"); + datadog_signal_safe_logf("Received Signal %d", sig); void *array[MAX_STACK_SIZE]; backtrace_size_t size = backtrace(array, MAX_STACK_SIZE); if (size == MAX_STACK_SIZE) { - ddtrace_bgs_logf("Note: max stacktrace size reached"); + datadog_signal_safe_logf("Note: max stacktrace size reached"); } - ddtrace_bgs_logf("Note: Backtrace below might be incomplete and have wrong entries due to optimized runtime"); - ddtrace_bgs_logf("Backtrace:"); + datadog_signal_safe_logf("Note: Backtrace below might be incomplete and have wrong entries due to optimized runtime"); + datadog_signal_safe_logf("Backtrace:"); char **backtraces = backtrace_symbols(array, size); if (backtraces) { @@ -100,7 +101,7 @@ static void dd_sigsegv_handler(int sig) { #endif } - int error_log_fd = atomic_load(&ddtrace_error_log_fd); + int error_log_fd = atomic_load(&datadog_error_log_fd); if (error_log_fd != -1) { #ifndef _WIN32 fsync(error_log_fd); @@ -270,7 +271,7 @@ static void dd_init_crashtracker() { free((void *) socket_path.ptr); socket_path.ptr = crashtracker_socket_path; - if (!ddtrace_endpoint) { + if (!datadog_endpoint) { return; } @@ -286,12 +287,12 @@ static void dd_init_crashtracker() { .collect_all_threads = true, .max_threads = 0, // uses libdatadog default, which is 256 }, - .metadata = ddtrace_setup_crashtracking_metadata(&tags), + .metadata = datadog_setup_crashtracking_metadata(&tags), }; - ddtrace_endpoint_as_crashtracker_config(ddtrace_endpoint, dd_crasht_do_init, &args); + datadog_endpoint_as_crashtracker_config(datadog_endpoint, dd_crasht_do_init, &args); - ddtrace_register_crashtracking_frames_collection(); + datadog_register_crashtracking_frames_collection(); ddog_Vec_Tag_drop(tags); } @@ -303,18 +304,18 @@ static void dd_signals_init_async_stack() { } } -void ddtrace_signals_first_rinit(void) { - DDTRACE_G(backtrace_handler_already_run) = false; +void datadog_signals_first_rinit(void) { + DATADOG_G(backtrace_handler_already_run) = false; // Signal handlers are causing issues with FrankenPHP. - if (ddtrace_active_sapi == DATADOG_PHP_SAPI_FRANKENPHP) { + if (datadog_active_sapi == DATADOG_PHP_SAPI_FRANKENPHP) { return; } bool install_crashtracker = get_DD_INSTRUMENTATION_TELEMETRY_ENABLED() && get_DD_CRASHTRACKING_ENABLED(); bool install_backtrace_handler = get_DD_TRACE_HEALTH_METRICS_ENABLED(); -#if DDTRACE_HAVE_BACKTRACE +#if DATADOG_HAVE_BACKTRACE install_backtrace_handler |= get_DD_LOG_BACKTRACE(); #endif @@ -365,7 +366,7 @@ static int dd_call_prev_handler(bool flush) { } if (flush) { - ddog_sidecar_flush(&ddtrace_sidecar_for_signal, (ddog_SidecarFlushOptions){.traces_and_stats = true}); + ddog_sidecar_flush(&datadog_sidecar_for_signal, (ddog_SidecarFlushOptions){.traces_and_stats = true}); } if (prev_handler == SIG_DFL) { @@ -405,7 +406,7 @@ static void dd_sigint_sigterm_handler(int sig, siginfo_t *si, void *uc) { memcpy(&dd_signal_data.si, si, sizeof(*si)); dd_signal_data.uc = uc; - if (ddtrace_sidecar_for_signal) { + if (datadog_sidecar_for_signal) { // Spawn a thread using clone() to perform sidecar cleanup asynchronously to avoid async unsafeness in the signal handler void *stack_top = dd_signal_async_stack + dd_signal_async_stack_size; int flags = CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | CLONE_THREAD; @@ -416,7 +417,7 @@ static void dd_sigint_sigterm_handler(int sig, siginfo_t *si, void *uc) { } #endif -void ddtrace_signals_minit(void) { +void datadog_signals_minit(void) { #if __linux dd_sigint_sigterm_sigaction.sa_sigaction = dd_sigint_sigterm_handler; dd_sigint_sigterm_sigaction.sa_flags = SA_SIGINFO; @@ -432,7 +433,7 @@ void ddtrace_signals_minit(void) { #endif } -void ddtrace_signals_mshutdown(void) { +void datadog_signals_mshutdown(void) { #if __linux if (dd_sigint_sigterm_sigaction.sa_sigaction) { if (get_global_DD_TRACE_FORCE_FLUSH_ON_SIGTERM()) { @@ -451,12 +452,12 @@ void ddtrace_signals_mshutdown(void) { } #else -void ddtrace_signals_first_rinit(void) {} -void ddtrace_signals_mshutdown(void) {} +void datadog_signals_first_rinit(void) {} +void datadog_signals_mshutdown(void) {} #endif // This allows us to include the executing php binary and extensions themselves in the core dump too -void ddtrace_set_coredumpfilter(void) { +void datadog_set_coredumpfilter(void) { FILE *fp = fopen("/proc/self/coredump_filter", "r+"); if (!fp) { return; diff --git a/ext/signals.h b/ext/signals.h index d466def65f3..326abb9542c 100644 --- a/ext/signals.h +++ b/ext/signals.h @@ -1,9 +1,9 @@ #ifndef DD_TRACE_SIGNALS_H #define DD_TRACE_SIGNALS_H -void ddtrace_set_coredumpfilter(void); -void ddtrace_signals_first_rinit(void); -void ddtrace_signals_minit(void); -void ddtrace_signals_mshutdown(void); +void datadog_set_coredumpfilter(void); +void datadog_signals_first_rinit(void); +void datadog_signals_minit(void); +void datadog_signals_mshutdown(void); #endif // DD_TRACE_SIGNALS_H diff --git a/ext/startup_logging.c b/ext/startup_logging.c index 34afbbfc34b..f920b5a4c98 100644 --- a/ext/startup_logging.c +++ b/ext/startup_logging.c @@ -1,32 +1,31 @@ #include "startup_logging.h" +#include #include #include #include #include -#include -#include #include #include #ifndef _WIN32 #include -#include "coms.h" +#include #endif -#include "auto_flush.h" #include "configuration.h" -#include "excluded_modules.h" +#include "endpoints.h" +#include "telemetry.h" +#include #include "ext/version.h" -#include "integrations/integrations.h" #include -#define ISO_8601_LEN (20 + 1) // +1 for terminating null-character +#include "startup_logging_helpers.h" -extern bool ddtrace_loaded_by_ssi; +#define ISO_8601_LEN (20 + 1) // +1 for terminating null-character -static void _dd_get_time(char *buf) { +static void dd_get_time(char *buf) { time_t now = time(NULL); struct tm *tm = gmtime(&now); if (tm) { @@ -36,173 +35,41 @@ static void _dd_get_time(char *buf) { } } -static void _dd_add_assoc_string(HashTable *ht, const char *name, size_t name_len, const char *str) { - zval value; - size_t str_len = str ? strlen(str) : 0; - if (str_len > 0) { - ZVAL_STRINGL(&value, str, str_len); - } else { - ZVAL_NULL(&value); - } - zend_hash_str_update(ht, name, name_len, &value); -} - -static void _dd_add_assoc_string_free(HashTable *ht, const char *name, size_t name_len, char *str) { - _dd_add_assoc_string(ht, name, name_len, (const char *)str); - free(str); -} - -static void _dd_add_assoc_array(HashTable *ht, const char *name, size_t name_len, zend_array *array) { - zval value; - ZVAL_ARR(&value, array); - zend_hash_str_update(ht, name, name_len, &value); -} - -static void _dd_add_assoc_zstring(HashTable *ht, const char *name, size_t name_len, zend_string *str) { - zval value; - if (ZSTR_LEN(str) == 0) { - zend_string_release(str); - ZVAL_NULL(&value); - } else { - ZVAL_STR(&value, str); - } - zend_hash_str_update(ht, name, name_len, &value); -} - -static void _dd_add_assoc_bool(HashTable *ht, const char *name, size_t name_len, bool v) { - zval value; - ZVAL_BOOL(&value, v); - zend_hash_str_update(ht, name, name_len, &value); -} - -static void _dd_add_assoc_double(HashTable *ht, const char *name, size_t name_len, double num) { - zval value; - ZVAL_DOUBLE(&value, num); - zend_hash_str_update(ht, name, name_len, &value); -} -static char *_dd_get_ini(const char *name, size_t name_len) { return zend_ini_string((char *)name, name_len, 0); } +static void dd_get_startup_config(HashTable *ht) { + // Cross-language tracer values + char time[ISO_8601_LEN]; + dd_get_time(time); + dd_add_assoc_string(ht, ZEND_STRL("date"), time); -static bool _dd_ini_is_set(const char *name, size_t name_len) { - const char *ini = _dd_get_ini(name, name_len); - return ini && (strcmp(ini, "") != 0); -} + dd_add_assoc_zstring(ht, ZEND_STRL("os_name"), php_get_uname('a')); + dd_add_assoc_zstring(ht, ZEND_STRL("os_version"), php_get_uname('r')); + dd_add_assoc_string(ht, ZEND_STRL("version"), PHP_DDTRACE_VERSION); + dd_add_assoc_string(ht, ZEND_STRL("lang"), "php"); + dd_add_assoc_string(ht, ZEND_STRL("lang_version"), PHP_VERSION); + dd_add_assoc_zstring(ht, ZEND_STRL("env"), zend_string_copy(get_DD_ENV())); + dd_add_assoc_bool(ht, ZEND_STRL("enabled"), !dd_parse_bool(ZEND_STRL("ddtrace.disable"))); + dd_add_assoc_zstring(ht, ZEND_STRL("service"), zend_string_copy(get_DD_SERVICE())); + dd_add_assoc_bool(ht, ZEND_STRL("enabled_cli"), get_DD_TRACE_CLI_ENABLED()); + dd_add_assoc_string_free(ht, ZEND_STRL("agent_url"), datadog_agent_url()); -// Modified version of zend_ini_parse_bool() -// @see https://github.com/php/php-src/blob/28b4761/Zend/zend_ini.c#L493-L502 -static bool _dd_parse_bool(const char *name, size_t name_len) { - const char *ini = _dd_get_ini(name, name_len); - size_t ini_len = strlen(ini); - if ((ini_len == 4 && strcasecmp(ini, "true") == 0) || (ini_len == 3 && strcasecmp(ini, "yes") == 0) || - (ini_len == 2 && strcasecmp(ini, "on") == 0)) { - return 1; - } else { - return atoi(ini) != 0; - } -} -static zend_array *_dd_array_copy(zend_array *array) { - if (!(GC_FLAGS(array) & IS_ARRAY_IMMUTABLE)) { - GC_ADDREF(array); - return array; - } - - // If it's not duplicated, it may crash later e.g. in json encoding. - return zend_array_dup(array); -} - -static zend_string *_dd_implode_keys(zend_array *array) { - smart_str imploded = {0}; - zend_string *key; - ZEND_HASH_FOREACH_STR_KEY(array, key) { - if (imploded.a != 0) { - smart_str_appendc(&imploded, ','); - } - smart_str_append(&imploded, key); - } - ZEND_HASH_FOREACH_END(); - smart_str_0(&imploded); - return imploded.s ? imploded.s : ZSTR_EMPTY_ALLOC(); -} - -static void _dd_get_startup_config(HashTable *ht) { - // Cross-language tracer values - char time[ISO_8601_LEN]; - _dd_get_time(time); - _dd_add_assoc_string(ht, ZEND_STRL("date"), time); - - _dd_add_assoc_zstring(ht, ZEND_STRL("os_name"), php_get_uname('a')); - _dd_add_assoc_zstring(ht, ZEND_STRL("os_version"), php_get_uname('r')); - _dd_add_assoc_string(ht, ZEND_STRL("version"), PHP_DDTRACE_VERSION); - _dd_add_assoc_string(ht, ZEND_STRL("lang"), "php"); - _dd_add_assoc_string(ht, ZEND_STRL("lang_version"), PHP_VERSION); - _dd_add_assoc_zstring(ht, ZEND_STRL("env"), zend_string_copy(get_DD_ENV())); - _dd_add_assoc_bool(ht, ZEND_STRL("enabled"), !_dd_parse_bool(ZEND_STRL("ddtrace.disable"))); - _dd_add_assoc_zstring(ht, ZEND_STRL("service"), zend_string_copy(get_DD_SERVICE())); - _dd_add_assoc_bool(ht, ZEND_STRL("enabled_cli"), get_DD_TRACE_CLI_ENABLED()); - - _dd_add_assoc_string_free(ht, ZEND_STRL("agent_url"), ddtrace_agent_url()); - - _dd_add_assoc_bool(ht, ZEND_STRL("debug"), get_DD_TRACE_DEBUG()); - _dd_add_assoc_bool(ht, ZEND_STRL("analytics_enabled"), get_DD_TRACE_ANALYTICS_ENABLED()); - _dd_add_assoc_double(ht, ZEND_STRL("sample_rate"), get_DD_TRACE_SAMPLE_RATE()); - _dd_add_assoc_array(ht, ZEND_STRL("sampling_rules"), _dd_array_copy(get_DD_TRACE_SAMPLING_RULES())); - // TODO Add integration-specific config: integration__analytics_enabled, - // integration__sample_rate, integrations_loaded - _dd_add_assoc_array(ht, ZEND_STRL("tags"), _dd_array_copy(get_DD_TAGS())); - _dd_add_assoc_array(ht, ZEND_STRL("service_mapping"), _dd_array_copy(get_DD_SERVICE_MAPPING())); - // "log_injection_enabled" N/A for PHP - // "runtime_metrics_enabled" N/A for PHP - // "configuration_file" N/A for PHP - // "vm" N/A for PHP - // "partial_flushing_enabled" N/A for PHP - _dd_add_assoc_bool(ht, ZEND_STRL("distributed_tracing_enabled"), get_DD_DISTRIBUTED_TRACING()); - // "logs_correlation_enabled" N/A for PHP - // "profiling_enabled" N/A for PHP - _dd_add_assoc_zstring(ht, ZEND_STRL("dd_version"), zend_string_copy(get_DD_VERSION())); - // "health_metrics_enabled" N/A for PHP - _dd_add_assoc_zstring(ht, ZEND_STRL("architecture"), php_get_uname('m')); - _dd_add_assoc_bool(ht, ZEND_STRL("instrumentation_telemetry_enabled"), get_global_DD_INSTRUMENTATION_TELEMETRY_ENABLED()); - - // PHP-specific values - _dd_add_assoc_string(ht, ZEND_STRL("sapi"), sapi_module.name); - _dd_add_assoc_zstring(ht, ZEND_STRL("datadog.trace.sources_path"), - zend_string_copy(get_DD_TRACE_SOURCES_PATH())); - _dd_add_assoc_bool(ht, ZEND_STRL("open_basedir_configured"), _dd_ini_is_set(ZEND_STRL("open_basedir"))); - _dd_add_assoc_zstring(ht, ZEND_STRL("uri_fragment_regex"), - _dd_implode_keys(get_DD_TRACE_RESOURCE_URI_FRAGMENT_REGEX())); - _dd_add_assoc_zstring(ht, ZEND_STRL("uri_mapping_incoming"), - _dd_implode_keys(get_DD_TRACE_RESOURCE_URI_MAPPING_INCOMING())); - _dd_add_assoc_zstring(ht, ZEND_STRL("uri_mapping_outgoing"), - _dd_implode_keys(get_DD_TRACE_RESOURCE_URI_MAPPING_OUTGOING())); - _dd_add_assoc_bool(ht, ZEND_STRL("auto_flush_enabled"), get_DD_TRACE_AUTO_FLUSH_ENABLED()); - _dd_add_assoc_bool(ht, ZEND_STRL("generate_root_span"), get_DD_TRACE_GENERATE_ROOT_SPAN()); - _dd_add_assoc_bool(ht, ZEND_STRL("http_client_split_by_domain"), get_DD_TRACE_HTTP_CLIENT_SPLIT_BY_DOMAIN()); - _dd_add_assoc_bool(ht, ZEND_STRL("measure_compile_time"), get_DD_TRACE_MEASURE_COMPILE_TIME()); - _dd_add_assoc_bool(ht, ZEND_STRL("report_hostname_on_root_span"), get_DD_TRACE_REPORT_HOSTNAME()); - _dd_add_assoc_zstring(ht, ZEND_STRL("traced_internal_functions"), - _dd_implode_keys(get_DD_TRACE_TRACED_INTERNAL_FUNCTIONS())); - _dd_add_assoc_bool(ht, ZEND_STRL("enabled_from_env"), get_DD_TRACE_ENABLED()); - _dd_add_assoc_string(ht, ZEND_STRL("opcache.file_cache"), _dd_get_ini(ZEND_STRL("opcache.file_cache"))); - _dd_add_assoc_bool(ht, ZEND_STRL("sidecar_trace_sender"), get_global_DD_TRACE_SIDECAR_TRACE_SENDER()); - _dd_add_assoc_bool(ht, ZEND_STRL("dynamic_instrumentation_enabled"), get_global_DD_DYNAMIC_INSTRUMENTATION_ENABLED()); - _dd_add_assoc_bool(ht, ZEND_STRL("exception_replay_enabled"), get_global_DD_EXCEPTION_REPLAY_ENABLED()); - - _dd_add_assoc_bool(ht, ZEND_STRL("loaded_by_ssi"), ddtrace_loaded_by_ssi); + dd_add_assoc_bool(ht, ZEND_STRL("debug"), get_DD_TRACE_DEBUG()); } +// TODO replace with a rust-based implementation #ifndef _WIN32 -static size_t _dd_curl_write_noop(void *ptr, size_t size, size_t nmemb, void *userdata) { +static size_t dd_curl_write_noop(void *ptr, size_t size, size_t nmemb, void *userdata) { UNUSED(ptr, userdata); return size * nmemb; } -static size_t _dd_check_for_agent_error(char *error, bool quick) { +static size_t dd_check_for_agent_error(char *error, bool quick) { CURL *curl = curl_easy_init(); ddtrace_curl_set_hostname(curl); if (quick) { - curl_easy_setopt(curl, CURLOPT_TIMEOUT_MS, DDTRACE_AGENT_QUICK_TIMEOUT); - curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT_MS, DDTRACE_AGENT_QUICK_CONNECT_TIMEOUT); + curl_easy_setopt(curl, CURLOPT_TIMEOUT_MS, DATADOG_AGENT_QUICK_TIMEOUT); + curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT_MS, DATADOG_AGENT_QUICK_CONNECT_TIMEOUT); } else { ddtrace_curl_set_timeout(curl); ddtrace_curl_set_connect_timeout(curl); @@ -216,7 +83,7 @@ static size_t _dd_check_for_agent_error(char *error, bool quick) { const char *body = "[]"; curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, (long)strlen(body)); curl_easy_setopt(curl, CURLOPT_POSTFIELDS, body); - curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, _dd_curl_write_noop); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, dd_curl_write_noop); curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, error); error[0] = 0; @@ -233,68 +100,41 @@ static size_t _dd_check_for_agent_error(char *error, bool quick) { } #endif -static bool _dd_file_exists(const char *file) { - if (!strlen(file)) { - return false; - } - return (VCWD_ACCESS(file, R_OK) == 0); -} - -static bool _dd_open_basedir_allowed(const char *file) { return (php_check_open_basedir_ex(file, 0) != -1); } - static void dd_check_for_excluded_module(HashTable *ht, zend_module_entry *module) { - char error[DDTRACE_EXCLUDED_MODULES_ERROR_MAX_LEN + 1]; + char error[DATADOG_EXCLUDED_MODULES_ERROR_MAX_LEN + 1]; - if (module && module->name && module->version && ddtrace_is_excluded_module(module, error)) { + if (module && module->name && module->version && datadog_is_excluded_module(module, error)) { char key[64]; size_t key_len; key_len = snprintf(key, sizeof(key) - 1, "incompatible module %s", module->name); - _dd_add_assoc_string(ht, key, key_len, error); + dd_add_assoc_string(ht, key, key_len, error); } } /* Supported zval types for diagnostics: string, bool, null - * To support other types, update: - * - ddtrace.c:_dd_info_diagnostics_table(); PHP info output - * - _dd_print_values_to_log(); Debug log output + * To support other types, update phpinfo.c:_dd_info_diagnostics_table(); */ -void ddtrace_startup_diagnostics(HashTable *ht, bool quick) { - // Cross-language tracer values +void datadog_startup_diagnostics(HashTable *ht, bool quick) { +#ifdef DDTRACE + ddtrace_startup_diagnostics(ht, quick); +#endif #ifndef _WIN32 char agent_error[CURL_ERROR_SIZE]; - if (_dd_check_for_agent_error(agent_error, quick)) { - _dd_add_assoc_string(ht, ZEND_STRL("agent_error"), agent_error); + if (dd_check_for_agent_error(agent_error, quick)) { + dd_add_assoc_string(ht, ZEND_STRL("agent_error"), agent_error); } #endif - //_dd_add_assoc_string(ht, ZEND_STRL("sampling_rules_error"), ""); // TODO Parse at C level - //_dd_add_assoc_string(ht, ZEND_STRL("service_mapping_error"), ""); // TODO Parse at C level - - // PHP-specific values - const char *sources = ZSTR_VAL(get_DD_TRACE_SOURCES_PATH()); - bool sources_exist = _dd_file_exists(sources); - if (!sources_exist) { - _dd_add_assoc_bool(ht, ZEND_STRL("datadog.trace.sources_path_reachable"), sources_exist); - } else { - bool sources_allowed = _dd_open_basedir_allowed(sources); - if (!sources_allowed) { - _dd_add_assoc_bool(ht, ZEND_STRL("open_basedir_sources_allowed"), sources_allowed); - } - } + //dd_add_assoc_string(ht, ZEND_STRL("service_mapping_error"), ""); // TODO Parse at C level - bool container_allowed = _dd_open_basedir_allowed("/proc/self/cgroup"); - if (!container_allowed) { - _dd_add_assoc_bool(ht, ZEND_STRL("open_basedir_container_tagging_allowed"), container_allowed); - } - - //_dd_add_assoc_string(ht, ZEND_STRL("uri_fragment_regex_error"), ""); // TODO Parse at C level - //_dd_add_assoc_string(ht, ZEND_STRL("uri_mapping_incoming_error"), ""); // TODO Parse at C level - //_dd_add_assoc_string(ht, ZEND_STRL("uri_mapping_outgoing_error"), ""); // TODO Parse at C level + //dd_add_assoc_string(ht, ZEND_STRL("uri_fragment_regex_error"), ""); // TODO Parse at C level + //dd_add_assoc_string(ht, ZEND_STRL("uri_mapping_incoming_error"), ""); // TODO Parse at C level + //dd_add_assoc_string(ht, ZEND_STRL("uri_mapping_outgoing_error"), ""); // TODO Parse at C level // opcache.file_cache was added in PHP 7.0 - const char *opcache_file_cache = _dd_get_ini(ZEND_STRL("opcache.file_cache")); + const char *opcache_file_cache = dd_get_ini(ZEND_STRL("opcache.file_cache")); if (opcache_file_cache && opcache_file_cache[0]) { - _dd_add_assoc_string(ht, ZEND_STRL("opcache_file_cache_set"), + dd_add_assoc_string(ht, ZEND_STRL("opcache_file_cache_set"), "The opcache.file_cache INI setting is set. This setting can cause unexpected behavior " "with the PHP tracer due to a bug in OPcache: https://bugs.php.net/bug.php?id=79825"); } @@ -302,43 +142,47 @@ void ddtrace_startup_diagnostics(HashTable *ht, bool quick) { for (uint16_t i = 0; i < zai_config_memoized_entries_count; ++i) { zai_config_memoized_entry *cfg = &zai_config_memoized_entries[i]; // DD_TRACE_LOGS_ENABLED would be the proper name, but for compatibility with other tracers, we also support DD_LOGS_INJECTION officially - if (cfg->name_index > 0 && i != DDTRACE_CONFIG_DD_TRACE_LOGS_ENABLED) { + if (cfg->name_index > 0 && i != DATADOG_CONFIG_DD_TRACE_LOGS_ENABLED) { zai_config_name *old_name = &cfg->names[cfg->name_index]; zend_string *message = zend_strpprintf(0, "'%s=%s' is deprecated, use %s instead.", old_name->ptr, ZSTR_VAL(cfg->ini_entries[0]->value), cfg->names[0].ptr); - _dd_add_assoc_zstring(ht, old_name->ptr, old_name->len, message); + dd_add_assoc_zstring(ht, old_name->ptr, old_name->len, message); } } - if (ddtrace_has_excluded_module == true) { + if (datadog_has_excluded_module == true) { zend_module_entry *module; ZEND_HASH_FOREACH_PTR(&module_registry, module) { dd_check_for_excluded_module(ht, module); } ZEND_HASH_FOREACH_END(); } } -static void _dd_serialize_json(HashTable *ht, smart_str *buf, int options) { +static void dd_serialize_json(HashTable *ht, smart_str *buf, int options) { zval zv; ZVAL_ARR(&zv, ht); zai_json_encode(buf, &zv, options); smart_str_0(buf); } -void ddtrace_startup_logging_json(smart_str *buf, int options) { +void datadog_startup_logging_json(smart_str *buf, int options) { HashTable *ht; ALLOC_HASHTABLE(ht); - zend_hash_init(ht, DDTRACE_STARTUP_STAT_COUNT, NULL, ZVAL_PTR_DTOR, 0); + zend_hash_init(ht, DATADOG_STARTUP_STAT_COUNT, NULL, ZVAL_PTR_DTOR, 0); - _dd_get_startup_config(ht); - ddtrace_startup_diagnostics(ht, false); + dd_get_startup_config(ht); +#ifdef DDTRACE + ddtrace_populate_startup_config(ht); +#endif + dd_add_assoc_bool(ht, ZEND_STRL("loaded_by_ssi"), datadog_loaded_by_ssi); + datadog_startup_diagnostics(ht, false); - _dd_serialize_json(ht, buf, options); + dd_serialize_json(ht, buf, options); zend_hash_destroy(ht); FREE_HASHTABLE(ht); } -static void _dd_print_values_to_log(HashTable *ht, void (*log)(const char *format, ...)) { +static void dd_print_values_to_log(HashTable *ht, void (*log)(const char *format, ...)) { zend_string *key; zval *val; ZEND_HASH_FOREACH_STR_KEY_VAL_IND(ht, key, val) { @@ -363,31 +207,37 @@ static void _dd_print_values_to_log(HashTable *ht, void (*log)(const char *forma ZEND_HASH_FOREACH_END(); } -// Only show startup logs on the first request -void ddtrace_startup_logging_first_rinit(void) { - LOGEV(STARTUP, { - HashTable *ht; - ALLOC_HASHTABLE(ht); - zend_hash_init(ht, DDTRACE_STARTUP_STAT_COUNT, NULL, ZVAL_PTR_DTOR, 0); - - ddtrace_startup_diagnostics(ht, true); - _dd_print_values_to_log(ht, log); - _dd_get_startup_config(ht); - - smart_str buf = {0}; - _dd_serialize_json(ht, &buf, 0); - log("DATADOG TRACER CONFIGURATION - %s", ZSTR_VAL(buf.s)); - log("For additional diagnostic checks such as Agent connectivity, see the 'ddtrace' section of a phpinfo() " - "page. Alternatively set DD_TRACE_DEBUG=Error,Startup to add diagnostic checks to the error logs on the first request " - "of a new PHP process. Set DD_TRACE_STARTUP_LOGS=0 to disable this tracer configuration message."); - - if (get_DD_OPENAI_LOGS_ENABLED()) { - log("Note that DD_OPENAI_LOGS_ENABLED=1 may be changed or removed in any release."); - } +static void dd_print_startup_logs(void (*log)(const char *format, ...)) { + HashTable *ht; + ALLOC_HASHTABLE(ht); + zend_hash_init(ht, DATADOG_STARTUP_STAT_COUNT, NULL, ZVAL_PTR_DTOR, 0); + + datadog_startup_diagnostics(ht, true); + dd_get_startup_config(ht); +#ifdef DDTRACE + ddtrace_populate_startup_config(ht); +#endif + dd_add_assoc_bool(ht, ZEND_STRL("loaded_by_ssi"), datadog_loaded_by_ssi); + dd_print_values_to_log(ht, log); + + smart_str buf = {0}; + dd_serialize_json(ht, &buf, 0); + log("DATADOG TRACER CONFIGURATION - %s", ZSTR_VAL(buf.s)); + log("For additional diagnostic checks such as Agent connectivity, see the 'ddtrace' section of a phpinfo() " + "page. Alternatively set DD_TRACE_DEBUG=Error,Startup to add diagnostic checks to the error logs on the first request " + "of a new PHP process. Set DD_TRACE_STARTUP_LOGS=0 to disable this tracer configuration message."); + +#ifdef DDTRACE + ddtrace_startup_logging_extra(log); +#endif - smart_str_free(&buf); + smart_str_free(&buf); - zend_hash_destroy(ht); - FREE_HASHTABLE(ht); - }) + zend_hash_destroy(ht); + FREE_HASHTABLE(ht); +} + +// Only show startup logs on the first request +void datadog_startup_logging_first_rinit(void) { + LOGEV(STARTUP, dd_print_startup_logs(log);) } diff --git a/ext/startup_logging.h b/ext/startup_logging.h index 0adbdccdd7b..efa53ccf1d4 100644 --- a/ext/startup_logging.h +++ b/ext/startup_logging.h @@ -1,28 +1,28 @@ -#ifndef DD_TRACE_STARTUP_LOGGING_H -#define DD_TRACE_STARTUP_LOGGING_H +#ifndef DATADOG_STARTUP_LOGGING_H +#define DATADOG_STARTUP_LOGGING_H #include #include #include /* Number of config & diagnostic values */ -#define DDTRACE_STARTUP_STAT_COUNT 43 +#define DATADOG_STARTUP_STAT_COUNT 64 /* These are the Agent connectivity timeouts for the diagnostic check on the first RINIT * so they should be quick to not block script execution too long. */ -#define DDTRACE_AGENT_QUICK_TIMEOUT 500L -#define DDTRACE_AGENT_QUICK_CONNECT_TIMEOUT 100L +#define DATADOG_AGENT_QUICK_TIMEOUT 500L +#define DATADOG_AGENT_QUICK_CONNECT_TIMEOUT 100L -void ddtrace_startup_logging_first_rinit(void); -void ddtrace_startup_diagnostics(HashTable *ht, bool quick); +void datadog_startup_logging_first_rinit(void); +void datadog_startup_diagnostics(HashTable *ht, bool quick); /* Returns a json-encoded string of config/diagnostic info; caller must free. * smart_str buf = {0}; - * ddtrace_startup_logging_json(&buf); + * datadog_startup_logging_json(&buf); * // don't forget! * smart_str_free(&buf); */ -void ddtrace_startup_logging_json(smart_str *buf, int options); +void datadog_startup_logging_json(smart_str *buf, int options); -#endif // DD_TRACE_STARTUP_LOGGING_H +#endif // DATADOG_STARTUP_LOGGING_H diff --git a/ext/startup_logging_helpers.h b/ext/startup_logging_helpers.h new file mode 100644 index 00000000000..6d9e008c0ad --- /dev/null +++ b/ext/startup_logging_helpers.h @@ -0,0 +1,91 @@ +#include +#include + +static inline void dd_add_assoc_string(HashTable *ht, const char *name, size_t name_len, const char *str) { + zval value; + size_t str_len = str ? strlen(str) : 0; + if (str_len > 0) { + ZVAL_STRINGL(&value, str, str_len); + } else { + ZVAL_NULL(&value); + } + zend_hash_str_update(ht, name, name_len, &value); +} + +static inline void dd_add_assoc_string_free(HashTable *ht, const char *name, size_t name_len, char *str) { + dd_add_assoc_string(ht, name, name_len, (const char *)str); + free(str); +} + +static inline void dd_add_assoc_array(HashTable *ht, const char *name, size_t name_len, zend_array *array) { + zval value; + ZVAL_ARR(&value, array); + zend_hash_str_update(ht, name, name_len, &value); +} + +static inline void dd_add_assoc_zstring(HashTable *ht, const char *name, size_t name_len, zend_string *str) { + zval value; + if (ZSTR_LEN(str) == 0) { + zend_string_release(str); + ZVAL_NULL(&value); + } else { + ZVAL_STR(&value, str); + } + zend_hash_str_update(ht, name, name_len, &value); +} + +static inline void dd_add_assoc_bool(HashTable *ht, const char *name, size_t name_len, bool v) { + zval value; + ZVAL_BOOL(&value, v); + zend_hash_str_update(ht, name, name_len, &value); +} + +static inline void dd_add_assoc_double(HashTable *ht, const char *name, size_t name_len, double num) { + zval value; + ZVAL_DOUBLE(&value, num); + zend_hash_str_update(ht, name, name_len, &value); +} + +static inline char *dd_get_ini(const char *name, size_t name_len) { return zend_ini_string((char *)name, name_len, 0); } + +static inline bool dd_ini_is_set(const char *name, size_t name_len) { + const char *ini = dd_get_ini(name, name_len); + return ini && (strcmp(ini, "") != 0); +} + +// Modified version of zend_ini_parse_bool() +// @see https://github.com/php/php-src/blob/28b4761/Zend/zend_ini.c#L493-L502 +static inline bool dd_parse_bool(const char *name, size_t name_len) { + const char *ini = dd_get_ini(name, name_len); + size_t ini_len = strlen(ini); + if ((ini_len == 4 && strcasecmp(ini, "true") == 0) || (ini_len == 3 && strcasecmp(ini, "yes") == 0) || + (ini_len == 2 && strcasecmp(ini, "on") == 0)) { + return 1; + } else { + return atoi(ini) != 0; + } +} + +static inline zend_array *dd_array_copy(zend_array *array) { + if (!(GC_FLAGS(array) & IS_ARRAY_IMMUTABLE)) { + GC_ADDREF(array); + return array; + } + + // If it's not duplicated, it may crash later e.g. in json encoding. + return zend_array_dup(array); +} + +static inline zend_string *dd_implode_keys(zend_array *array) { + smart_str imploded = {0}; + zend_string *key; + ZEND_HASH_FOREACH_STR_KEY(array, key) { + if (imploded.a != 0) { + smart_str_appendc(&imploded, ','); + } + smart_str_append(&imploded, key); + } + ZEND_HASH_FOREACH_END(); + smart_str_0(&imploded); + return imploded.s ? imploded.s : ZSTR_EMPTY_ALLOC(); +} diff --git a/ext/compat_string.c b/ext/string_utils.c similarity index 85% rename from ext/compat_string.c rename to ext/string_utils.c index 7bc64b2ef81..b8d8211a260 100644 --- a/ext/compat_string.c +++ b/ext/string_utils.c @@ -1,5 +1,4 @@ -#include "compat_string.h" -#include "ddtrace.h" +#include "string_utils.h" #include #include @@ -7,27 +6,7 @@ #include "compatibility.h" -size_t ddtrace_spprintf(char **message, size_t max_len, char *format, ...) { - va_list arg; - size_t len; - - va_start(arg, format); - len = vspprintf(message, max_len, format, arg); - va_end(arg); - return len; -} - -void ddtrace_downcase_zval(zval *src) { - if (!src || Z_TYPE_P(src) != IS_STRING) { - return; - } - zend_string *str = Z_STR_P(src); - - ZVAL_STR(src, zend_string_tolower(str)); - zend_string_release(str); -} - -zend_string *ddtrace_convert_to_str(const zval *op) { +zend_string *datadog_convert_to_str(const zval *op) { try_again: switch (Z_TYPE_P(op)) { case IS_UNDEF: @@ -89,8 +68,8 @@ zend_string *ddtrace_convert_to_str(const zval *op) { } } -void ddtrace_convert_to_string(zval *dst, zval *src) { - zend_string *str = ddtrace_convert_to_str(src); +void datadog_convert_to_string(zval *dst, zval *src) { + zend_string *str = datadog_convert_to_str(src); ZVAL_STR(dst, str); } diff --git a/ext/compat_string.h b/ext/string_utils.h similarity index 59% rename from ext/compat_string.h rename to ext/string_utils.h index 25de9a02a30..dddb2764ec1 100644 --- a/ext/compat_string.h +++ b/ext/string_utils.h @@ -1,15 +1,6 @@ #ifndef COMPAT_STRING_H #define COMPAT_STRING_H -#include #include -#include - -#include "compatibility.h" - -void ddtrace_downcase_zval(zval *src); - -// ddtrace_spprintf is a replacement for zend_spprintf, since it is not exported in many versions -size_t ddtrace_spprintf(char **message, size_t max_len, char *format, ...); /** * dst will be IS_STRING after the call; caller must dtor. @@ -19,7 +10,7 @@ size_t ddtrace_spprintf(char **message, size_t max_len, char *format, ...); * The we avoid the __toString cast here to not execute user code at this place. Also avoids possible stack * overflows due to recursion stemming from our own code as the root. **/ -void ddtrace_convert_to_string(zval *dst, zval *src); -zend_string *ddtrace_convert_to_str(const zval *op); +void datadog_convert_to_string(zval *dst, zval *src); +zend_string *datadog_convert_to_str(const zval *op); #endif // COMPAT_STRING_H diff --git a/ext/telemetry.c b/ext/telemetry.c index fff422a24e2..7f73e0fe6d5 100644 --- a/ext/telemetry.c +++ b/ext/telemetry.c @@ -1,150 +1,86 @@ #include "components-rs/sidecar.h" -#include "ddtrace.h" +#include "datadog.h" +#include "ffi_utils.h" +#include "tracer/tracer_api.h" +#include #ifndef _WIN32 #include #else #include #endif -#include "configuration.h" -#include "integrations/integrations.h" +#include +#include #include #include #include "telemetry.h" -#include "serializer.h" +#include #include "sidecar.h" #include -ZEND_EXTERN_MODULE_GLOBALS(ddtrace); +ZEND_EXTERN_MODULE_GLOBALS(datadog); // These globals are set by the SSI loader -DDTRACE_PUBLIC bool ddtrace_loaded_by_ssi = false; -DDTRACE_PUBLIC bool ddtrace_ssi_forced_injection_enabled = false; - -zend_long dd_composer_hook_id; -ddog_QueueId dd_bgs_queued_id; +DATADOG_PUBLIC bool datadog_loaded_by_ssi = false; +DATADOG_PUBLIC bool datadog_ssi_forced_injection_enabled = false; static void dd_commit_metrics(void); -ddog_SidecarActionsBuffer *ddtrace_telemetry_buffer(void) { - if (DDTRACE_G(telemetry_buffer)) { - return DDTRACE_G(telemetry_buffer); +ddog_SidecarActionsBuffer *datadog_telemetry_buffer(void) { + if (DATADOG_G(telemetry_buffer)) { + return DATADOG_G(telemetry_buffer); } - return DDTRACE_G(telemetry_buffer) = ddog_sidecar_telemetry_buffer_alloc(); + return DATADOG_G(telemetry_buffer) = ddog_sidecar_telemetry_buffer_alloc(); } -ddog_ShmCacheMap *ddtrace_telemetry_cache(void) { - if (DDTRACE_G(telemetry_cache)) { - return DDTRACE_G(telemetry_cache); +ddog_ShmCacheMap *datadog_telemetry_cache(void) { + if (DATADOG_G(telemetry_cache)) { + return DATADOG_G(telemetry_cache); } - return DDTRACE_G(telemetry_cache) = ddog_sidecar_telemetry_cache_new(); + return DATADOG_G(telemetry_cache) = ddog_sidecar_telemetry_cache_new(); } -void ddtrace_integration_error_telemetryf(ddog_Log source, const char *format, ...) { - va_list va, va2; - va_start(va, format); - char buf[0x100]; - ddog_SidecarActionsBuffer *buffer = ddtrace_telemetry_buffer(); - va_copy(va2, va); - int len = vsnprintf(buf, sizeof(buf), format, va2); - va_end(va2); - if (len > (int)sizeof(buf)) { - char *msg = malloc(len + 1); - len = vsnprintf(msg, len + 1, format, va); - ddog_sidecar_telemetry_add_integration_log_buffer(source, buffer, (ddog_CharSlice){ .ptr = msg, .len = (uintptr_t)len }); - free(msg); - } else { - ddog_sidecar_telemetry_add_integration_log_buffer(source, buffer, (ddog_CharSlice){ .ptr = buf, .len = (uintptr_t)len }); - } - va_end(va); +void datadog_telemetry_rinit(void) { + zend_hash_init(&DATADOG_G(otel_config_telemetry), 8, unused, ZVAL_PTR_DTOR, 0); } -const char *ddtrace_telemetry_redact_file(const char *file) { -#ifdef _WIN32 -#define SEPARATOR_CHAR "\\" -#else -#define SEPARATOR_CHAR "/" -#endif - const char *redacted_substring = strstr(file, SEPARATOR_CHAR "DDTrace"); - if (redacted_substring != NULL) { - return redacted_substring; - } else { - // Should not happen but will serve as a gate keepers - const char *php_file_name = strrchr(file, SEPARATOR_CHAR[0]); - if (php_file_name) { - return php_file_name; - } - return ""; - } -} - -static bool dd_check_for_composer_autoloader(zend_ulong invocation, zend_execute_data *execute_data, void *auxiliary, void *dynamic) { - UNUSED(invocation, auxiliary, dynamic); - - ddog_CharSlice composer_path = dd_zend_string_to_CharSlice(execute_data->func->op_array.filename); - if (!DDTRACE_G(sidecar) // if sidecar connection was broken, let's skip immediately - || ddtrace_detect_composer_installed_json(&DDTRACE_G(sidecar), ddtrace_sidecar_instance_id, &DDTRACE_G(sidecar_queue_id), composer_path)) { - zai_hook_remove((zai_str)ZAI_STR_EMPTY, (zai_str)ZAI_STR_EMPTY, dd_composer_hook_id); - } - return true; -} - -void ddtrace_telemetry_first_init(void) { - dd_composer_hook_id = zai_hook_install((zai_str)ZAI_STR_EMPTY, (zai_str)ZAI_STR_EMPTY, dd_check_for_composer_autoloader, NULL, ZAI_HOOK_AUX_UNUSED, 0); -} - -void ddtrace_telemetry_rinit(void) { - zend_hash_init(&DDTRACE_G(telemetry_spans_created_per_integration), 8, unused, NULL, 0); - zend_hash_init(&DDTRACE_G(otel_config_telemetry), 8, unused, ZVAL_PTR_DTOR, 0); - DDTRACE_G(baggage_extract_count) = 0; - DDTRACE_G(baggage_inject_count) = 0; - DDTRACE_G(baggage_malformed_count) = 0; - DDTRACE_G(baggage_max_item_count) = 0; - DDTRACE_G(baggage_max_byte_count) = 0; - DDTRACE_G(baggage_extract_max_item_count) = 0; - DDTRACE_G(baggage_extract_max_byte_count) = 0; -} - -void ddtrace_telemetry_rshutdown(void) { - zend_hash_destroy(&DDTRACE_G(telemetry_spans_created_per_integration)); - zend_hash_destroy(&DDTRACE_G(otel_config_telemetry)); +void datadog_telemetry_rshutdown(void) { + zend_hash_destroy(&DATADOG_G(otel_config_telemetry)); } // Register in the sidecar services not bound to the request lifetime -void ddtrace_telemetry_register_services(ddog_SidecarTransport **sidecar) { - if (!dd_bgs_queued_id) { - dd_bgs_queued_id = ddog_sidecar_queueId_generate(); - } - - ddog_sidecar_telemetry_register_metric(sidecar, DDOG_CHARSLICE_C("trace_api.requests"), DDOG_METRIC_TYPE_COUNT, DDOG_METRIC_NAMESPACE_TRACERS); - ddog_sidecar_telemetry_register_metric(sidecar, DDOG_CHARSLICE_C("trace_api.responses"), DDOG_METRIC_TYPE_COUNT, DDOG_METRIC_NAMESPACE_TRACERS); - ddog_sidecar_telemetry_register_metric(sidecar, DDOG_CHARSLICE_C("trace_api.errors"), DDOG_METRIC_TYPE_COUNT, DDOG_METRIC_NAMESPACE_TRACERS); - - // FIXME: it seems we must call "enqueue_actions" (even with an empty list of actions) for things to work properly - ddog_SidecarActionsBuffer *buffer = ddog_sidecar_telemetry_buffer_alloc(); - ddtrace_ffi_try("Failed flushing background sender telemetry buffer", - ddog_sidecar_telemetry_buffer_flush(sidecar, ddtrace_sidecar_instance_id, &dd_bgs_queued_id, buffer)); +void datadog_telemetry_register_services(ddog_SidecarTransport **sidecar) { +#ifdef DDTRACE + ddtrace_telemetry_register_services(sidecar); +#endif } -void ddtrace_telemetry_lifecycle_end() { - if (!DDTRACE_G(sidecar) || !get_global_DD_INSTRUMENTATION_TELEMETRY_ENABLED()) { +void datadog_telemetry_lifecycle_end() { + if (!DATADOG_G(sidecar) || !get_global_DD_INSTRUMENTATION_TELEMETRY_ENABLED()) { return; } - ddtrace_ffi_try("Failed ending sidecar lifecycle", - ddog_sidecar_lifecycle_end(&DDTRACE_G(sidecar), ddtrace_sidecar_instance_id, &DDTRACE_G(sidecar_queue_id))); + datadog_ffi_try("Failed ending sidecar lifecycle", + ddog_sidecar_lifecycle_end(&DATADOG_G(sidecar), datadog_sidecar_instance_id, &DATADOG_G(sidecar_queue_id))); } -void ddtrace_telemetry_finalize() { - if (!DDTRACE_G(last_service_name) || !DDTRACE_G(last_env_name)) { +void datadog_telemetry_finalize() { + if (!DATADOG_G(last_service_name) || !DATADOG_G(last_env_name)) { LOG(WARN, "No telemetry submission can happen without service/env"); return; } - ddog_CharSlice service_name = dd_zend_string_to_CharSlice(DDTRACE_G(last_service_name)); - ddog_CharSlice env_name = dd_zend_string_to_CharSlice(DDTRACE_G(last_env_name)); + ddog_CharSlice service_name = dd_zend_string_to_CharSlice(DATADOG_G(last_service_name)); + ddog_CharSlice env_name = dd_zend_string_to_CharSlice(DATADOG_G(last_env_name)); + + ddog_SidecarActionsBuffer *buffer = datadog_telemetry_buffer(); + +#ifdef DDTRACE + // Must be called before clearing telemetry_buffer so ddtrace_telemetry_finalize + // uses the same buffer (via datadog_telemetry_buffer()) that we'll flush below. + ddtrace_telemetry_finalize(); +#endif - ddog_SidecarActionsBuffer *buffer = ddtrace_telemetry_buffer(); - DDTRACE_G(telemetry_buffer) = NULL; + DATADOG_G(telemetry_buffer) = NULL; zend_module_entry *module; char module_name[261] = { 'e', 'x', 't', '-' }; @@ -158,7 +94,7 @@ void ddtrace_telemetry_finalize() { (ddog_CharSlice) {.len = strlen(version), .ptr = version}); } ZEND_HASH_FOREACH_END(); - if (!ddog_sidecar_telemetry_config_sent(ddtrace_telemetry_cache(), service_name, env_name)) { + if (!ddog_sidecar_telemetry_config_sent(datadog_telemetry_cache(), service_name, env_name)) { for (uint16_t i = 0; i < zai_config_memoized_entries_count; i++) { zai_config_memoized_entry *cfg = &zai_config_memoized_entries[i]; zend_ini_entry *ini = cfg->ini_entries[0]; @@ -191,10 +127,10 @@ void ddtrace_telemetry_finalize() { } // Send extra internal configuration - ddog_CharSlice instrumentation_source = ddtrace_loaded_by_ssi ? DDOG_CHARSLICE_C("ssi") : DDOG_CHARSLICE_C("manual"); + ddog_CharSlice instrumentation_source = datadog_loaded_by_ssi ? DDOG_CHARSLICE_C("ssi") : DDOG_CHARSLICE_C("manual"); ddog_sidecar_telemetry_enqueueConfig_buffer(buffer, DDOG_CHARSLICE_C("instrumentation_source"), instrumentation_source, DDOG_CONFIGURATION_ORIGIN_DEFAULT, DDOG_CHARSLICE_C("")); - ddog_CharSlice ssi_forced = ddtrace_ssi_forced_injection_enabled ? DDOG_CHARSLICE_C("True") : DDOG_CHARSLICE_C("False"); + ddog_CharSlice ssi_forced = datadog_ssi_forced_injection_enabled ? DDOG_CHARSLICE_C("True") : DDOG_CHARSLICE_C("False"); ddog_sidecar_telemetry_enqueueConfig_buffer(buffer, DDOG_CHARSLICE_C("ssi_forced_injection_enabled"), ssi_forced, DDOG_CONFIGURATION_ORIGIN_ENV_VAR, DDOG_CHARSLICE_C("")); char *injection_enabled = getenv("DD_INJECTION_ENABLED"); @@ -205,7 +141,7 @@ void ddtrace_telemetry_finalize() { // Send OTel configuration telemetry zend_string *config_name; zval *config_value; - ZEND_HASH_FOREACH_STR_KEY_VAL(&DDTRACE_G(otel_config_telemetry), config_name, config_value) { + ZEND_HASH_FOREACH_STR_KEY_VAL(&DATADOG_G(otel_config_telemetry), config_name, config_value) { if (config_name && Z_TYPE_P(config_value) == IS_STRING) { ddog_CharSlice name = dd_zend_string_to_CharSlice(config_name); ddog_CharSlice value = dd_zend_string_to_CharSlice(Z_STR_P(config_value)); @@ -215,40 +151,8 @@ void ddtrace_telemetry_finalize() { } ZEND_HASH_FOREACH_END(); } - // Send information about explicitly disabled integrations - for (size_t i = 0; i < ddtrace_integrations_len; ++i) { - ddtrace_integration *integration = &ddtrace_integrations[i]; - if (!integration->is_enabled()) { - ddog_CharSlice integration_name = (ddog_CharSlice) {.len = integration->name_len, .ptr = integration->name_lcase}; - ddog_sidecar_telemetry_addIntegration_buffer(buffer, integration_name, DDOG_CHARSLICE_C(""), false); - } - } - - // Telemetry metrics - ddog_CharSlice metric_name = DDOG_CHARSLICE_C("spans_created"); - ddog_sidecar_telemetry_register_metric(&DDTRACE_G(sidecar), metric_name, DDOG_METRIC_TYPE_COUNT, DDOG_METRIC_NAMESPACE_TRACERS); - zend_string *integration_name; - zval *metric_value; - ZEND_HASH_FOREACH_STR_KEY_VAL(&DDTRACE_G(telemetry_spans_created_per_integration), integration_name, metric_value) { - zai_string tags = zai_string_concat3((zai_str)ZAI_STRL("integration_name:"), (zai_str)ZAI_STR_FROM_ZSTR(integration_name), (zai_str)ZAI_STRING_EMPTY); - ddog_sidecar_telemetry_add_span_metric_point_buffer(buffer, metric_name, Z_DVAL_P(metric_value), dd_zai_string_to_CharSlice(tags)); - zai_string_destroy(&tags); - } ZEND_HASH_FOREACH_END(); - - ddog_sidecar_telemetry_register_metric(&DDTRACE_G(sidecar), DDOG_CHARSLICE_C("context_header_style.extracted"), DDOG_METRIC_TYPE_COUNT, DDOG_METRIC_NAMESPACE_TRACERS); - ddog_sidecar_telemetry_add_span_metric_point_buffer(buffer, DDOG_CHARSLICE_C("context_header_style.extracted"), DDTRACE_G(baggage_extract_count), DDOG_CHARSLICE_C("header_style:baggage")); - ddog_sidecar_telemetry_register_metric(&DDTRACE_G(sidecar), DDOG_CHARSLICE_C("context_header_style.injected"), DDOG_METRIC_TYPE_COUNT, DDOG_METRIC_NAMESPACE_TRACERS); - ddog_sidecar_telemetry_add_span_metric_point_buffer(buffer, DDOG_CHARSLICE_C("context_header_style.injected"), DDTRACE_G(baggage_inject_count), DDOG_CHARSLICE_C("header_style:baggage")); - ddog_sidecar_telemetry_register_metric(&DDTRACE_G(sidecar), DDOG_CHARSLICE_C("context_header.truncated"), DDOG_METRIC_TYPE_COUNT, DDOG_METRIC_NAMESPACE_TRACERS); - ddog_sidecar_telemetry_add_span_metric_point_buffer(buffer, DDOG_CHARSLICE_C("context_header.truncated"), DDTRACE_G(baggage_max_item_count), DDOG_CHARSLICE_C("truncation_reason:baggage_byte_item_exceeded")); - ddog_sidecar_telemetry_add_span_metric_point_buffer(buffer, DDOG_CHARSLICE_C("context_header.truncated"), DDTRACE_G(baggage_max_byte_count), DDOG_CHARSLICE_C("truncation_reason:baggage_byte_count_exceeded")); - ddog_sidecar_telemetry_add_span_metric_point_buffer(buffer, DDOG_CHARSLICE_C("context_header.truncated"), DDTRACE_G(baggage_extract_max_item_count), DDOG_CHARSLICE_C("truncation_reason:baggage_extract_item_exceeded")); - ddog_sidecar_telemetry_add_span_metric_point_buffer(buffer, DDOG_CHARSLICE_C("context_header.truncated"), DDTRACE_G(baggage_extract_max_byte_count), DDOG_CHARSLICE_C("truncation_reason:baggage_extract_byte_exceeded")); - ddog_sidecar_telemetry_register_metric(&DDTRACE_G(sidecar), DDOG_CHARSLICE_C("context_header_style.malformed"), DDOG_METRIC_TYPE_COUNT, DDOG_METRIC_NAMESPACE_TRACERS); - ddog_sidecar_telemetry_add_span_metric_point_buffer(buffer, DDOG_CHARSLICE_C("context_header_style.malformed"), DDTRACE_G(baggage_malformed_count), DDOG_CHARSLICE_C("header_style:baggage")); - - metric_name = DDOG_CHARSLICE_C("logs_created"); - ddog_sidecar_telemetry_register_metric(&DDTRACE_G(sidecar), metric_name, DDOG_METRIC_TYPE_COUNT, DDOG_METRIC_NAMESPACE_GENERAL); + ddog_CharSlice metric_name = DDOG_CHARSLICE_C("logs_created"); + ddog_sidecar_telemetry_register_metric(&DATADOG_G(sidecar), metric_name, DDOG_METRIC_TYPE_COUNT, DDOG_METRIC_NAMESPACE_GENERAL); static struct { ddog_CharSlice level; ddog_CharSlice tags; @@ -268,177 +172,36 @@ void ddtrace_telemetry_finalize() { dd_commit_metrics(); - ddtrace_ffi_try("Failed flushing filtered telemetry buffer", - ddog_sidecar_telemetry_filter_flush(&DDTRACE_G(sidecar), ddtrace_sidecar_instance_id, &DDTRACE_G(sidecar_queue_id), buffer, ddtrace_telemetry_cache(), service_name, env_name)); + datadog_ffi_try("Failed flushing filtered telemetry buffer", + ddog_sidecar_telemetry_filter_flush(&DATADOG_G(sidecar), datadog_sidecar_instance_id, &DATADOG_G(sidecar_queue_id), buffer, datadog_telemetry_cache(), service_name, env_name)); ddog_sidecar_telemetry_buffer_drop(buffer); - - // Flush any accumulated BGS (background sender) metrics if enough time has passed. - ddtrace_telemetry_flush_bgs_metrics_if_due(DDTRACE_GLOBALS_PTR()); } -void ddtrace_telemetry_notify_integration(const char *name, size_t name_len) { - ddtrace_telemetry_notify_integration_version(name, name_len, "", 0); -} - -void ddtrace_telemetry_notify_integration_version(const char *name, size_t name_len, const char *version, size_t version_len) { - if (DDTRACE_G(sidecar) && get_global_DD_INSTRUMENTATION_TELEMETRY_ENABLED()) { - ddog_CharSlice integration = (ddog_CharSlice) {.len = name_len, .ptr = name}; - ddog_CharSlice ver = (ddog_CharSlice) {.len = version_len, .ptr = version}; - ddog_sidecar_telemetry_addIntegration_buffer(ddtrace_telemetry_buffer(), integration, ver, true); - } -} - -void ddtrace_telemetry_inc_spans_created(ddtrace_span_data *span) { - zval *component = NULL; - if (Z_TYPE(span->property_meta) == IS_ARRAY) { - component = zend_hash_str_find(Z_ARRVAL(span->property_meta), ZEND_STRL("component")); - } - - zend_string *integration = NULL; - 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); - } else if (span->flags & DDTRACE_SPAN_FLAG_OPENTRACING) { - integration = zend_string_init(ZEND_STRL("opentracing"), 0); - } else { - // Fallback value when the span has not been created by an integration, nor OpenTelemetry/OpenTracing (i.e. \DDTrace\span_start()) - integration = zend_string_init(ZEND_STRL("datadog"), 0); - } - - zval *current = zend_hash_find(&DDTRACE_G(telemetry_spans_created_per_integration), integration); - if (current) { - ++Z_DVAL_P(current); - } else { - zval counter; - ZVAL_DOUBLE(&counter, 1.0); - zend_hash_add(&DDTRACE_G(telemetry_spans_created_per_integration), integration, &counter); - } - - zend_string_release(integration); -} - -// Process-global atomic accumulators for background-sender metrics. -// Written by the BGS thread (coms.c) without any lock; drained by a PHP request -// thread in ddtrace_telemetry_flush_bgs_metrics_if_due(). -static _Atomic(int) bgs_metric_requests = 0; -static _Atomic(int) bgs_metric_responses_1xx = 0; -static _Atomic(int) bgs_metric_responses_2xx = 0; -static _Atomic(int) bgs_metric_responses_3xx = 0; -static _Atomic(int) bgs_metric_responses_4xx = 0; -static _Atomic(int) bgs_metric_responses_5xx = 0; -static _Atomic(int) bgs_metric_errors_timeout = 0; -static _Atomic(int) bgs_metric_errors_network = 0; -static _Atomic(int) bgs_metric_errors_status_code = 0; -// Timestamp (nanoseconds) of the last flush; used to rate-limit to one flush per interval. -static _Atomic(uint64_t) bgs_metrics_last_flush_ns = 0; - -void ddtrace_telemetry_send_trace_api_metrics(trace_api_metrics metrics) { - // Pure atomic accumulation — never touches the sidecar. - if (!metrics.requests) { - return; - } - atomic_fetch_add(&bgs_metric_requests, metrics.requests); - atomic_fetch_add(&bgs_metric_responses_1xx, metrics.responses_1xx); - atomic_fetch_add(&bgs_metric_responses_2xx, metrics.responses_2xx); - atomic_fetch_add(&bgs_metric_responses_3xx, metrics.responses_3xx); - atomic_fetch_add(&bgs_metric_responses_4xx, metrics.responses_4xx); - atomic_fetch_add(&bgs_metric_responses_5xx, metrics.responses_5xx); - atomic_fetch_add(&bgs_metric_errors_timeout, metrics.errors_timeout); - atomic_fetch_add(&bgs_metric_errors_network, metrics.errors_network); - atomic_fetch_add(&bgs_metric_errors_status_code, metrics.errors_status_code); -} - -void ddtrace_telemetry_flush_bgs_metrics_if_due(zend_ddtrace_globals *ddtrace_globals) { - if (!ddtrace_globals->sidecar || !get_global_DD_INSTRUMENTATION_TELEMETRY_ENABLED()) { - return; - } - - // Rate-limit: flush at most once per agent flush interval. - uint64_t now_ns = ddtrace_nanoseconds_realtime(); - uint64_t last = atomic_load(&bgs_metrics_last_flush_ns); - uint64_t interval_ns = (uint64_t)get_global_DD_TRACE_AGENT_FLUSH_INTERVAL() * 1000000ULL; - if (now_ns - last < interval_ns) { - return; - } - // CAS ensures only one thread flushes per interval. - if (!atomic_compare_exchange_strong(&bgs_metrics_last_flush_ns, &last, now_ns)) { - return; - } - - int requests = atomic_exchange(&bgs_metric_requests, 0); - if (!requests) { - return; - } - - ddog_SidecarActionsBuffer *buffer = ddog_sidecar_telemetry_buffer_alloc(); - ddog_sidecar_telemetry_add_span_metric_point_buffer(buffer, DDOG_CHARSLICE_C("trace_api.requests"), requests, DDOG_CHARSLICE_C("")); - - int v; - if ((v = atomic_exchange(&bgs_metric_responses_1xx, 0))) { - ddog_sidecar_telemetry_add_span_metric_point_buffer(buffer, DDOG_CHARSLICE_C("trace_api.responses"), v, DDOG_CHARSLICE_C("status_code:1xx")); - } - if ((v = atomic_exchange(&bgs_metric_responses_2xx, 0))) { - ddog_sidecar_telemetry_add_span_metric_point_buffer(buffer, DDOG_CHARSLICE_C("trace_api.responses"), v, DDOG_CHARSLICE_C("status_code:2xx")); - } - if ((v = atomic_exchange(&bgs_metric_responses_3xx, 0))) { - ddog_sidecar_telemetry_add_span_metric_point_buffer(buffer, DDOG_CHARSLICE_C("trace_api.responses"), v, DDOG_CHARSLICE_C("status_code:3xx")); - } - if ((v = atomic_exchange(&bgs_metric_responses_4xx, 0))) { - ddog_sidecar_telemetry_add_span_metric_point_buffer(buffer, DDOG_CHARSLICE_C("trace_api.responses"), v, DDOG_CHARSLICE_C("status_code:4xx")); - } - if ((v = atomic_exchange(&bgs_metric_responses_5xx, 0))) { - ddog_sidecar_telemetry_add_span_metric_point_buffer(buffer, DDOG_CHARSLICE_C("trace_api.responses"), v, DDOG_CHARSLICE_C("status_code:5xx")); - } - if ((v = atomic_exchange(&bgs_metric_errors_timeout, 0))) { - ddog_sidecar_telemetry_add_span_metric_point_buffer(buffer, DDOG_CHARSLICE_C("trace_api.errors"), v, DDOG_CHARSLICE_C("type:timeout")); - } - if ((v = atomic_exchange(&bgs_metric_errors_network, 0))) { - ddog_sidecar_telemetry_add_span_metric_point_buffer(buffer, DDOG_CHARSLICE_C("trace_api.errors"), v, DDOG_CHARSLICE_C("type:network")); - } - if ((v = atomic_exchange(&bgs_metric_errors_status_code, 0))) { - ddog_sidecar_telemetry_add_span_metric_point_buffer(buffer, DDOG_CHARSLICE_C("trace_api.errors"), v, DDOG_CHARSLICE_C("type:status_code")); - } - - ddtrace_ffi_try("Failed flushing background sender metrics", - ddog_sidecar_telemetry_buffer_flush(&ddtrace_globals->sidecar, ddtrace_sidecar_instance_id, &dd_bgs_queued_id, buffer)); -} - -void ddtrace_telemetry_flush_bgs_metrics_final(zend_ddtrace_globals *ddtrace_globals) { - if (!ddtrace_sidecar_instance_id) { - return; - } - // Bypass the time gate so any remaining metrics are sent before the transport - // is dropped in GSHUTDOWN. Setting last_flush_ns to 0 makes the time check in - // _if_due always pass; the CAS inside still prevents a concurrent double-flush. - atomic_store(&bgs_metrics_last_flush_ns, 0); - ddtrace_telemetry_flush_bgs_metrics_if_due(ddtrace_globals); -} -DDTRACE_PUBLIC void ddtrace_metric_register_buffer(zend_string *name, ddog_MetricType type, ddog_MetricNamespace ns) { - if (!DDTRACE_G(sidecar)) { +DATADOG_PUBLIC void datadog_metric_register_buffer(zend_string *name, ddog_MetricType type, ddog_MetricNamespace ns) { + if (!DATADOG_G(sidecar)) { return; } ddog_CharSlice metric_name = dd_zend_string_to_CharSlice(name); - ddog_sidecar_telemetry_register_metric(&DDTRACE_G(sidecar), metric_name, type, ns); + ddog_sidecar_telemetry_register_metric(&DATADOG_G(sidecar), metric_name, type, ns); } -DDTRACE_PUBLIC bool ddtrace_metric_add_point(zend_string *name, double value, zend_string *tags) { - if (!DDTRACE_G(metrics_buffer)) { - DDTRACE_G(metrics_buffer) = ddog_sidecar_telemetry_buffer_alloc(); +DATADOG_PUBLIC bool datadog_metric_add_point(zend_string *name, double value, zend_string *tags) { + if (!DATADOG_G(metrics_buffer)) { + DATADOG_G(metrics_buffer) = ddog_sidecar_telemetry_buffer_alloc(); } ddog_CharSlice metric_name = dd_zend_string_to_CharSlice(name); ddog_CharSlice tags_slice = dd_zend_string_to_CharSlice(tags); - ddog_sidecar_telemetry_add_span_metric_point_buffer(DDTRACE_G(metrics_buffer), metric_name, value, tags_slice); + ddog_sidecar_telemetry_add_span_metric_point_buffer(DATADOG_G(metrics_buffer), metric_name, value, tags_slice); return true; } static void dd_commit_metrics() { - if (!DDTRACE_G(metrics_buffer)) { + if (!DATADOG_G(metrics_buffer)) { return; } ddog_sidecar_telemetry_buffer_flush( - &DDTRACE_G(sidecar), ddtrace_sidecar_instance_id, &DDTRACE_G(sidecar_queue_id), DDTRACE_G(metrics_buffer)); - DDTRACE_G(metrics_buffer) = NULL; + &DATADOG_G(sidecar), datadog_sidecar_instance_id, &DATADOG_G(sidecar_queue_id), DATADOG_G(metrics_buffer)); + DATADOG_G(metrics_buffer) = NULL; } diff --git a/ext/telemetry.h b/ext/telemetry.h index cb31d5594b8..97828859bd2 100644 --- a/ext/telemetry.h +++ b/ext/telemetry.h @@ -1,12 +1,11 @@ -#ifndef DDTRACE_TELEMETRY_H -#define DDTRACE_TELEMETRY_H +#ifndef DATADOG_TELEMETRY_H +#define DATADOG_TELEMETRY_H #include #include #include "components-rs/common.h" -#include "ddtrace_export.h" -#include "span.h" +#include "datadog_export.h" void ddtrace_integration_error_telemetryf(ddog_Log source, const char *format, ...); #define INTEGRATION_ERROR_TELEMETRY(source, format, ...) { ddtrace_integration_error_telemetryf(DDOG_LOG_##source, format, ##__VA_ARGS__); } @@ -23,30 +22,19 @@ typedef struct _trace_api_metrics { int errors_status_code; } trace_api_metrics; -ddog_SidecarActionsBuffer *ddtrace_telemetry_buffer(void); -ddog_ShmCacheMap *ddtrace_telemetry_cache(void); +ddog_SidecarActionsBuffer *datadog_telemetry_buffer(void); +ddog_ShmCacheMap *datadog_telemetry_cache(void); const char *ddtrace_telemetry_redact_file(const char *file); -void ddtrace_telemetry_first_init(void); -void ddtrace_telemetry_rinit(void); -void ddtrace_telemetry_rshutdown(void); -void ddtrace_telemetry_notify_integration(const char *name, size_t name_len); -void ddtrace_telemetry_notify_integration_version(const char *name, size_t name_len, const char *version, size_t version_len); -void ddtrace_telemetry_finalize(); -void ddtrace_telemetry_lifecycle_end(void); -void ddtrace_telemetry_register_services(ddog_SidecarTransport **sidecar); -void ddtrace_telemetry_inc_spans_created(ddtrace_span_data *span); -// Called by the background sender thread (coms.c) to accumulate metrics atomically. -// Never touches the sidecar; the request thread flushes via ddtrace_telemetry_flush_bgs_metrics_if_due(). -void ddtrace_telemetry_send_trace_api_metrics(trace_api_metrics metrics); -// Called from ddtrace_telemetry_finalize() to flush accumulated BGS metrics through -// the given thread's sidecar connection, at most once per flush interval. -void ddtrace_telemetry_flush_bgs_metrics_if_due(zend_ddtrace_globals *ddtrace_globals); -// Force-flush accumulated BGS metrics regardless of the time gate. Call immediately -// before dropping the per-thread transport in GSHUTDOWN so no data is lost. -void ddtrace_telemetry_flush_bgs_metrics_final(zend_ddtrace_globals *ddtrace_globals); +void datadog_telemetry_rinit(void); +void datadog_telemetry_rshutdown(void); +void datadog_telemetry_finalize(void); +void datadog_telemetry_lifecycle_end(void); +void datadog_telemetry_register_services(ddog_SidecarTransport **sidecar); // public API -DDTRACE_PUBLIC void ddtrace_metric_register_buffer(zend_string *name, ddog_MetricType type, ddog_MetricNamespace ns); -DDTRACE_PUBLIC bool ddtrace_metric_add_point(zend_string *name, double value, zend_string *tags); +DATADOG_PUBLIC void datadog_metric_register_buffer(zend_string *name, ddog_MetricType type, ddog_MetricNamespace ns); +DATADOG_PUBLIC bool datadog_metric_add_point(zend_string *name, double value, zend_string *tags); + +DATADOG_PUBLIC extern bool datadog_loaded_by_ssi; #endif // DDTRACE_TELEMETRY_H diff --git a/ext/threads.c b/ext/threads.c index fa176ddba5b..0acc483cdda 100644 --- a/ext/threads.c +++ b/ext/threads.c @@ -6,7 +6,6 @@ #undef zend_signal_globals_id #undef zend_signal_globals_offset #undef zend_signal_handler_unblock -#include "ddtrace.h" #if ZTS @@ -24,13 +23,13 @@ __attribute__((weak)) size_t zend_signal_globals_offset; __attribute__((weak)) void zend_signal_handler_unblock(void); #endif -HashTable ddtrace_tls_bases; // map thread id to TSRMLS_CACHE -MUTEX_T ddtrace_threads_mutex = NULL; +HashTable datadog_tls_bases; // map thread id to TSRMLS_CACHE +MUTEX_T datadog_threads_mutex = NULL; -void ddtrace_thread_ginit() { - if (!ddtrace_threads_mutex) { - ddtrace_threads_mutex = tsrm_mutex_alloc(); - zend_hash_init(&ddtrace_tls_bases, 8, NULL, NULL, 1); +void datadog_thread_ginit() { + if (!datadog_threads_mutex) { + datadog_threads_mutex = tsrm_mutex_alloc(); + zend_hash_init(&datadog_tls_bases, 8, NULL, NULL, 1); } #ifdef ZEND_SIGNALS @@ -39,11 +38,11 @@ void ddtrace_thread_ginit() { HANDLE_BLOCK_INTERRUPTIONS(); } #endif - tsrm_mutex_lock(ddtrace_threads_mutex); + tsrm_mutex_lock(datadog_threads_mutex); - zend_hash_index_add_new_ptr(&ddtrace_tls_bases, (zend_ulong)(uintptr_t)tsrm_thread_id(), TSRMLS_CACHE); + zend_hash_index_add_new_ptr(&datadog_tls_bases, (zend_ulong)(uintptr_t)tsrm_thread_id(), TSRMLS_CACHE); - tsrm_mutex_unlock(ddtrace_threads_mutex); + tsrm_mutex_unlock(datadog_threads_mutex); #ifdef ZEND_SIGNALS if (zend_signal_globals_id) { HANDLE_UNBLOCK_INTERRUPTIONS(); @@ -51,29 +50,29 @@ void ddtrace_thread_ginit() { #endif } -void ddtrace_thread_gshutdown() { - if (ddtrace_threads_mutex) { +void datadog_thread_gshutdown() { + if (datadog_threads_mutex) { #ifdef ZEND_SIGNALS // avoid deadlocks due to signal handlers accessing this if (zend_signal_globals_id) { HANDLE_BLOCK_INTERRUPTIONS(); } #endif - tsrm_mutex_lock(ddtrace_threads_mutex); + tsrm_mutex_lock(datadog_threads_mutex); - zend_hash_index_del(&ddtrace_tls_bases, (zend_ulong)(uintptr_t)tsrm_thread_id()); + zend_hash_index_del(&datadog_tls_bases, (zend_ulong)(uintptr_t)tsrm_thread_id()); - tsrm_mutex_unlock(ddtrace_threads_mutex); + tsrm_mutex_unlock(datadog_threads_mutex); #ifdef ZEND_SIGNALS if (zend_signal_globals_id) { HANDLE_UNBLOCK_INTERRUPTIONS(); } #endif - if (zend_hash_num_elements(&ddtrace_tls_bases) == 0) { - tsrm_mutex_free(ddtrace_threads_mutex); - ddtrace_threads_mutex = NULL; - zend_hash_destroy(&ddtrace_tls_bases); + if (zend_hash_num_elements(&datadog_tls_bases) == 0) { + tsrm_mutex_free(datadog_threads_mutex); + datadog_threads_mutex = NULL; + zend_hash_destroy(&datadog_tls_bases); } } } diff --git a/ext/threads.h b/ext/threads.h index 1f0742f5c21..18042244129 100644 --- a/ext/threads.h +++ b/ext/threads.h @@ -1,15 +1,15 @@ -#ifndef DD_THREADS_H -#define DD_THREADS_H +#ifndef DATADOG_THREADS_H +#define DATADOG_THREADS_H #include #include #if ZTS -extern HashTable ddtrace_tls_bases; -extern MUTEX_T ddtrace_threads_mutex; +extern HashTable datadog_tls_bases; +extern MUTEX_T datadog_threads_mutex; -void ddtrace_thread_ginit(void); -void ddtrace_thread_gshutdown(void); +void datadog_thread_ginit(void); +void datadog_thread_gshutdown(void); #else // Taken from TSRM.h @@ -26,4 +26,4 @@ TSRM_API int tsrm_mutex_lock(MUTEX_T mutexp); TSRM_API int tsrm_mutex_unlock(MUTEX_T mutexp); #endif -#endif // DD_THREADS_H +#endif // DATADOG_THREADS_H diff --git a/ext/zend_hrtime.c b/ext/zend_hrtime.c index 362a7a89c06..71dfdeae6bc 100644 --- a/ext/zend_hrtime.c +++ b/ext/zend_hrtime.c @@ -16,7 +16,7 @@ mach_timebase_info_data_t zend_hrtime_timerlib_info = { }; #endif -void ddtrace_startup_hrtime(void){ +void datadog_startup_hrtime(void){ #if ZEND_HRTIME_PLATFORM_WINDOWS LARGE_INTEGER tf = {0}; if (QueryPerformanceFrequency(&tf) || 0 != tf.QuadPart) { diff --git a/ext/zend_hrtime.h b/ext/zend_hrtime.h index b9a69f9a04d..85e92c4ff8b 100644 --- a/ext/zend_hrtime.h +++ b/ext/zend_hrtime.h @@ -1,5 +1,5 @@ -#ifndef DD_HRTIME_H -#define DD_HRTIME_H +#ifndef DATADOG_HRTIME_H +#define DATADOG_HRTIME_H #include
#include @@ -42,7 +42,7 @@ extern mach_timebase_info_data_t zend_hrtime_timerlib_info; typedef uint64_t zend_hrtime_t; -void ddtrace_startup_hrtime(void); +void datadog_startup_hrtime(void); static zend_always_inline zend_hrtime_t zend_hrtime(void) { @@ -69,4 +69,4 @@ static zend_always_inline zend_hrtime_t zend_hrtime(void) #else #include #endif -#endif /* DD_HRTIME_H */ \ No newline at end of file +#endif /* DATADOG_HRTIME_H */ \ No newline at end of file diff --git a/loader/dd_library_loader.c b/loader/dd_library_loader.c index 3f47f197798..d581f69769f 100644 --- a/loader/dd_library_loader.c +++ b/loader/dd_library_loader.c @@ -253,13 +253,13 @@ static void ddtrace_pre_minit_hook(injected_ext *config, zend_module_entry *modu } // Let ddtrace knows that it was loaded by the loader - bool *ddtrace_loaded_by_ssi = (bool *)DL_FETCH_SYMBOL(config->so_handle, "ddtrace_loaded_by_ssi"); - if (ddtrace_loaded_by_ssi) { - *ddtrace_loaded_by_ssi = true; + bool *datadog_loaded_by_ssi = (bool *)DL_FETCH_SYMBOL(config->so_handle, "datadog_loaded_by_ssi"); + if (datadog_loaded_by_ssi) { + *datadog_loaded_by_ssi = true; } - bool *ddtrace_ssi_forced_injection_enabled = (bool *)DL_FETCH_SYMBOL(config->so_handle, "ddtrace_ssi_forced_injection_enabled"); - if (ddtrace_ssi_forced_injection_enabled) { - *ddtrace_ssi_forced_injection_enabled = force_load; + bool *datadog_ssi_forced_injection_enabled = (bool *)DL_FETCH_SYMBOL(config->so_handle, "datadog_ssi_forced_injection_enabled"); + if (datadog_ssi_forced_injection_enabled) { + *datadog_ssi_forced_injection_enabled = force_load; } } diff --git a/package.xml b/package.xml index b6a0b9bd3e4..b69cba5d1dd 100644 --- a/package.xml +++ b/package.xml @@ -75,7 +75,7 @@ ${changelog} ${codefiles} - + diff --git a/php_ddtrace.h b/php_ddtrace.h index 6aecf52c82e..700d4ec57bc 100644 --- a/php_ddtrace.h +++ b/php_ddtrace.h @@ -1,3 +1,3 @@ -#include "ext/ddtrace.h" +#include "ext/datadog.h" -#define phpext_ddtrace_ptr &ddtrace_module_entry +#define phpext_ddtrace_ptr &datadog_module_entry diff --git a/profiling/src/lib.rs b/profiling/src/lib.rs index ec0bd6da9f7..286505c57bc 100644 --- a/profiling/src/lib.rs +++ b/profiling/src/lib.rs @@ -152,7 +152,7 @@ lazy_static! { static RUNTIME_ID: OnceLock = OnceLock::new(); // If ddtrace is loaded, we fetch the uuid from there instead extern "C" { - pub static ddtrace_runtime_id: *const Uuid; + pub static datadog_runtime_id: *const Uuid; } /// Module dependencies for the profiler extension. @@ -524,7 +524,7 @@ thread_local! { /// Gets the runtime-id for the process. Do not call before RINIT! fn runtime_id() -> &'static Uuid { RUNTIME_ID - .get_or_init(|| unsafe { ddtrace_runtime_id.as_ref() }.map_or_else(Uuid::new_v4, |u| *u)) + .get_or_init(|| unsafe { datadog_runtime_id.as_ref() }.map_or_else(Uuid::new_v4, |u| *u)) } extern "C" fn activate() { diff --git a/profiling/src/php_ffi.c b/profiling/src/php_ffi.c index 00f684e9534..43d51ee050f 100644 --- a/profiling/src/php_ffi.c +++ b/profiling/src/php_ffi.c @@ -14,10 +14,10 @@ const char *datadog_extension_build_id(void) { return ZEND_EXTENSION_BUILD_ID; } const char *datadog_module_build_id(void) { return ZEND_MODULE_BUILD_ID; } -uint8_t *ddtrace_runtime_id = NULL; +uint8_t *datadog_runtime_id = NULL; -static void locate_ddtrace_runtime_id(const zend_extension *extension) { - ddtrace_runtime_id = DL_FETCH_SYMBOL(extension->handle, "ddtrace_runtime_id"); +static void locate_datadog_runtime_id(const zend_extension *extension) { + datadog_runtime_id = DL_FETCH_SYMBOL(extension->handle, "datadog_runtime_id"); } static void locate_ddtrace_get_profiling_context(const zend_extension *extension) { @@ -28,9 +28,9 @@ static void locate_ddtrace_get_profiling_context(const zend_extension *extension } } -static void locate_ddtrace_process_tags_get_serialized(const zend_extension *extension) { +static void locate_datadog_process_tags_get_serialized(const zend_extension *extension) { zend_string *(*get_process_tags)(void) = - DL_FETCH_SYMBOL(extension->handle, "ddtrace_process_tags_get_serialized"); + DL_FETCH_SYMBOL(extension->handle, "datadog_process_tags_get_serialized"); if (EXPECTED(get_process_tags)) { datadog_php_profiling_get_process_tags_serialized = get_process_tags; } @@ -163,8 +163,8 @@ void datadog_php_profiling_startup(zend_extension *extension) { const zend_extension *maybe_ddtrace = (zend_extension *)item->data; if (maybe_ddtrace != extension && is_ddtrace_extension(maybe_ddtrace)) { locate_ddtrace_get_profiling_context(maybe_ddtrace); - locate_ddtrace_runtime_id(maybe_ddtrace); - locate_ddtrace_process_tags_get_serialized(maybe_ddtrace); + locate_datadog_runtime_id(maybe_ddtrace); + locate_datadog_process_tags_get_serialized(maybe_ddtrace); break; } } diff --git a/src/DDTrace/Integrations/OpenAI/OpenAIIntegration.php b/src/DDTrace/Integrations/OpenAI/OpenAIIntegration.php index cbe6cabc0f2..e94adacdaf7 100644 --- a/src/DDTrace/Integrations/OpenAI/OpenAIIntegration.php +++ b/src/DDTrace/Integrations/OpenAI/OpenAIIntegration.php @@ -684,7 +684,7 @@ public static function sendMetrics( bool $estimated = false ) { - if (!dd_trace_env_config('DD_OPENAI_METRICS_ENABLED')) { + if (!dd_trace_env_config('DD_OPENAI_METRICS_ENABLED') || !dd_trace_env_config('DD_INTEGRATION_METRICS_ENABLED')) { return; } diff --git a/tests/Integrations/Custom/Autoloaded/StartupLoggingDiagnosticsTest.php b/tests/Integrations/Custom/Autoloaded/StartupLoggingDiagnosticsTest.php index 3420c2b0f51..156e58a492c 100644 --- a/tests/Integrations/Custom/Autoloaded/StartupLoggingDiagnosticsTest.php +++ b/tests/Integrations/Custom/Autoloaded/StartupLoggingDiagnosticsTest.php @@ -22,12 +22,13 @@ protected static function getEnvs() return array_merge(parent::getEnvs(), [ 'DD_TRACE_DEBUG' => true, // Startup logs only show in debug mode 'DD_AGENT_HOST' => 'invalid_host', // Will fail diagnostic check + 'DD_TRACE_SOURCES_PATH' => '/foo/invalid.php', // Will fail diagnostic check ]); } - protected function ddSetUp() + public static function ddSetUpBeforeClass() { - parent::ddSetUp(); + parent::ddSetUpBeforeClass(); // clear out any previous logs $log = self::getAppErrorLog(); @@ -39,7 +40,6 @@ protected static function getInis() { return array_merge(parent::getInis(), [ 'error_log' => self::getAppErrorLog(), - 'datadog.trace.sources_path' => '/foo/invalid.php', // Will fail diagnostic check ]); } diff --git a/tests/Integrations/Exec/ExecIntegrationTest.php b/tests/Integrations/Exec/ExecIntegrationTest.php index 1f274d77ed1..b9237a54ed2 100644 --- a/tests/Integrations/Exec/ExecIntegrationTest.php +++ b/tests/Integrations/Exec/ExecIntegrationTest.php @@ -621,7 +621,7 @@ public function testProcOpenInjectsSessionIds() public function testShellExecInheritsSessionIds() { // For shell functions (no explicit env), subprocesses inherit the process - // environment. ddtrace_generate_session_id() sets _DD_PARENT_PHP_SESSION_ID + // environment. datadog_generate_session_id() sets _DD_PARENT_PHP_SESSION_ID // and _DD_ROOT_PHP_SESSION_ID in the process env at startup, so they are // always available to child processes without any extra injection. $expectedParent = (string)getenv('_DD_PARENT_PHP_SESSION_ID'); diff --git a/tests/ext/background-sender/agent_sampling.phpt b/tests/ext/background-sender/agent_sampling.phpt index e821bb6ecd6..fe32799f15a 100644 --- a/tests/ext/background-sender/agent_sampling.phpt +++ b/tests/ext/background-sender/agent_sampling.phpt @@ -25,6 +25,9 @@ $rr = new RequestReplayer(); $get_sampling = function() use ($rr) { $root = json_decode($rr->waitForDataAndReplay()["body"], true); $spans = $root["chunks"][0]["spans"] ?? $root[0]; + // Ensure the BGS has finished processing the HTTP response (writing agent rates to SHM) + // before the caller changes the mock response. + dd_trace_internal_fn("synchronous_flush"); return $spans[0]["metrics"]["_sampling_priority_v1"]; }; diff --git a/tests/ext/background-sender/sidecar_fallback.phpt b/tests/ext/background-sender/sidecar_fallback.phpt deleted file mode 100644 index 8b9783795b2..00000000000 --- a/tests/ext/background-sender/sidecar_fallback.phpt +++ /dev/null @@ -1,66 +0,0 @@ ---TEST-- -Send telemetry about the sidecar being disabled ---SKIPIF-- - - - - -replayRequest(); /* avoid cross-pollination */ ?> ---ENV-- -DD_AGENT_HOST=request-replayer -DD_TRACE_AGENT_PORT=80 -DD_TRACE_AGENT_FLUSH_INTERVAL=333 -DD_TRACE_GENERATE_ROOT_SPAN=0 -DD_REMOTE_CONFIG_ENABLED=0 -DD_INSTRUMENTATION_TELEMETRY_ENABLED=0 -DD_SERVICE=service ---INI-- -datadog.trace.agent_test_session_token=background-sender/sidecar_fallback ---FILE-- -waitForDataAndReplay(false)["body"]; - -?> ---EXPECTF-- -string(1) "0" -{ - "api_version": "v2", - "request_type": "generate-metrics", - "seq_id": 1, - "runtime_id": "%s-%s-%s-%s-%s", - "tracer_time": %d, - "payload": { - "namespace": "tracers", - "series": [ - { - "metric": "exporter_fallback", - "tags": [ - "reason:instrumentation_telemetry_disabled" - ], - "points": [ - [ - %d, - 1 - ] - ], - "type": "count", - "common": true - } - ] - }, - "application": { - "service_name": "service", - "tracer_version": "%s", - "language_name": "php", - "language_version": "%s" - }, - "host": { - "hostname": "%s" - } -} diff --git a/tests/ext/live-debugger/debugger_enable_dynamic_config.phpt b/tests/ext/live-debugger/debugger_enable_dynamic_config.phpt index 0013fa3d3d4..8e4acc832c5 100644 --- a/tests/ext/live-debugger/debugger_enable_dynamic_config.phpt +++ b/tests/ext/live-debugger/debugger_enable_dynamic_config.phpt @@ -6,7 +6,7 @@ Enabling dynamic instrumentation via dynamic configuration DD_AGENT_HOST=request-replayer DD_TRACE_AGENT_PORT=80 DD_TRACE_GENERATE_ROOT_SPAN=0 -DD_REMOTE_CONFIG_POLL_INTERVAL_SECONDS=0.01 +DD_REMOTE_CONFIG_POLL_INTERVAL_SECONDS=0.1 --INI-- datadog.trace.agent_test_session_token=live-debugger/enable_dynamic_config --FILE-- diff --git a/tests/ext/live-debugger/debugger_log_probe.phpt b/tests/ext/live-debugger/debugger_log_probe.phpt index 345af03c357..72d9e076a27 100644 --- a/tests/ext/live-debugger/debugger_log_probe.phpt +++ b/tests/ext/live-debugger/debugger_log_probe.phpt @@ -7,7 +7,7 @@ DD_AGENT_HOST=request-replayer DD_TRACE_AGENT_PORT=80 DD_TRACE_GENERATE_ROOT_SPAN=0 DD_DYNAMIC_INSTRUMENTATION_ENABLED=1 -DD_REMOTE_CONFIG_POLL_INTERVAL_SECONDS=0.01 +DD_REMOTE_CONFIG_POLL_INTERVAL_SECONDS=0.1 --INI-- datadog.trace.agent_test_session_token=live-debugger/log_probe --FILE-- diff --git a/tests/ext/live-debugger/debugger_log_probe_process_tags.phpt b/tests/ext/live-debugger/debugger_log_probe_process_tags.phpt index 0ed61760f9f..9f994b4a3de 100644 --- a/tests/ext/live-debugger/debugger_log_probe_process_tags.phpt +++ b/tests/ext/live-debugger/debugger_log_probe_process_tags.phpt @@ -7,7 +7,7 @@ DD_AGENT_HOST=request-replayer DD_TRACE_AGENT_PORT=80 DD_TRACE_GENERATE_ROOT_SPAN=0 DD_DYNAMIC_INSTRUMENTATION_ENABLED=1 -DD_REMOTE_CONFIG_POLL_INTERVAL_SECONDS=0.01 +DD_REMOTE_CONFIG_POLL_INTERVAL_SECONDS=0.1 DD_EXPERIMENTAL_PROPAGATE_PROCESS_TAGS_ENABLED=1 --INI-- datadog.trace.agent_test_session_token=live-debugger/log_probe_process_tags diff --git a/tests/ext/live-debugger/debugger_metric_probe.phpt b/tests/ext/live-debugger/debugger_metric_probe.phpt index af8039adec9..623c1b35a00 100644 --- a/tests/ext/live-debugger/debugger_metric_probe.phpt +++ b/tests/ext/live-debugger/debugger_metric_probe.phpt @@ -13,7 +13,7 @@ DD_TRACE_AGENT_PORT=80 DD_TRACE_GENERATE_ROOT_SPAN=0 DD_DOGSTATSD_URL=unix:///tmp/ddtrace-test-metric_probe.socket DD_DYNAMIC_INSTRUMENTATION_ENABLED=1 -DD_REMOTE_CONFIG_POLL_INTERVAL_SECONDS=0.01 +DD_REMOTE_CONFIG_POLL_INTERVAL_SECONDS=0.1 DD_VERSION=1.2.3 --INI-- datadog.trace.agent_test_session_token=live-debugger/metric_probe diff --git a/tests/ext/live-debugger/debugger_span_decoration_probe.phpt b/tests/ext/live-debugger/debugger_span_decoration_probe.phpt index ba1f6e6ac7c..4ce2aaebc1a 100644 --- a/tests/ext/live-debugger/debugger_span_decoration_probe.phpt +++ b/tests/ext/live-debugger/debugger_span_decoration_probe.phpt @@ -7,7 +7,7 @@ DD_AGENT_HOST=request-replayer DD_TRACE_AGENT_PORT=80 DD_TRACE_GENERATE_ROOT_SPAN=0 DD_DYNAMIC_INSTRUMENTATION_ENABLED=1 -DD_REMOTE_CONFIG_POLL_INTERVAL_SECONDS=0.01 +DD_REMOTE_CONFIG_POLL_INTERVAL_SECONDS=0.1 --INI-- datadog.trace.agent_test_session_token=live-debugger/span_decoration_probe --FILE-- diff --git a/tests/ext/live-debugger/debugger_span_probe.phpt b/tests/ext/live-debugger/debugger_span_probe.phpt index b38af41d658..3bd45de09dc 100644 --- a/tests/ext/live-debugger/debugger_span_probe.phpt +++ b/tests/ext/live-debugger/debugger_span_probe.phpt @@ -7,7 +7,7 @@ DD_AGENT_HOST=request-replayer DD_TRACE_AGENT_PORT=80 DD_TRACE_GENERATE_ROOT_SPAN=0 DD_DYNAMIC_INSTRUMENTATION_ENABLED=1 -DD_REMOTE_CONFIG_POLL_INTERVAL_SECONDS=0.01 +DD_REMOTE_CONFIG_POLL_INTERVAL_SECONDS=0.1 --INI-- datadog.trace.agent_test_session_token=live-debugger/span_probe --FILE-- diff --git a/tests/ext/live-debugger/debugger_span_probe_class.phpt b/tests/ext/live-debugger/debugger_span_probe_class.phpt index 3147ceaf8f5..28977d0aedd 100644 --- a/tests/ext/live-debugger/debugger_span_probe_class.phpt +++ b/tests/ext/live-debugger/debugger_span_probe_class.phpt @@ -8,7 +8,7 @@ DD_AGENT_HOST=request-replayer DD_TRACE_AGENT_PORT=80 DD_TRACE_GENERATE_ROOT_SPAN=0 DD_DYNAMIC_INSTRUMENTATION_ENABLED=1 -DD_REMOTE_CONFIG_POLL_INTERVAL_SECONDS=0.01 +DD_REMOTE_CONFIG_POLL_INTERVAL_SECONDS=0.1 --INI-- datadog.trace.agent_test_session_token=live-debugger/span_probe_class --FILE-- diff --git a/tests/ext/pcntl/pcntl_fork_thread_mode_orphan.phpt b/tests/ext/pcntl/pcntl_fork_thread_mode_orphan.phpt index 1cb0766e149..14558a83316 100644 --- a/tests/ext/pcntl/pcntl_fork_thread_mode_orphan.phpt +++ b/tests/ext/pcntl/pcntl_fork_thread_mode_orphan.phpt @@ -27,7 +27,7 @@ if ($pid > 0) { usleep(500000); // 500ms -// Creating and flushing a span triggers ddtrace_sidecar_ensure_active() +// Creating and flushing a span triggers datadog_sidecar_ensure_active() $span = DDTrace\start_span(); $span->name = 'orphaned-child-span'; DDTrace\close_span(); diff --git a/tests/ext/remote_config/dynamic_config_auto_update.phpt b/tests/ext/remote_config/dynamic_config_auto_update.phpt index 79b694722c7..70d7891dbee 100644 --- a/tests/ext/remote_config/dynamic_config_auto_update.phpt +++ b/tests/ext/remote_config/dynamic_config_auto_update.phpt @@ -6,7 +6,7 @@ Test dynamic config update DD_AGENT_HOST=request-replayer DD_TRACE_AGENT_PORT=80 DD_TRACE_GENERATE_ROOT_SPAN=0 -DD_REMOTE_CONFIG_POLL_INTERVAL_SECONDS=0.01 +DD_REMOTE_CONFIG_POLL_INTERVAL_SECONDS=0.1 DD_TRACE_AGENT_FLUSH_INTERVAL=333 DD_DYNAMIC_INSTRUMENTATION_ENABLED=0 DD_EXCEPTION_REPLAY_ENABLED=1 diff --git a/tests/ext/remote_config/dynamic_config_multiconfig.phpt b/tests/ext/remote_config/dynamic_config_multiconfig.phpt index df3ee6080bc..2a69d8d95ed 100644 --- a/tests/ext/remote_config/dynamic_config_multiconfig.phpt +++ b/tests/ext/remote_config/dynamic_config_multiconfig.phpt @@ -6,7 +6,7 @@ Test dynamic config multiconfig priority merging DD_AGENT_HOST=request-replayer DD_TRACE_AGENT_PORT=80 DD_TRACE_GENERATE_ROOT_SPAN=0 -DD_REMOTE_CONFIG_POLL_INTERVAL_SECONDS=0.01 +DD_REMOTE_CONFIG_POLL_INTERVAL_SECONDS=0.1 --INI-- datadog.trace.agent_test_session_token=remote-config/dynamic_config_multiconfig --FILE-- diff --git a/tests/ext/remote_config/dynamic_config_update.phpt b/tests/ext/remote_config/dynamic_config_update.phpt index 48be3ca6ad0..a70f34be5b8 100644 --- a/tests/ext/remote_config/dynamic_config_update.phpt +++ b/tests/ext/remote_config/dynamic_config_update.phpt @@ -6,7 +6,7 @@ Test dynamic config update DD_AGENT_HOST=request-replayer DD_TRACE_AGENT_PORT=80 DD_TRACE_GENERATE_ROOT_SPAN=0 -DD_REMOTE_CONFIG_POLL_INTERVAL_SECONDS=0.01 +DD_REMOTE_CONFIG_POLL_INTERVAL_SECONDS=0.1 --INI-- datadog.trace.agent_test_session_token=remote-config/dynamic_config_update --FILE-- diff --git a/tests/ext/remote_config/rc_process_tags.phpt b/tests/ext/remote_config/rc_process_tags.phpt index e4c16f93753..3fcc880d882 100644 --- a/tests/ext/remote_config/rc_process_tags.phpt +++ b/tests/ext/remote_config/rc_process_tags.phpt @@ -6,7 +6,7 @@ Test remote config request payload DD_AGENT_HOST=request-replayer DD_TRACE_AGENT_PORT=80 DD_TRACE_GENERATE_ROOT_SPAN=0 -DD_REMOTE_CONFIG_POLL_INTERVAL_SECONDS=0.01 +DD_REMOTE_CONFIG_POLL_INTERVAL_SECONDS=0.1 DD_EXPERIMENTAL_PROPAGATE_PROCESS_TAGS_ENABLED=1 --INI-- datadog.trace.agent_test_session_token=remote-config/check_payload diff --git a/tests/ext/request-replayer/client_side_stats.phpt b/tests/ext/request-replayer/client_side_stats.phpt index f3dfc6bee49..3e20b8a6cc4 100644 --- a/tests/ext/request-replayer/client_side_stats.phpt +++ b/tests/ext/request-replayer/client_side_stats.phpt @@ -47,7 +47,7 @@ $root->resource = "GET /test"; $root->service = "stats-test-service"; \DDTrace\close_span(); -dd_trace_internal_fn('synchronous_flush'); +dd_trace_internal_fn('synchronous_flush', 5000); $rr->waitForDataAndReplay(); // The request-replayer stores the msgpack-decoded body as JSON, with OkSummary/ErrorSummary diff --git a/tests/ext/shm_data_internal_fns.phpt b/tests/ext/shm_data_internal_fns.phpt index c3a36f34a52..cd85e14ba44 100644 --- a/tests/ext/shm_data_internal_fns.phpt +++ b/tests/ext/shm_data_internal_fns.phpt @@ -9,6 +9,8 @@ if (PHP_VERSION_ID >= 80100) { echo "nocache\n"; } // Set agent /info BEFORE the test process starts so the sidecar fetches our data on first poll. +require __DIR__ . '/remote_config/remote_config.inc'; +reset_request_replayer(); file_get_contents('http://request-replayer/set-agent-info', false, stream_context_create([ 'http' => [ 'method' => 'PUT', @@ -28,7 +30,7 @@ DD_TRACE_AGENT_PORT=80 DD_TRACE_AGENT_FLUSH_INTERVAL=333 DD_TRACE_GENERATE_ROOT_SPAN=0 DD_INSTRUMENTATION_TELEMETRY_ENABLED=0 -DD_REMOTE_CONFIG_POLL_INTERVAL_SECONDS=0.01 +DD_REMOTE_CONFIG_POLL_INTERVAL_SECONDS=0.1 DD_TRACE_SIDECAR_TRACE_SENDER=1 DD_DYNAMIC_INSTRUMENTATION_ENABLED=1 DD_TRACE_IGNORE_AGENT_SAMPLING_RATES=0 @@ -42,7 +44,6 @@ datadog.trace.agent_test_session_token=remote-config/shm_data_internal_fns require __DIR__ . '/remote_config/remote_config.inc'; include __DIR__ . '/includes/request_replayer.inc'; -reset_request_replayer(); $rr = new RequestReplayer(); $rr->replayRequest(); // consume any leftover traces from startup diff --git a/tests/ext/sidecar_disabled_when_telemetry_disabled.phpt b/tests/ext/sidecar_disabled_when_telemetry_disabled.phpt deleted file mode 100644 index 0f311a64086..00000000000 --- a/tests/ext/sidecar_disabled_when_telemetry_disabled.phpt +++ /dev/null @@ -1,26 +0,0 @@ ---TEST-- -Sidecar should be disabled when telemetry is disabled ---SKIPIF-- - ---FILE-- - '1', - 'DD_INSTRUMENTATION_TELEMETRY_ENABLED' => '0', -]); - -dd_dump_startup_logs($logs, [ - 'instrumentation_telemetry_enabled', - 'sidecar_trace_sender', -]); - -?> ---EXPECT-- -instrumentation_telemetry_enabled: false -sidecar_trace_sender: false diff --git a/tests/ext/startup_logging_diagnostics.phpt b/tests/ext/startup_logging_diagnostics.phpt index 6f02b5cdd03..ccc6d506bee 100644 --- a/tests/ext/startup_logging_diagnostics.phpt +++ b/tests/ext/startup_logging_diagnostics.phpt @@ -19,7 +19,6 @@ $logs = dd_get_startup_logs($args, $env); dd_dump_startup_logs($logs, [ 'open_basedir_sources_allowed', - 'open_basedir_container_tagging_allowed', 'service', 'tags', 'agent_url', @@ -31,7 +30,6 @@ var_dump(strncasecmp(PHP_OS, "WIN", 3) == 0 || isset($logs["agent_error"])); ?> --EXPECTF-- open_basedir_sources_allowed: false -open_basedir_container_tagging_allowed: false service: "foo_service" agent_url: "http://invalid_host:8126" tags: {"foo":"tag"} diff --git a/tests/ext/telemetry/config.phpt b/tests/ext/telemetry/config.phpt index a062945fdd3..d4f950aff41 100644 --- a/tests/ext/telemetry/config.phpt +++ b/tests/ext/telemetry/config.phpt @@ -92,8 +92,8 @@ Array [2] => Array ( - [name] => DD_TRACE_IGNORE_AGENT_SAMPLING_RATES - [value] => 1 + [name] => DD_TRACE_GIT_METADATA_ENABLED + [value] => 0 [origin] => env_var [config_id] => [seq_id] => @@ -101,7 +101,7 @@ Array [3] => Array ( - [name] => DD_TRACE_GENERATE_ROOT_SPAN + [name] => DD_EXPERIMENTAL_PROPAGATE_PROCESS_TAGS_ENABLED [value] => 0 [origin] => env_var [config_id] => @@ -110,8 +110,8 @@ Array [4] => Array ( - [name] => DD_TRACE_GIT_METADATA_ENABLED - [value] => 0 + [name] => DD_TRACE_IGNORE_AGENT_SAMPLING_RATES + [value] => 1 [origin] => env_var [config_id] => [seq_id] => @@ -119,7 +119,7 @@ Array [5] => Array ( - [name] => DD_EXPERIMENTAL_PROPAGATE_PROCESS_TAGS_ENABLED + [name] => DD_TRACE_GENERATE_ROOT_SPAN [value] => 0 [origin] => env_var [config_id] => diff --git a/tooling/bin/cputime.d b/tooling/bin/cputime.d index adb4e384380..57e85e868e7 100755 --- a/tooling/bin/cputime.d +++ b/tooling/bin/cputime.d @@ -14,7 +14,7 @@ dtrace:::BEGIN printf("Tracing... Hit Ctrl-C to end.\n"); } -pid$target:ddtrace:_dd_*:entry, +pid$target:ddtrace:dd_*:entry, pid$target:ddtrace:ddtrace_*:entry, pid$target:ddtrace:zm_activate_ddtrace*:entry, pid$target:ddtrace:zif_dd_trace*:entry, @@ -25,7 +25,7 @@ pid$target:ddtrace:zif_ddtrace**:entry self->function[self->depth] = vtimestamp; } -pid$target:ddtrace:_dd_*:return, +pid$target:ddtrace:dd_*:return, pid$target:ddtrace:ddtrace_*:return, pid$target:ddtrace:zm_activate_ddtrace*:return, pid$target:ddtrace:zif_dd_trace*:return, diff --git a/tooling/bin/verify-dd-trace-php.sh b/tooling/bin/verify-dd-trace-php.sh index e84d176ebf1..c0961a94d1f 100755 --- a/tooling/bin/verify-dd-trace-php.sh +++ b/tooling/bin/verify-dd-trace-php.sh @@ -17,8 +17,8 @@ if [ "z${1:-}" = "z" ] ; then exit 1 fi -if [ ! -f "ddtrace.sym" ] ; then - >&2 echo "ERROR: expected 'ddtrace.sym' to exist" +if [ ! -f "datadog.sym" ] ; then + >&2 echo "ERROR: expected 'datadog.sym' to exist" exit 1 fi # }}} @@ -39,7 +39,7 @@ nm -gC "$sofile" \ | sort > "$actual_symbols" expected_symbols=`mktemp "$TMPDIR/expected_symbols.XXXXXXXX"` -sort "ddtrace.sym" > "$expected_symbols" +sort "datadog.sym" > "$expected_symbols" unexpected_symbols=`mktemp "$TMPDIR/unexpected_symbols.XXXXXXXX"` # comm -13 will show lines that exist in file 2 that do not exist in file 1. diff --git a/tooling/generate-supported-configurations.sh b/tooling/generate-supported-configurations.sh index 62688de24d3..12e17b12232 100755 --- a/tooling/generate-supported-configurations.sh +++ b/tooling/generate-supported-configurations.sh @@ -9,12 +9,15 @@ readonly CONFIG_HEADER_FILES=( "ext/configuration.h" "appsec/src/extension/configuration.h" ) -readonly OTEL_CONFIG_FILE="ext/otel_config.c" +readonly OTEL_CONFIG_FILES=( + "ext/otel_config.c" + "tracer/configuration.c" +) readonly PROFILING_CONFIG_FILE="profiling/src/config.rs" readonly GENERATOR_SCRIPT_FILE="tooling/generate-supported-configurations.sh" readonly CONFIG_GENERATION_INPUT_FILES=( "${CONFIG_HEADER_FILES[@]}" - "${OTEL_CONFIG_FILE}" + "${OTEL_CONFIG_FILE[@]}" "${PROFILING_CONFIG_FILE}" "${GENERATOR_SCRIPT_FILE}" ) @@ -270,17 +273,19 @@ foreach (explode("|NEXT_CONFIG|", file_get_contents("php://stdin")) as $configLi add_supported_entry($supported, $name, $entry); } -$otelPath = getenv('DDTRACE_SUPPORTED_CONFIG_OTEL_FILE') ?: "../ext/otel_config.c"; -if (file_exists($otelPath)) { - preg_match_all('/ZAI_STRL\("(OTEL_[A-Z0-9_]+)"\)/', file_get_contents($otelPath), $m); - $otelVars = array_unique($m[1]); - sort($otelVars); - foreach ($otelVars as $v) { - add_supported_entry($supported, $v, ["implementation" => "A", "type" => "string", "default" => ""]); +$otelPaths = ["../ext/otel_config.c", "../tracer/otel_config.c"]; +foreach ($otelPaths as $otelPath) { + if (file_exists($otelPath)) { + preg_match_all('/ZAI_STRL\("(OTEL_[A-Z0-9_]+)"\)/', file_get_contents($otelPath), $m); + $otelVars = array_unique($m[1]); + sort($otelVars); + foreach ($otelVars as $v) { + add_supported_entry($supported, $v, ["implementation" => "A", "type" => "string", "default" => ""]); + } } } -$profilingPath = getenv('DDTRACE_SUPPORTED_CONFIG_PROFILING_FILE') ?: "../profiling/src/config.rs"; +$profilingPath = "../profiling/src/config.rs"; add_rust_profiling_configurations($supported, $profilingPath); if (empty($supported)) { @@ -383,6 +388,7 @@ extract_c_supported_configurations() { # across developer machines and CI runners. "${CPP_COMPILER_CMD[@]}" $(php-config --includes) -I.. -I../ext -I../zend_abstract_interface -I../src/dogstatsd -I../components-rs -x c -E - <root_span->asm_event_emitted = true; ddtrace_trace_source_set_asm_source(); } else { - DDTRACE_G(asm_event_emitted) = true; + DATADOG_G(asm_event_emitted) = true; } ddtrace_set_priority_sampling_on_root(PRIORITY_SAMPLING_USER_KEEP, DD_MECHANISM_ASM); @@ -31,9 +32,9 @@ PHP_FUNCTION(DDTrace_Testing_emit_asm_event) { } bool ddtrace_asm_event_emitted() { - return DDTRACE_G(asm_event_emitted) || (DDTRACE_G(active_stack) && DDTRACE_G(active_stack)->root_span && DDTRACE_G(active_stack)->root_span->asm_event_emitted); + return DATADOG_G(asm_event_emitted) || (DDTRACE_G(active_stack) && DDTRACE_G(active_stack)->root_span && DDTRACE_G(active_stack)->root_span->asm_event_emitted); } void ddtrace_asm_event_rinit() { - DDTRACE_G(asm_event_emitted) = false; + DATADOG_G(asm_event_emitted) = false; } diff --git a/ext/asm_event.h b/tracer/asm_event.h similarity index 66% rename from ext/asm_event.h rename to tracer/asm_event.h index 988cdd8e088..c76763dcff0 100644 --- a/ext/asm_event.h +++ b/tracer/asm_event.h @@ -2,9 +2,9 @@ #define ASM_EVENT_H #include "ddtrace.h" -#include "ddtrace_export.h" +#include -DDTRACE_PUBLIC void ddtrace_emit_asm_event(); +DATADOG_PUBLIC void ddtrace_emit_asm_event(); bool ddtrace_asm_event_emitted(); void ddtrace_asm_event_rinit(); diff --git a/ext/auto_flush.c b/tracer/auto_flush.c similarity index 64% rename from ext/auto_flush.c rename to tracer/auto_flush.c index 50faf8fdf88..1e1a45eff7e 100644 --- a/ext/auto_flush.c +++ b/tracer/auto_flush.c @@ -1,24 +1,24 @@ #include "auto_flush.h" +#include #include "asm_event.h" #ifndef _WIN32 #include "comms_php.h" #include "coms.h" #endif -#include "ddtrace_string.h" #include "configuration.h" #include #include "serializer.h" #include "span.h" -#include "sidecar.h" +#include #include "trace_source.h" -#include "ddshared.h" +#include "rule_matching.h" #include "standalone_limiter.h" #include
#include #include -ZEND_EXTERN_MODULE_GLOBALS(ddtrace); +ZEND_EXTERN_MODULE_GLOBALS(datadog); ZEND_RESULT_CODE ddtrace_flush_tracer(bool force_on_startup, bool collect_cycles, bool fast_shutdown) { bool success = true; @@ -45,10 +45,10 @@ ZEND_RESULT_CODE ddtrace_flush_tracer(bool force_on_startup, bool collect_cycles } size_t limit = get_global_DD_TRACE_AGENT_MAX_PAYLOAD_SIZE(); - char *url = ddtrace_agent_url(); + char *url = datadog_agent_url(); if (get_global_DD_TRACE_SIDECAR_TRACE_SENDER()) { - if (DDTRACE_G(sidecar)) { + if (DATADOG_G(sidecar)) { ddog_SenderParameters parameters = { .tracer_headers_tags = { .container_id = ddtrace_get_container_id(), @@ -60,8 +60,8 @@ ZEND_RESULT_CODE ddtrace_flush_tracer(bool force_on_startup, bool collect_cycles .client_computed_top_level = get_DD_TRACE_STATS_COMPUTATION_ENABLED(), .client_computed_stats = !get_global_DD_APM_TRACING_ENABLED() || (get_DD_TRACE_STATS_COMPUTATION_ENABLED() && ddog_agent_has_stats_computation()), }, - .transport = DDTRACE_G(sidecar), - .instance_id = ddtrace_sidecar_instance_id, + .transport = DATADOG_G(sidecar), + .instance_id = datadog_sidecar_instance_id, .limit = limit, .n_requests = get_global_DD_TRACE_AGENT_FLUSH_AFTER_N_REQUESTS(), .buffer_size = get_global_DD_TRACE_BUFFER_SIZE(), @@ -111,58 +111,8 @@ ZEND_RESULT_CODE ddtrace_flush_tracer(bool force_on_startup, bool collect_cycles return success ? SUCCESS : FAILURE; } -DDTRACE_PUBLIC void ddtrace_close_all_spans_and_flush() +DATADOG_PUBLIC void ddtrace_close_all_spans_and_flush() { ddtrace_close_all_open_spans(true); ddtrace_flush_tracer(true, true, false); } - -#define DEFAULT_UDS_PATH "/var/run/datadog/apm.socket" - -char *ddtrace_agent_url(void) { - zend_string *url = get_global_DD_TRACE_AGENT_URL(); - if (ZSTR_LEN(url) > 0) { - char *dup = zend_strndup(ZSTR_VAL(url), ZSTR_LEN(url) + 1); - - // mess around with backslashes to support our test cases providing something like "file://C:\dir\test.out" - const char *fileprefix = "file://"; - if (strncmp(ZSTR_VAL(url), fileprefix, strlen(fileprefix)) == 0 && strchr(ZSTR_VAL(url), '\\')) { - for (size_t i = strlen(fileprefix); i < ZSTR_LEN(url); ++i) { - if (dup[i] == '\\') { - dup[i] = '/'; - } - } - } - - return dup; - } - - zend_string *hostname = get_global_DD_AGENT_HOST(); - if (ZSTR_LEN(hostname) > 7 && strncmp(ZSTR_VAL(hostname), "unix://", 7) == 0) { - return zend_strndup(ZSTR_VAL(hostname), ZSTR_LEN(hostname)); - } - - if (ZSTR_LEN(hostname) > 0 && zai_config_memoized_entries[DDTRACE_CONFIG_DD_AGENT_HOST].name_index != ZAI_CONFIG_ORIGIN_DEFAULT) { - bool isIPv6 = memchr(ZSTR_VAL(hostname), ':', ZSTR_LEN(hostname)); - - int64_t port = get_global_DD_TRACE_AGENT_PORT(); - if (port <= 0 || port > 65535) { - port = 8126; - } - char *formatted_url; - asprintf(&formatted_url, isIPv6 ? HOST_V6_FORMAT_STR : HOST_V4_FORMAT_STR, ZSTR_VAL(hostname), (uint32_t)port); - return formatted_url; - } - - if (access(DEFAULT_UDS_PATH, F_OK) == SUCCESS) { - return zend_strndup(ZEND_STRL("unix://" DEFAULT_UDS_PATH)); - } - - int64_t port = get_global_DD_TRACE_AGENT_PORT(); - if (port <= 0 || port > 65535) { - port = 8126; - } - char *formatted_url; - asprintf(&formatted_url, HOST_V4_FORMAT_STR, "localhost", (uint32_t)port); - return formatted_url; -} diff --git a/ext/auto_flush.h b/tracer/auto_flush.h similarity index 70% rename from ext/auto_flush.h rename to tracer/auto_flush.h index f4d793b1772..3f3c0c08826 100644 --- a/ext/auto_flush.h +++ b/tracer/auto_flush.h @@ -1,15 +1,13 @@ #ifndef DDTRACE_AUTO_FLUSH_H #define DDTRACE_AUTO_FLUSH_H -#include +#include #include #include ZEND_RESULT_CODE ddtrace_flush_tracer(bool force_on_startup, bool collect_cycles, bool fast_shutdown); // This function is exported and used by appsec -DDTRACE_PUBLIC void ddtrace_close_all_spans_and_flush(void); - -char *ddtrace_agent_url(void); +DATADOG_PUBLIC void ddtrace_close_all_spans_and_flush(void); #endif // DDTRACE_AUTO_FLUSH_H diff --git a/ext/autoload_php_files.c b/tracer/autoload_php_files.c similarity index 99% rename from ext/autoload_php_files.c rename to tracer/autoload_php_files.c index 246008d4c19..92903e01d8d 100644 --- a/ext/autoload_php_files.c +++ b/tracer/autoload_php_files.c @@ -11,11 +11,11 @@ #include "configuration.h" #include "ddtrace.h" #include "engine_hooks.h" -#include "telemetry.h" +#include #include #include -ZEND_EXTERN_MODULE_GLOBALS(ddtrace); +ZEND_EXTERN_MODULE_GLOBALS(datadog); #if PHP_VERSION_ID < 80000 zif_handler dd_spl_autoload_fn_handler; diff --git a/ext/autoload_php_files.h b/tracer/autoload_php_files.h similarity index 89% rename from ext/autoload_php_files.h rename to tracer/autoload_php_files.h index d26bc7a3a19..dcb5c2c21e8 100644 --- a/ext/autoload_php_files.h +++ b/tracer/autoload_php_files.h @@ -4,7 +4,7 @@ #include #include -#include "compatibility.h" +#include void ddtrace_autoload_minit(void); #if PHP_VERSION_ID < 80000 diff --git a/ext/code_origins.c b/tracer/code_origins.c similarity index 100% rename from ext/code_origins.c rename to tracer/code_origins.c diff --git a/ext/code_origins.h b/tracer/code_origins.h similarity index 100% rename from ext/code_origins.h rename to tracer/code_origins.h diff --git a/ext/collect_backtrace.c b/tracer/collect_backtrace.c similarity index 99% rename from ext/collect_backtrace.c rename to tracer/collect_backtrace.c index 7086de471a7..5b1d4fe1df8 100644 --- a/ext/collect_backtrace.c +++ b/tracer/collect_backtrace.c @@ -6,7 +6,7 @@ #include #endif #include -#include "compatibility.h" +#include // skip_args to not capture args if anyway captured via !DEBUG_BACKTRACE_IGNORE_ARGS void ddtrace_call_get_locals(zend_execute_data *call, zval *locals_array, bool skip_args) { diff --git a/ext/collect_backtrace.h b/tracer/collect_backtrace.h similarity index 100% rename from ext/collect_backtrace.h rename to tracer/collect_backtrace.h diff --git a/ext/comms_php.c b/tracer/comms_php.c similarity index 97% rename from ext/comms_php.c rename to tracer/comms_php.c index 4e7c51101e8..019a5452e61 100644 --- a/ext/comms_php.c +++ b/tracer/comms_php.c @@ -7,7 +7,7 @@ #include #include "mpack/mpack.h" -ZEND_EXTERN_MODULE_GLOBALS(ddtrace); +ZEND_EXTERN_MODULE_GLOBALS(datadog); bool ddtrace_send_traces_via_thread(size_t num_traces, const char *payload, size_t payload_len) { if (!get_DD_TRACE_ENABLED()) { diff --git a/ext/comms_php.h b/tracer/comms_php.h similarity index 89% rename from ext/comms_php.h rename to tracer/comms_php.h index 43133f19dcb..3b51ac797e4 100644 --- a/ext/comms_php.h +++ b/tracer/comms_php.h @@ -5,7 +5,7 @@ #include #include -#include "compatibility.h" +#include bool ddtrace_send_traces_via_thread(size_t num_traces, const char *payload, size_t payload_len); diff --git a/ext/coms.c b/tracer/coms.c similarity index 80% rename from ext/coms.c rename to tracer/coms.c index 91d46857051..d91d298136f 100644 --- a/ext/coms.c +++ b/tracer/coms.c @@ -13,7 +13,7 @@ // For reasons it doesn't find asprintf() if this isn't included later... #include "coms.h" -#include "telemetry.h" +#include #include #ifdef HAVE_CONFIG_H @@ -30,19 +30,24 @@ #endif #include "auto_flush.h" -#include "compatibility.h" +#include #include "configuration.h" -#include "ddshared.h" #include "ddtrace.h" -#include "ext/version.h" -#include "logging.h" +#include +#include +#include +#include +#include "tracer_telemetry.h" #include "mpack/mpack.h" -#include "sidecar.h" +#include #include "zend_smart_str.h" extern inline bool ddtrace_coms_is_stack_unused(ddtrace_coms_stack_t *stack); extern inline bool ddtrace_coms_is_stack_free(ddtrace_coms_stack_t *stack); +/* guard our logging in the whole file */ +#define datadog_signal_safe_logf(fmt, ...) (get_global_DD_TRACE_DEBUG_CURL_OUTPUT() ? datadog_signal_safe_logf(fmt, __VA_ARGS__) : 0) + typedef uint32_t group_id_t; #define GROUP_ID_PROCESSED (1UL << 31UL) @@ -125,7 +130,7 @@ void ddtrace_coms_mshutdown_proxy_env(void) { ddtrace_env_all_proxy = NULL; } -static bool _dd_is_memory_pressure_high(void) { +static bool dd_is_memory_pressure_high(void) { ddtrace_coms_stack_t *stack = atomic_load(&ddtrace_coms_globals.current_stack); if (stack) { int64_t used = (((double)atomic_load(&stack->position) / (double)stack->size) * 100); @@ -139,7 +144,7 @@ static bool _dd_is_memory_pressure_high(void) { * there is not enough memory left in the currently active stack, it does not attempt to generate a new stack, instead * it returns a `ENOMEM` code that should be read by the invoker that can manually decide to ask for a larger stack. */ -static uint32_t _dd_store_data(group_id_t group_id, const char *src, size_t size) { +static uint32_t dd_store_data(group_id_t group_id, const char *src, size_t size) { ddtrace_coms_stack_t *stack = atomic_load(&ddtrace_coms_globals.current_stack); if (stack == NULL) { // no stack to save data to @@ -176,7 +181,7 @@ static uint32_t _dd_store_data(group_id_t group_id, const char *src, size_t size * The rationale behind this is that once we know that at least one single trace can be larger than X bytes, then * all the subsequent stacks are allocated at least as large as that size. */ -static ddtrace_coms_stack_t *_dd_new_stack(size_t min_size) { +static ddtrace_coms_stack_t *dd_new_stack(size_t min_size) { size_t initial_size = atomic_load(&ddtrace_coms_globals.stack_size); size_t size = initial_size; while (min_size > size && size <= (ddtrace_coms_globals.max_payload_size/2)) { @@ -199,12 +204,12 @@ static ddtrace_coms_stack_t *_dd_new_stack(size_t min_size) { return stack; } -static void _dd_coms_free_stack(ddtrace_coms_stack_t *stack) { +static void dd_coms_free_stack(ddtrace_coms_stack_t *stack) { free(stack->data); free(stack); } -static void _dd_recycle_stack(ddtrace_coms_stack_t *stack) { +static void dd_recycle_stack(ddtrace_coms_stack_t *stack) { char *data = stack->data; size_t size = stack->size; @@ -215,28 +220,24 @@ static void _dd_recycle_stack(ddtrace_coms_stack_t *stack) { stack->size = size; } -static void (*_dd_ptr_at_exit_callback)(void) = 0; +static void (*dd_ptr_at_exit_callback)(void) = 0; -static void _dd_at_exit_callback() { ddtrace_coms_flush_shutdown_writer_synchronous(); } +static void dd_at_exit_callback() { ddtrace_coms_flush_shutdown_writer_synchronous(); } -static void _dd_at_exit_hook() { - if (_dd_ptr_at_exit_callback) { - _dd_ptr_at_exit_callback(); +static void dd_at_exit_hook() { + if (dd_ptr_at_exit_callback) { + dd_ptr_at_exit_callback(); } } -bool ddtrace_coms_minit(size_t initial_stack_size, size_t max_stack_size, size_t max_backlog_size, char *bgs_fallback_telemetry_service) { +bool ddtrace_coms_minit(size_t initial_stack_size, size_t max_stack_size, size_t max_backlog_size) { ddtrace_coms_globals.initial_stack_size = initial_stack_size; ddtrace_coms_globals.max_payload_size = max_stack_size; ddtrace_coms_globals.max_backlog_size = max_backlog_size; - ddtrace_coms_globals.bgs_fallback_telemetry = bgs_fallback_telemetry_service != NULL; - if (bgs_fallback_telemetry_service) { - strncpy(ddtrace_coms_globals.initial_service_name, bgs_fallback_telemetry_service, sizeof(ddtrace_coms_globals.initial_service_name) - 1); - } atomic_store(&ddtrace_coms_globals.stack_size, initial_stack_size); - ddtrace_coms_stack_t *stack = _dd_new_stack(initial_stack_size); + ddtrace_coms_stack_t *stack = dd_new_stack(initial_stack_size); if (!ddtrace_coms_globals.stacks) { ddtrace_coms_globals.stacks = calloc(max_backlog_size, sizeof(ddtrace_coms_stack_t *)); } @@ -246,8 +247,8 @@ bool ddtrace_coms_minit(size_t initial_stack_size, size_t max_stack_size, size_t ddtrace_coms_globals.tmp_stack = NULL; - _dd_ptr_at_exit_callback = _dd_at_exit_callback; - atexit(_dd_at_exit_hook); + dd_ptr_at_exit_callback = dd_at_exit_callback; + atexit(dd_at_exit_hook); if (curl_global_init(CURL_GLOBAL_DEFAULT) != CURLE_OK) { return false; @@ -256,9 +257,9 @@ bool ddtrace_coms_minit(size_t initial_stack_size, size_t max_stack_size, size_t return true; } -void ddtrace_coms_mshutdown(void) { _dd_ptr_at_exit_callback = NULL; } +void ddtrace_coms_mshutdown(void) { dd_ptr_at_exit_callback = NULL; } -static void _dd_coms_stack_shutdown(void) { +static void dd_coms_stack_shutdown(void) { ddtrace_coms_stack_t *current_stack = atomic_load(&ddtrace_coms_globals.current_stack); if (current_stack) { if (current_stack->data) { @@ -280,7 +281,7 @@ static void printf_stack_info(ddtrace_coms_stack_t *stack) { } #endif -static void _dd_unsafe_store_or_discard_stack(ddtrace_coms_stack_t *stack) { +static void dd_unsafe_store_or_discard_stack(ddtrace_coms_stack_t *stack) { for (size_t i = 0; i < ddtrace_coms_globals.max_backlog_size; i++) { ddtrace_coms_stack_t *stack_tmp = ddtrace_coms_globals.stacks[i]; if (stack_tmp == stack) { @@ -293,10 +294,10 @@ static void _dd_unsafe_store_or_discard_stack(ddtrace_coms_stack_t *stack) { } } - _dd_coms_free_stack(stack); + dd_coms_free_stack(stack); } -static void _dd_unsafe_cleanup_dirty_stack_area(void) { +static void dd_unsafe_cleanup_dirty_stack_area(void) { ddtrace_coms_stack_t *current_stack = atomic_load(&ddtrace_coms_globals.current_stack); if (!ddtrace_coms_globals.tmp_stack) { return; @@ -306,7 +307,7 @@ static void _dd_unsafe_cleanup_dirty_stack_area(void) { ddtrace_coms_stack_t *stack = ddtrace_coms_globals.tmp_stack; atomic_store(&stack->refcount, 0); - _dd_unsafe_store_or_discard_stack(stack); + dd_unsafe_store_or_discard_stack(stack); } ddtrace_coms_globals.tmp_stack = NULL; } @@ -322,8 +323,8 @@ static void _dd_unsafe_cleanup_dirty_stack_area(void) { * no available existing stacks that could store `min_size` bytes and it is the invoker's own responsibility to allocate * a new stack of the desired size and assign it to the global current stack. */ -static void _dd_unsafe_store_or_swap_current_stack_for_empty_stack(size_t min_size) { - _dd_unsafe_cleanup_dirty_stack_area(); +static void dd_unsafe_store_or_swap_current_stack_for_empty_stack(size_t min_size) { + dd_unsafe_cleanup_dirty_stack_area(); // store the temp variable if we ever need to recover it ddtrace_coms_stack_t **current_stack = &ddtrace_coms_globals.tmp_stack; @@ -341,7 +342,7 @@ static void _dd_unsafe_store_or_swap_current_stack_for_empty_stack(size_t min_si ddtrace_coms_stack_t *stack_tmp = ddtrace_coms_globals.stacks[i]; if (stack_tmp && stack_tmp->size >= min_size && ddtrace_coms_is_stack_free(stack_tmp)) { // order is important due to ability to restore state on thread restart - _dd_recycle_stack(stack_tmp); + dd_recycle_stack(stack_tmp); atomic_store(&ddtrace_coms_globals.current_stack, stack_tmp); ddtrace_coms_globals.stacks[i] = *current_stack; @@ -368,8 +369,8 @@ static void _dd_unsafe_store_or_swap_current_stack_for_empty_stack(size_t min_si *current_stack = NULL; } -static bool _dd_coms_unsafe_rotate_stack(bool attempt_allocate_new, size_t min_size) { - _dd_unsafe_store_or_swap_current_stack_for_empty_stack(min_size); +static bool dd_coms_unsafe_rotate_stack(bool attempt_allocate_new, size_t min_size) { + dd_unsafe_store_or_swap_current_stack_for_empty_stack(min_size); ddtrace_coms_stack_t *current_stack = atomic_load(&ddtrace_coms_globals.current_stack); @@ -388,7 +389,7 @@ static bool _dd_coms_unsafe_rotate_stack(bool attempt_allocate_new, size_t min_s if (!current_stack) { if (attempt_allocate_new) { ddtrace_coms_stack_t **next_stack = &ddtrace_coms_globals.tmp_stack; - *next_stack = _dd_new_stack(min_size); + *next_stack = dd_new_stack(min_size); atomic_store(&ddtrace_coms_globals.current_stack, *next_stack); *next_stack = NULL; return true; @@ -432,14 +433,14 @@ static struct _writer_loop_data_t global_writer = {.thread = NULL, .allocate_new_stacks = ATOMIC_VAR_INIT(0), .sending = ATOMIC_VAR_INIT(0)}; -static struct _writer_loop_data_t *_dd_get_writer() { return &global_writer; } +static struct _writer_loop_data_t *dd_get_writer() { return &global_writer; } static bool ddtrace_coms_threadsafe_rotate_stack(bool attempt_allocate_new, size_t min_size) { - struct _writer_loop_data_t *writer = _dd_get_writer(); + struct _writer_loop_data_t *writer = dd_get_writer(); bool rv = false; if (writer->thread) { pthread_mutex_lock(&writer->thread->stack_rotation_mutex); - rv = _dd_coms_unsafe_rotate_stack(attempt_allocate_new, min_size); + rv = dd_coms_unsafe_rotate_stack(attempt_allocate_new, min_size); pthread_mutex_unlock(&writer->thread->stack_rotation_mutex); } return rv; @@ -457,9 +458,9 @@ bool ddtrace_coms_buffer_data(uint32_t group_id, const char *data, size_t size) } } - uint32_t store_result = _dd_store_data(group_id, data, size); + uint32_t store_result = dd_store_data(group_id, data, size); - if (_dd_is_memory_pressure_high()) { + if (dd_is_memory_pressure_high()) { ddtrace_coms_trigger_writer_flush(); } @@ -467,7 +468,7 @@ bool ddtrace_coms_buffer_data(uint32_t group_id, const char *data, size_t size) size_t padding = 2; ddtrace_coms_threadsafe_rotate_stack(true, size + padding); ddtrace_coms_trigger_writer_flush(); - store_result = _dd_store_data(group_id, data, size); + store_result = dd_store_data(group_id, data, size); } return store_result == 0; @@ -483,7 +484,7 @@ struct _grouped_stack_t { size_t dest_size; }; -static size_t _dd_write_array_header(char *buffer, size_t buffer_size, size_t position, uint32_t array_size) { +static size_t dd_write_array_header(char *buffer, size_t buffer_size, size_t position, uint32_t array_size) { size_t free_space = buffer_size - position; char *data = buffer + position; if (array_size < 16) { @@ -508,7 +509,7 @@ static size_t _dd_write_array_header(char *buffer, size_t buffer_size, size_t po return 0; } -static size_t _dd_write_to_buffer(char *buffer, size_t buffer_size, size_t position, struct _grouped_stack_t *read) { +static size_t dd_write_to_buffer(char *buffer, size_t buffer_size, size_t position, struct _grouped_stack_t *read) { size_t write_size = read->bytes_to_write; if (write_size > 0) { if (write_size > (buffer_size - position)) { @@ -527,7 +528,7 @@ static size_t _dd_write_to_buffer(char *buffer, size_t buffer_size, size_t posit return write_size; } -static bool _dd_ensure_correct_dest_capacity(struct _grouped_stack_t *dest, size_t position, size_t write_size) { +static bool dd_ensure_correct_dest_capacity(struct _grouped_stack_t *dest, size_t position, size_t write_size) { size_t requested_size = position + write_size; if (requested_size > dest->dest_size) { @@ -545,16 +546,16 @@ static bool _dd_ensure_correct_dest_capacity(struct _grouped_stack_t *dest, size return true; } -static void _dd_write_metadata(struct _grouped_stack_t *dest, size_t position, size_t elements_in_group, +static void dd_write_metadata(struct _grouped_stack_t *dest, size_t position, size_t elements_in_group, size_t bytes_in_group) { - _dd_ensure_correct_dest_capacity(dest, position, sizeof(size_t) * 2); + dd_ensure_correct_dest_capacity(dest, position, sizeof(size_t) * 2); memcpy(dest->dest_data + position, &elements_in_group, sizeof(size_t)); position += sizeof(size_t); memcpy(dest->dest_data + position, &bytes_in_group, sizeof(size_t)); } -static void _dd_read_metadata(struct _grouped_stack_t *dest, size_t position, size_t *elements_in_group, +static void dd_read_metadata(struct _grouped_stack_t *dest, size_t position, size_t *elements_in_group, size_t *bytes_in_group) { memcpy(elements_in_group, dest->dest_data + position, sizeof(size_t)); @@ -562,7 +563,7 @@ static void _dd_read_metadata(struct _grouped_stack_t *dest, size_t position, si memcpy(bytes_in_group, dest->dest_data + position, sizeof(size_t)); } -static size_t _dd_coms_read_callback(char *buffer, size_t size, size_t nitems, void *userdata) { +static size_t dd_coms_read_callback(char *buffer, size_t size, size_t nitems, void *userdata) { if (!userdata) { return 0; } @@ -572,12 +573,12 @@ static size_t _dd_coms_read_callback(char *buffer, size_t size, size_t nitems, v size_t buffer_size = size * nitems; if (read->total_groups > 0) { - written += _dd_write_array_header(buffer, buffer_size, written, read->total_groups); + written += dd_write_array_header(buffer, buffer_size, written, read->total_groups); read->total_groups = 0; } // write the remainder from previous iteration - written += _dd_write_to_buffer(buffer, buffer_size, written, read); + written += dd_write_to_buffer(buffer, buffer_size, written, read); while (written < buffer_size) { // safe read size check position + metadata @@ -586,14 +587,14 @@ static size_t _dd_coms_read_callback(char *buffer, size_t size, size_t nitems, v } size_t num_elements = 0; - _dd_read_metadata(read, read->position, &num_elements, &read->bytes_to_write); + dd_read_metadata(read, read->position, &num_elements, &read->bytes_to_write); if (read->bytes_to_write == 0) { break; } // written += _dd_write_array_header(buffer, buffer_size, written, num_elements); read->position += sizeof(size_t) * 2; - written += _dd_write_to_buffer(buffer, buffer_size, written, read); + written += dd_write_to_buffer(buffer, buffer_size, written, read); } return written; @@ -607,7 +608,7 @@ struct _entry_t { char *raw_entry; }; -static struct _entry_t _dd_create_entry(ddtrace_coms_stack_t *stack, size_t position) { +static struct _entry_t dd_create_entry(ddtrace_coms_stack_t *stack, size_t position) { struct _entry_t rv = {.size = 0, .group_id = 0, .data = NULL, .next_entry_offset = 0}; size_t bytes_written = atomic_load(&stack->bytes_written); @@ -631,13 +632,13 @@ static struct _entry_t _dd_create_entry(ddtrace_coms_stack_t *stack, size_t posi return rv; } -static void _dd_mark_entry_as_processed(struct _entry_t *entry) { +static void dd_mark_entry_as_processed(struct _entry_t *entry) { group_id_t processed_special_id = GROUP_ID_PROCESSED; memcpy(entry->raw_entry + sizeof(size_t), &processed_special_id, sizeof(group_id_t)); } -static size_t _dd_append_entry(struct _entry_t *entry, struct _grouped_stack_t *dest, size_t position) { - if (_dd_ensure_correct_dest_capacity(dest, position, entry->size)) { +static size_t dd_append_entry(struct _entry_t *entry, struct _grouped_stack_t *dest, size_t position) { + if (dd_ensure_correct_dest_capacity(dest, position, entry->size)) { memcpy(dest->dest_data + position, entry->data, entry->size); return entry->size; } else { @@ -645,10 +646,10 @@ static size_t _dd_append_entry(struct _entry_t *entry, struct _grouped_stack_t * } } -static void _dd_msgpack_group_stack_by_id(ddtrace_coms_stack_t *stack, struct _grouped_stack_t *dest) { +static void dd_msgpack_group_stack_by_id(ddtrace_coms_stack_t *stack, struct _grouped_stack_t *dest) { // perform an insertion sort by group_id uint32_t current_group_id = 0; - struct _entry_t first_entry = _dd_create_entry(stack, 0); + struct _entry_t first_entry = dd_create_entry(stack, 0); dest->total_bytes = 0; dest->total_groups = 0; @@ -673,15 +674,15 @@ static void _dd_msgpack_group_stack_by_id(ddtrace_coms_stack_t *stack, struct _g size_t bytes_in_group = 0; group_dest_position += sizeof(size_t) * 2; // leave place for group meta data while (current_src_position < bytes_written) { - struct _entry_t entry = _dd_create_entry(stack, current_src_position); + struct _entry_t entry = dd_create_entry(stack, current_src_position); if (entry.size == 0) { break; } if (entry.group_id == current_group_id) { - size_t copied = _dd_append_entry(&entry, dest, group_dest_position); + size_t copied = dd_append_entry(&entry, dest, group_dest_position); if (copied > 0) { - _dd_mark_entry_as_processed(&entry); + dd_mark_entry_as_processed(&entry); elements_in_group++; group_dest_position += copied; bytes_in_group += copied; @@ -694,7 +695,7 @@ static void _dd_msgpack_group_stack_by_id(ddtrace_coms_stack_t *stack, struct _g current_src_position += entry.next_entry_offset; } - _dd_write_metadata(dest, group_dest_beginning_position, elements_in_group, bytes_in_group); + dd_write_metadata(dest, group_dest_beginning_position, elements_in_group, bytes_in_group); group_dest_beginning_position = group_dest_position; // no new groups - exit loop @@ -708,7 +709,7 @@ static void _dd_msgpack_group_stack_by_id(ddtrace_coms_stack_t *stack, struct _g dest->total_bytes = group_dest_beginning_position; // save total bytes count after conversion } -static void *_dd_init_read_userdata(ddtrace_coms_stack_t *stack) { +static void *dd_init_read_userdata(ddtrace_coms_stack_t *stack) { size_t total_bytes = atomic_load(&stack->bytes_written); struct _grouped_stack_t *readstack = calloc(1, sizeof(struct _grouped_stack_t)); @@ -716,12 +717,12 @@ static void *_dd_init_read_userdata(ddtrace_coms_stack_t *stack) { readstack->dest_size = atomic_load(&stack->bytes_written) + 2000; readstack->dest_data = malloc(readstack->dest_size); - _dd_msgpack_group_stack_by_id(stack, readstack); + dd_msgpack_group_stack_by_id(stack, readstack); return readstack; } -static void _dd_deinit_read_userdata(void *userdata) { +static void dd_deinit_read_userdata(void *userdata) { struct _grouped_stack_t *data = userdata; if (data->dest_data) { free(data->dest_data); @@ -729,7 +730,7 @@ static void _dd_deinit_read_userdata(void *userdata) { free(userdata); } -static ddtrace_coms_stack_t *_dd_coms_attempt_acquire_stack(void) { +static ddtrace_coms_stack_t *dd_coms_attempt_acquire_stack(void) { ddtrace_coms_stack_t *stack = NULL; if (!ddtrace_coms_globals.stacks) { @@ -803,20 +804,20 @@ void ddtrace_coms_curl_shutdown(void) { } } -static long _dd_max_long(long a, long b) { return a >= b ? a : b; } +static long dd_max_long(long a, long b) { return a >= b ? a : b; } void ddtrace_curl_set_timeout(CURL *curl) { - long timeout = _dd_max_long(get_global_DD_TRACE_BGS_TIMEOUT(), get_global_DD_TRACE_AGENT_TIMEOUT()); + long timeout = dd_max_long(get_global_DD_TRACE_BGS_TIMEOUT(), get_global_DD_TRACE_AGENT_TIMEOUT()); curl_easy_setopt(curl, CURLOPT_TIMEOUT_MS, timeout); } void ddtrace_curl_set_connect_timeout(CURL *curl) { - long timeout = _dd_max_long(get_global_DD_TRACE_BGS_CONNECT_TIMEOUT(), get_global_DD_TRACE_AGENT_CONNECT_TIMEOUT()); + long timeout = dd_max_long(get_global_DD_TRACE_BGS_CONNECT_TIMEOUT(), get_global_DD_TRACE_AGENT_CONNECT_TIMEOUT()); curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT_MS, timeout); } static void ddtrace_curl_set_hostname_generic(CURL *curl, const char *path) { - char *url = ddtrace_agent_url(); + char *url = datadog_agent_url(); /* Prevent libcurl from reading no_proxy/NO_PROXY in worker threads: * always set CURLOPT_NOPROXY on this handle. If the env had a value @@ -895,7 +896,7 @@ void ddtrace_curl_set_telemetry_url(CURL *curl) { ddtrace_curl_set_hostname_generic(curl, "/telemetry/proxy/api/v2/apmtelemetry"); } -static struct timespec _dd_deadline_in_ms(uint32_t ms) { +static struct timespec dd_deadline_in_ms(uint32_t ms) { struct timespec deadline; struct timeval now; @@ -912,14 +913,14 @@ static struct timespec _dd_deadline_in_ms(uint32_t ms) { return deadline; } -static size_t _dd_dummy_write_callback(char *ptr, size_t size, size_t nmemb, void *userdata) { +static size_t dd_dummy_write_callback(char *ptr, size_t size, size_t nmemb, void *userdata) { UNUSED(userdata); size_t data_length = size * nmemb; - ddtrace_bgs_logf("%s", ptr); + datadog_signal_safe_logf("%s", ptr); return data_length; } -static void _dd_curl_reset_headers(struct _writer_loop_data_t *writer) { +static void dd_curl_reset_headers(struct _writer_loop_data_t *writer) { struct curl_slist *headers = atomic_exchange(&writer->headers, NULL); if (headers) { curl_slist_free_all(headers); @@ -928,7 +929,7 @@ static void _dd_curl_reset_headers(struct _writer_loop_data_t *writer) { #define DD_TRACE_COUNT_HEADER "X-Datadog-Trace-Count: " -static void _dd_curl_set_headers(struct _writer_loop_data_t *writer, size_t trace_count) { +static void dd_curl_set_headers(struct _writer_loop_data_t *writer, size_t trace_count) { struct curl_slist *headers = NULL; for (struct curl_slist *current = dd_agent_curl_headers; current; current = current->next) { headers = curl_slist_append(headers, current->data); @@ -952,30 +953,30 @@ static void _dd_curl_set_headers(struct _writer_loop_data_t *writer, size_t trac headers = curl_slist_append(headers, buffer); } - _dd_curl_reset_headers(writer); + dd_curl_reset_headers(writer); curl_easy_setopt(writer->curl, CURLOPT_HTTPHEADER, headers); writer->headers = headers; } -static size_t _dd_curl_writefunc(char *ptr, size_t size, size_t nmemb, void *s) { +static size_t dd_curl_writefunc(char *ptr, size_t size, size_t nmemb, void *s) { smart_str_appendl_ex((smart_str *)s, ptr, size * nmemb, true); return size * nmemb; } -static void _dd_curl_send_stack(struct _writer_loop_data_t *writer, ddtrace_coms_stack_t *stack, trace_api_metrics *metrics) { +static void dd_curl_send_stack(struct _writer_loop_data_t *writer, ddtrace_coms_stack_t *stack, trace_api_metrics *metrics) { if (!writer->curl) { - ddtrace_bgs_logf("[bgs] no curl session - dropping the current stack.\n", NULL); + datadog_signal_safe_logf("[bgs] no curl session - dropping the current stack.\n", NULL); return; } - void *read_data = _dd_init_read_userdata(stack); + void *read_data = dd_init_read_userdata(stack); struct _grouped_stack_t *kData = read_data; int retries = MAX(get_global_DD_TRACE_AGENT_RETRIES(), 0) + 1; CURLcode res = CURLE_UNSUPPORTED_PROTOCOL; // Set a default value to avoid compiler warning for (int retry = 0; retry < retries; retry++) { - _dd_curl_set_headers(writer, kData->total_groups); + dd_curl_set_headers(writer, kData->total_groups); curl_easy_setopt(writer->curl, CURLOPT_READDATA, read_data); ddtrace_curl_set_hostname(writer->curl); ddtrace_curl_set_timeout(writer->curl); @@ -985,20 +986,20 @@ static void _dd_curl_send_stack(struct _writer_loop_data_t *writer, ddtrace_coms curl_easy_setopt(writer->curl, CURLOPT_UPLOAD, 1); curl_easy_setopt(writer->curl, CURLOPT_VERBOSE, (long) get_global_DD_TRACE_AGENT_DEBUG_VERBOSE_CURL()); - curl_easy_setopt(writer->curl, CURLOPT_WRITEFUNCTION, _dd_curl_writefunc); + curl_easy_setopt(writer->curl, CURLOPT_WRITEFUNCTION, dd_curl_writefunc); curl_easy_setopt(writer->curl, CURLOPT_WRITEDATA, &response); res = curl_easy_perform(writer->curl); if (res != CURLE_OK) { - ddtrace_bgs_logf("[bgs] curl_easy_perform() failed: %s\n", curl_easy_strerror(res)); + datadog_signal_safe_logf("[bgs] curl_easy_perform() failed: %s\n", curl_easy_strerror(res)); CURL *curl = writer->curl; writer->curl = NULL; curl_easy_cleanup(curl); writer->curl = curl_easy_init(); - curl_easy_setopt(writer->curl, CURLOPT_READFUNCTION, _dd_coms_read_callback); - curl_easy_setopt(writer->curl, CURLOPT_WRITEFUNCTION, _dd_dummy_write_callback); + curl_easy_setopt(writer->curl, CURLOPT_READFUNCTION, dd_coms_read_callback); + curl_easy_setopt(writer->curl, CURLOPT_WRITEFUNCTION, dd_dummy_write_callback); // as per https://curl.se/libcurl/c/threadsafe.html // Also note that the docs mention potential SIGPIPEs, which may occur with OpenSSL: // We can ignore that for now as we don't do TLS traffic to the agent currently @@ -1022,7 +1023,7 @@ static void _dd_curl_send_stack(struct _writer_loop_data_t *writer, ddtrace_coms #pragma GCC diagnostic ignored "-Wdeprecated-declarations" curl_easy_getinfo(writer->curl, CURLINFO_SIZE_UPLOAD, &uploaded); #pragma GCC diagnostic pop - ddtrace_bgs_logf("[bgs] uploaded %.0f bytes\n", uploaded); + datadog_signal_safe_logf("[bgs] uploaded %.0f bytes\n", uploaded); } // No response happens with test agents for example @@ -1061,11 +1062,11 @@ static void _dd_curl_send_stack(struct _writer_loop_data_t *writer, ddtrace_coms metrics->errors_network++; } - _dd_deinit_read_userdata(read_data); - _dd_curl_reset_headers(writer); + dd_deinit_read_userdata(read_data); + dd_curl_reset_headers(writer); } -static void _dd_signal_writer_started(struct _writer_loop_data_t *writer) { +static void dd_signal_writer_started(struct _writer_loop_data_t *writer) { if (writer->thread) { // at the moment no actual signal is sent but we will set a threadsafe state variable // ordering is important to correctly state that writer is either running or stil is starting up @@ -1074,7 +1075,7 @@ static void _dd_signal_writer_started(struct _writer_loop_data_t *writer) { } } -static void _dd_signal_writer_finished(struct _writer_loop_data_t *writer) { +static void dd_signal_writer_finished(struct _writer_loop_data_t *writer) { if (writer->thread) { pthread_mutex_lock(&writer->thread->writer_shutdown_signal_mutex); atomic_store(&writer->running, false); @@ -1084,7 +1085,7 @@ static void _dd_signal_writer_finished(struct _writer_loop_data_t *writer) { } } -static void _dd_signal_data_processed(struct _writer_loop_data_t *writer) { +static void dd_signal_data_processed(struct _writer_loop_data_t *writer) { if (writer->thread) { pthread_mutex_lock(&writer->thread->finished_flush_mutex); pthread_cond_signal(&writer->thread->finished_flush_condition); @@ -1098,14 +1099,14 @@ static void _dd_signal_data_processed(struct _writer_loop_data_t *writer) { #define TIMEOUT_SIG SIGPROF #endif -static void _dd_writer_loop_cleanup(void *ctx) { - _dd_signal_writer_finished((struct _writer_loop_data_t *)ctx); +static void dd_writer_loop_cleanup(void *ctx) { + dd_signal_writer_finished((struct _writer_loop_data_t *)ctx); #ifdef CXA_THREAD_ATEXIT_WRAPPER dd_run_rust_thread_destructors(NULL); #endif } -static void *_dd_writer_loop(void *_) { +static void *dd_writer_loop(void *_) { UNUSED(_); /* This thread must not handle signals intended for the PHP threads. * See Zend/zend_signal.c for which signals it registers. @@ -1121,7 +1122,7 @@ static void *_dd_writer_loop(void *_) { sigaddset(&sigset, SIGUSR2); pthread_sigmask(SIG_BLOCK, &sigset, NULL); - struct _writer_loop_data_t *volatile writer = _dd_get_writer(); + struct _writer_loop_data_t *volatile writer = dd_get_writer(); #if HAVE_LINUX_SECUREBITS_H if (writer->set_secbit) { @@ -1148,95 +1149,20 @@ static void *_dd_writer_loop(void *_) { // nothing we can do here, see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61118 #pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunknown-warning-option" #pragma GCC diagnostic ignored "-Wclobbered" - pthread_cleanup_push(_dd_writer_loop_cleanup, writer); + pthread_cleanup_push(dd_writer_loop_cleanup, writer); #pragma GCC diagnostic pop bool running = true; - _dd_signal_writer_started(writer); - - if (ddtrace_coms_globals.bgs_fallback_telemetry) { - ddtrace_coms_globals.bgs_fallback_telemetry = false; - uint8_t runtime_id[36]; - ddtrace_format_runtime_id(&runtime_id); - char hostname[101]; - hostname[100] = 0; - gethostname(hostname, 100); - char *payload; - asprintf(&payload, "{\n" - " \"api_version\": \"v2\",\n" - " \"request_type\": \"generate-metrics\",\n" - " \"seq_id\": 1,\n" - " \"runtime_id\": \"%.36s\",\n" - " \"tracer_time\": %ld,\n" - " \"payload\": {\n" - " \"namespace\": \"tracers\",\n" - " \"series\": [\n" - " {\n" - " \"metric\": \"exporter_fallback\",\n" - " \"tags\": [\n" - " \"reason:instrumentation_telemetry_disabled\"\n" - " ],\n" - " \"points\": [\n" - " [\n" - " %ld,\n" - " 1\n" - " ]\n" - " ],\n" - " \"type\": \"count\",\n" - " \"common\": true\n" - " }\n" - " ]\n" - " },\n" - " \"application\": {\n" - " \"service_name\": \"%s\",\n" - " \"tracer_version\": \"%s\",\n" - " \"language_name\": \"php\",\n" - " \"language_version\": \"%.*s\"\n" - " },\n" - " \"host\": {\n" - " \"hostname\": \"%s\"\n" - " }\n" - "}", - (char *)runtime_id, - time(NULL), - time(NULL), - ddtrace_coms_globals.initial_service_name, - PHP_DDTRACE_VERSION, - (int)php_version_rt.len, - php_version_rt.ptr, - hostname - ); - - writer->curl = curl_easy_init(); - curl_easy_setopt(writer->curl, CURLOPT_WRITEFUNCTION, _dd_dummy_write_callback); - curl_easy_setopt(writer->curl, CURLOPT_NOSIGNAL, 1); - curl_easy_setopt(writer->curl, CURLOPT_POSTFIELDS, payload); - ddtrace_curl_set_timeout(writer->curl); - ddtrace_curl_set_connect_timeout(writer->curl); - struct curl_slist *headers = curl_slist_append(NULL, "Content-Type: application/json"); - if (*ddtrace_coms_globals.test_session_token) { - char buffer[300]; - sprintf(buffer, "x-datadog-test-session-token: %s", ddtrace_coms_globals.test_session_token); - headers = curl_slist_append(headers, buffer); - } - curl_easy_setopt(writer->curl, CURLOPT_HTTPHEADER, headers); - ddtrace_curl_set_telemetry_url(writer->curl); - curl_easy_perform(writer->curl); - - free(payload); - CURL *curl = writer->curl; - writer->curl = NULL; - curl_easy_cleanup(curl); - curl_slist_free_all(headers); - } + dd_signal_writer_started(writer); do { atomic_fetch_add(&writer->writer_cycle, 1); uint32_t interval = atomic_load(&writer->flush_interval); // fprintf(stderr, "interval %lu\n", interval); if (interval > 0) { - struct timespec wait_deadline = _dd_deadline_in_ms(interval); + struct timespec wait_deadline = dd_deadline_in_ms(interval); if (writer->thread) { pthread_mutex_lock(&writer->thread->interval_flush_mutex); pthread_cond_timedwait(&writer->thread->interval_flush_condition, &writer->thread->interval_flush_mutex, @@ -1257,13 +1183,13 @@ static void *_dd_writer_loop(void *_) { uint32_t processed_stacks = 0; if (!*stack) { - *stack = _dd_coms_attempt_acquire_stack(); + *stack = dd_coms_attempt_acquire_stack(); } // initializing a curl client only for this iteration writer->curl = curl_easy_init(); - curl_easy_setopt(writer->curl, CURLOPT_READFUNCTION, _dd_coms_read_callback); - curl_easy_setopt(writer->curl, CURLOPT_WRITEFUNCTION, _dd_dummy_write_callback); + curl_easy_setopt(writer->curl, CURLOPT_READFUNCTION, dd_coms_read_callback); + curl_easy_setopt(writer->curl, CURLOPT_WRITEFUNCTION, dd_dummy_write_callback); // as per https://curl.se/libcurl/c/threadsafe.html // Also note that the docs mention potential SIGPIPEs, which may occur with OpenSSL: // We can ignore that for now as we don't do TLS traffic to the agent currently @@ -1273,16 +1199,16 @@ static void *_dd_writer_loop(void *_) { while (*stack) { processed_stacks++; if (atomic_load(&writer->sending)) { - _dd_curl_send_stack(writer, *stack, &metrics); + dd_curl_send_stack(writer, *stack, &metrics); } ddtrace_coms_stack_t *to_free = *stack; // successfully sent stack is no longer needed // ensure no one will refernce freed stack when thread restarts after fork *stack = NULL; - _dd_coms_free_stack(to_free); + dd_coms_free_stack(to_free); - *stack = _dd_coms_attempt_acquire_stack(); + *stack = dd_coms_attempt_acquire_stack(); } CURL *curl = writer->curl; @@ -1296,12 +1222,12 @@ static void *_dd_writer_loop(void *_) { } ddtrace_telemetry_send_trace_api_metrics(metrics); - _dd_signal_data_processed(writer); + dd_signal_data_processed(writer); } while (running); - _dd_curl_reset_headers(writer); + dd_curl_reset_headers(writer); - _dd_coms_stack_shutdown(); + dd_coms_stack_shutdown(); pthread_cleanup_pop(1); @@ -1309,14 +1235,14 @@ static void *_dd_writer_loop(void *_) { } bool ddtrace_coms_set_writer_send_on_flush(bool send) { - struct _writer_loop_data_t *writer = _dd_get_writer(); + struct _writer_loop_data_t *writer = dd_get_writer(); bool previous_value = atomic_load(&writer->sending); atomic_store(&writer->sending, send); return previous_value; } -static void _dd_writer_set_shutdown_state(struct _writer_loop_data_t *writer) { +static void dd_writer_set_shutdown_state(struct _writer_loop_data_t *writer) { // spin the writer without waiting to speedup processing time atomic_store(&writer->flush_interval, 0); // stop allocating new stacks on flush @@ -1325,14 +1251,14 @@ static void _dd_writer_set_shutdown_state(struct _writer_loop_data_t *writer) { atomic_store(&writer->shutdown_when_idle, true); } -static void _dd_writer_set_operational_state(struct _writer_loop_data_t *writer) { +static void dd_writer_set_operational_state(struct _writer_loop_data_t *writer) { atomic_store(&writer->sending, true); atomic_store(&writer->flush_interval, get_global_DD_TRACE_AGENT_FLUSH_INTERVAL()); atomic_store(&writer->allocate_new_stacks, true); atomic_store(&writer->shutdown_when_idle, false); } -static struct _writer_thread_variables_t *_dd_create_thread_variables() { +static struct _writer_thread_variables_t *dd_create_thread_variables() { struct _writer_thread_variables_t *thread = calloc(1, sizeof(struct _writer_thread_variables_t)); pthread_mutex_init(&thread->interval_flush_mutex, NULL); pthread_mutex_init(&thread->finished_flush_mutex, NULL); @@ -1347,24 +1273,24 @@ static struct _writer_thread_variables_t *_dd_create_thread_variables() { return thread; } -static bool _dd_coms_start_writer(void) { - struct _writer_loop_data_t *writer = _dd_get_writer(); - _dd_writer_set_operational_state(writer); - struct _writer_thread_variables_t *thread = _dd_create_thread_variables(); +static bool dd_coms_start_writer(void) { + struct _writer_loop_data_t *writer = dd_get_writer(); + dd_writer_set_operational_state(writer); + struct _writer_thread_variables_t *thread = dd_create_thread_variables(); writer->thread = thread; writer->set_secbit = get_global_DD_TRACE_RETAIN_THREAD_CAPABILITIES(); atomic_store(&writer->starting_up, true); - return pthread_create(&thread->self, NULL, &_dd_writer_loop, NULL) == 0; + return pthread_create(&thread->self, NULL, &dd_writer_loop, NULL) == 0; } bool ddtrace_coms_restart_writer(void) { - ddtrace_coms_minit(ddtrace_coms_globals.initial_stack_size, ddtrace_coms_globals.max_payload_size, ddtrace_coms_globals.max_backlog_size, NULL); - return _dd_coms_start_writer(); + ddtrace_coms_minit(ddtrace_coms_globals.initial_stack_size, ddtrace_coms_globals.max_payload_size, ddtrace_coms_globals.max_backlog_size); + return dd_coms_start_writer(); } bool ddtrace_coms_init_and_start_writer(void) { - struct _writer_loop_data_t *writer = _dd_get_writer(); + struct _writer_loop_data_t *writer = dd_get_writer(); atomic_store(&writer->current_pid, getpid()); dd_agent_curl_headers = dd_agent_headers_alloc(); @@ -1373,19 +1299,19 @@ bool ddtrace_coms_init_and_start_writer(void) { return false; } - ddtrace_ffi_try("error creating config writer", ddog_create_agent_remote_config_writer(&dd_agent_config_writer, &ddtrace_coms_agent_config_handle)); - return _dd_coms_start_writer(); + datadog_ffi_try("error creating config writer", ddog_create_agent_remote_config_writer(&dd_agent_config_writer, &ddtrace_coms_agent_config_handle)); + return dd_coms_start_writer(); } -static bool _dd_has_pid_changed(void) { - struct _writer_loop_data_t *writer = _dd_get_writer(); +static bool dd_has_pid_changed(void) { + struct _writer_loop_data_t *writer = dd_get_writer(); pid_t current_pid = getpid(); pid_t previous_pid = atomic_load(&writer->current_pid); return current_pid != previous_pid; } void ddtrace_coms_kill_background_sender(void) { - struct _writer_loop_data_t *writer = _dd_get_writer(); + struct _writer_loop_data_t *writer = dd_get_writer(); if (writer->thread) { free(writer->thread); writer->thread = NULL; @@ -1393,19 +1319,19 @@ void ddtrace_coms_kill_background_sender(void) { } void ddtrace_coms_clean_background_sender_after_fork(void) { - struct _writer_loop_data_t *writer = _dd_get_writer(); + struct _writer_loop_data_t *writer = dd_get_writer(); ddtrace_coms_kill_background_sender(); - _dd_curl_reset_headers(writer); + dd_curl_reset_headers(writer); curl_easy_cleanup(writer->curl); writer->curl = NULL; - _dd_unsafe_cleanup_dirty_stack_area(); - _dd_coms_stack_shutdown(); + dd_unsafe_cleanup_dirty_stack_area(); + dd_coms_stack_shutdown(); global_writer = (struct _writer_loop_data_t){0}; - ddtrace_coms_minit(ddtrace_coms_globals.initial_stack_size, ddtrace_coms_globals.max_payload_size, ddtrace_coms_globals.max_backlog_size, NULL); + ddtrace_coms_minit(ddtrace_coms_globals.initial_stack_size, ddtrace_coms_globals.max_payload_size, ddtrace_coms_globals.max_backlog_size); } bool ddtrace_coms_on_pid_change(void) { - struct _writer_loop_data_t *writer = _dd_get_writer(); + struct _writer_loop_data_t *writer = dd_get_writer(); pid_t current_pid = getpid(); pid_t previous_pid = atomic_load(&writer->current_pid); @@ -1428,7 +1354,7 @@ bool ddtrace_coms_on_pid_change(void) { } bool ddtrace_coms_trigger_writer_flush(void) { - struct _writer_loop_data_t *writer = _dd_get_writer(); + struct _writer_loop_data_t *writer = dd_get_writer(); if (writer->thread) { pthread_mutex_lock(&writer->thread->interval_flush_mutex); pthread_cond_signal(&writer->thread->interval_flush_condition); @@ -1439,7 +1365,7 @@ bool ddtrace_coms_trigger_writer_flush(void) { } void ddtrace_coms_rshutdown(void) { - struct _writer_loop_data_t *writer = _dd_get_writer(); + struct _writer_loop_data_t *writer = dd_get_writer(); atomic_fetch_add(&writer->request_counter, 1); @@ -1457,12 +1383,12 @@ void ddtrace_coms_rshutdown(void) { // Returns true if writer is shutdown completely bool ddtrace_coms_flush_shutdown_writer_synchronous(void) { - struct _writer_loop_data_t *writer = _dd_get_writer(); + struct _writer_loop_data_t *writer = dd_get_writer(); if (!writer->thread) { return true; } - _dd_writer_set_shutdown_state(writer); + dd_writer_set_shutdown_state(writer); // wait for writer cycle to to complete before exiting pthread_mutex_lock(&writer->thread->writer_shutdown_signal_mutex); @@ -1471,7 +1397,7 @@ bool ddtrace_coms_flush_shutdown_writer_synchronous(void) { bool should_join = false; // see _dd_signal_writer_started if (atomic_load(&writer->starting_up) || atomic_load(&writer->running)) { - struct timespec deadline = _dd_deadline_in_ms(get_global_DD_TRACE_SHUTDOWN_TIMEOUT()); + struct timespec deadline = dd_deadline_in_ms(get_global_DD_TRACE_SHUTDOWN_TIMEOUT()); int rv = pthread_cond_timedwait(&writer->thread->writer_shutdown_signal_condition, &writer->thread->writer_shutdown_signal_mutex, &deadline); @@ -1483,7 +1409,7 @@ bool ddtrace_coms_flush_shutdown_writer_synchronous(void) { /* if this is not a fork, and timeout has been reached, the thread needs to be cancelled and joined as this is the last opportunity to join */ - if (!_dd_has_pid_changed()) { + if (!dd_has_pid_changed()) { pthread_cancel(writer->thread->self); should_join = true; @@ -1495,7 +1421,7 @@ bool ddtrace_coms_flush_shutdown_writer_synchronous(void) { } pthread_mutex_unlock(&writer->thread->writer_shutdown_signal_mutex); - if (should_join && !_dd_has_pid_changed()) { + if (should_join && !dd_has_pid_changed()) { // After pthread_cancel (if timeout was reached), verify the thread has actually // stopped before calling pthread_join. pthread_cancel may fail to take effect if // the thread is blocked in a non-cancellable operation (e.g. certain curl states @@ -1506,7 +1432,7 @@ bool ddtrace_coms_flush_shutdown_writer_synchronous(void) { // handler to signal that the thread is terminating. pthread_mutex_lock(&writer->thread->writer_shutdown_signal_mutex); if (atomic_load(&writer->running) || atomic_load(&writer->starting_up)) { - struct timespec grace_deadline = _dd_deadline_in_ms(get_global_DD_TRACE_SHUTDOWN_TIMEOUT()); + struct timespec grace_deadline = dd_deadline_in_ms(get_global_DD_TRACE_SHUTDOWN_TIMEOUT()); pthread_cond_timedwait(&writer->thread->writer_shutdown_signal_condition, &writer->thread->writer_shutdown_signal_mutex, &grace_deadline); } @@ -1530,7 +1456,7 @@ bool ddtrace_coms_flush_shutdown_writer_synchronous(void) { } bool ddtrace_coms_synchronous_flush(uint32_t timeout) { - struct _writer_loop_data_t *writer = _dd_get_writer(); + struct _writer_loop_data_t *writer = dd_get_writer(); if (!writer->thread) { return false; @@ -1551,7 +1477,7 @@ bool ddtrace_coms_synchronous_flush(uint32_t timeout) { // writer stopped there is no way the counter will be increaseed break; } - struct timespec deadline = _dd_deadline_in_ms(timeout); + struct timespec deadline = dd_deadline_in_ms(timeout); pthread_cond_timedwait(&writer->thread->finished_flush_condition, &writer->thread->finished_flush_mutex, &deadline); } @@ -1567,7 +1493,7 @@ bool ddtrace_coms_synchronous_flush(uint32_t timeout) { } bool ddtrace_in_writer_thread(void) { - struct _writer_loop_data_t *writer = _dd_get_writer(); + struct _writer_loop_data_t *writer = dd_get_writer(); if (!writer->thread) { return false; } @@ -1589,7 +1515,7 @@ void ddtrace_coms_set_test_session_token(const char *token, size_t token_len) { #define DDTRACE_NUMBER_OF_DATA_TO_WRITE 2000 #define DDTRACE_DATA_TO_WRITE "0123456789" -static void *_dd_test_writer_function(void *_) { +static void *dd_test_writer_function(void *_) { (void)_; for (int i = 0; i < DDTRACE_NUMBER_OF_DATA_TO_WRITE; i++) { ddtrace_coms_buffer_data(0, DDTRACE_DATA_TO_WRITE, sizeof(DDTRACE_DATA_TO_WRITE) - 1); @@ -1604,7 +1530,7 @@ uint32_t ddtrace_coms_test_writers(void) { pthread_t *thread = malloc(sizeof(pthread_t) * threads); for (int i = 0; i < threads; i++) { - int ret = pthread_create(&thread[i], NULL, &_dd_test_writer_function, NULL); + int ret = pthread_create(&thread[i], NULL, &dd_test_writer_function, NULL); if (ret != 0) { printf("Create pthread error!\n"); @@ -1624,7 +1550,7 @@ uint32_t ddtrace_coms_test_writers(void) { } uint32_t ddtrace_coms_test_consumer(void) { - if (!_dd_coms_unsafe_rotate_stack(true, atomic_load(&ddtrace_coms_globals.stack_size))) { + if (!dd_coms_unsafe_rotate_stack(true, atomic_load(&ddtrace_coms_globals.stack_size))) { printf("error rotating stacks"); } @@ -1678,17 +1604,17 @@ uint32_t ddtrace_coms_test_consumer(void) { } while (0) uint32_t ddtrace_coms_test_msgpack_consumer(void) { - _dd_coms_unsafe_rotate_stack(true, atomic_load(&ddtrace_coms_globals.stack_size)); + dd_coms_unsafe_rotate_stack(true, atomic_load(&ddtrace_coms_globals.stack_size)); - ddtrace_coms_stack_t *stack = _dd_coms_attempt_acquire_stack(); + ddtrace_coms_stack_t *stack = dd_coms_attempt_acquire_stack(); if (!stack) { return 0; } - void *userdata = _dd_init_read_userdata(stack); + void *userdata = dd_init_read_userdata(stack); char *data = calloc(100000, 1); - size_t written = _dd_coms_read_callback(data, 1, 1000, userdata); + size_t written = dd_coms_read_callback(data, 1, 1000, userdata); if (written > 0) { PRINT_PRINTABLE("", 0, data[0]); for (size_t i = 1; i < written; i++) { @@ -1699,8 +1625,8 @@ uint32_t ddtrace_coms_test_msgpack_consumer(void) { printf("\n"); free(data); - _dd_deinit_read_userdata(userdata); - _dd_coms_free_stack(stack); + dd_deinit_read_userdata(userdata); + dd_coms_free_stack(stack); return 1; } /* }}} */ diff --git a/ext/coms.h b/tracer/coms.h similarity index 94% rename from ext/coms.h rename to tracer/coms.h index cee7467d75c..b8080f3c69f 100644 --- a/ext/coms.h +++ b/tracer/coms.h @@ -42,10 +42,6 @@ typedef struct ddtrace_coms_state_t { */ size_t max_backlog_size; - /* Whether to send fallback telemetry. */ - bool bgs_fallback_telemetry; - char initial_service_name[100]; - char test_session_token[255]; } ddtrace_coms_state_t; @@ -58,7 +54,7 @@ inline bool ddtrace_coms_is_stack_free(ddtrace_coms_stack_t *stack) { /* Is called by the PHP thread to buffer a payload in order to send it. It is non-blocking on the request to the agent. */ bool ddtrace_coms_buffer_data(uint32_t group_id, const char *data, size_t size); -bool ddtrace_coms_minit(size_t initial_stack_size, size_t max_payload_size, size_t max_backlog_size, char *bgs_fallback_telemetry_service); +bool ddtrace_coms_minit(size_t initial_stack_size, size_t max_payload_size, size_t max_backlog_size); void ddtrace_coms_mshutdown(void); void ddtrace_coms_curl_shutdown(void); void ddtrace_coms_rshutdown(void); diff --git a/tracer/configuration.h b/tracer/configuration.h new file mode 100644 index 00000000000..e78b40427b5 --- /dev/null +++ b/tracer/configuration.h @@ -0,0 +1,196 @@ +#ifndef DD_CONFIGURATION_H_MACROS +#define DD_CONFIGURATION_H_MACROS + +#include "integrations/integrations.h" + +#define DD_TRACE_BGS_CONNECT_TIMEOUT_VAL 2000 + +/* This should be at least an order of magnitude higher than the userland HTTP Transport default. */ +#define DD_TRACE_BGS_TIMEOUT_VAL 5000 + +#define DD_INTEGRATION_ANALYTICS_ENABLED_DEFAULT false +#define DD_INTEGRATION_ANALYTICS_SAMPLE_RATE_DEFAULT 1.0 + +#if PHP_VERSION_ID >= 80300 || defined(_WIN32) +#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/" +#else +#define DD_DEFAULT_SOURCES_PATH "" +#endif + +#define INTEGRATION_ALIAS(id, _, initial, ...) \ + CALIAS(BOOL, id, initial, __VA_ARGS__) +#define INTEGRATION_WITH_DEFAULT(id, _, initial) \ + CONFIG(BOOL, id, initial) +#define INTEGRATION_NORMAL(id, _) \ + CONFIG(BOOL, id, "true") +#define GET_INTEGRATION_CONFIG_MACRO(_1, _2, _3, DEFAULT, NAME, ...) NAME +#if defined(_MSVC_TRADITIONAL) && _MSVC_TRADITIONAL +#define GET_INTEGRATION_CONFIG_MACRO_EXPAND(...) __VA_ARGS__ +#define INTEGRATION_CONFIG_ACTIVE(id, ...) GET_INTEGRATION_CONFIG_MACRO_EXPAND(GET_INTEGRATION_CONFIG_MACRO(__VA_ARGS__, INTEGRATION_ALIAS, INTEGRATION_ALIAS, INTEGRATION_WITH_DEFAULT, INTEGRATION_NORMAL))GET_INTEGRATION_CONFIG_MACRO_EXPAND((DD_TRACE_##id##_ENABLED, __VA_ARGS__)) +#else +#define INTEGRATION_CONFIG_ACTIVE(id, ...) GET_INTEGRATION_CONFIG_MACRO(__VA_ARGS__, INTEGRATION_ALIAS, INTEGRATION_ALIAS, INTEGRATION_WITH_DEFAULT, INTEGRATION_NORMAL)(DD_TRACE_##id##_ENABLED, __VA_ARGS__) +#endif +#define INTEGRATION(id, ...) \ + INTEGRATION_CONFIG_ACTIVE(id, __VA_ARGS__) \ + CALIAS(BOOL, DD_TRACE_##id##_ANALYTICS_ENABLED, DD_CFG_EXPSTR(DD_INTEGRATION_ANALYTICS_ENABLED_DEFAULT), \ + CALIASES(DD_CFG_STR(DD_##id##_ANALYTICS_ENABLED), DD_CFG_STR(DD_TRACE_##id##_ANALYTICS_ENABLED))) \ + CALIAS(DOUBLE, DD_TRACE_##id##_ANALYTICS_SAMPLE_RATE, DD_CFG_EXPSTR(DD_INTEGRATION_ANALYTICS_SAMPLE_RATE_DEFAULT), \ + CALIASES(DD_CFG_STR(DD_##id##_ANALYTICS_SAMPLE_RATE), DD_CFG_STR(DD_TRACE_##id##_ANALYTICS_SAMPLE_RATE))) + +#define DD_TRACE_OBFUSCATION_QUERY_STRING_REGEXP_DEFAULT \ + "(?i)(?:(?:\"|%22)?)(?:(?:old[-_]?|new[-_]?)?p(?:ass)?w(?:or)?d(?:1|2)?|pass(?:[-_]?phrase)?|secret|(?:api[-_]?|private[-_]?|public[-_]?|access[-_]?|secret[-_]?|app(?:lication)?[-_]?)key(?:[-_]?id)?|token|consumer[-_]?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?)(?:(?:\\s|%20)*(?:=|%3D)[^&]+|(?:\"|%22)(?:\\s|%20)*(?::|%3A)(?:\\s|%20)*(?:\"|%22)(?:%2[^2]|%[^2]|[^\"%])+(?:\"|%22))|(?:bearer(?:\\s|%20)+[a-z0-9._\\-]+|token(?::|%3A)[a-z0-9]{13}|gh[opsu]_[0-9a-zA-Z]{36}|ey[I-L](?:[\\w=-]|%3D)+\\.ey[I-L](?:[\\w=-]|%3D)+(?:\\.(?:[\\w.+/=-]|%3D|%2F|%2B)+)?|-{5}BEGIN(?:[a-z\\s]|%20)+PRIVATE(?:\\s|%20)KEY-{5}[^\\-]+-{5}END(?:[a-z\\s]|%20)+PRIVATE(?:\\s|%20)KEY(?:-{5})?(?:\\n|%0A)?|(?:ssh-(?:rsa|dss)|ecdsa-[a-z0-9]+-[a-z0-9]+)(?:\\s|%20|%09)+(?:[a-z0-9/.+]|%2F|%5C|%2B){100,}(?:=|%3D)*(?:(?:\\s|%20|%09)+[a-z0-9._-]+)?)" + +#define DDTRACE_CONFIGURATION_ALL \ + CONFIG(STRING, DD_TRACE_SOURCES_PATH, DD_DEFAULT_SOURCES_PATH, .ini_change = zai_config_system_ini_change) \ + CONFIG(BOOL, DD_AUTOLOAD_NO_COMPILE, "false", .ini_change = zai_config_system_ini_change) \ + CONFIG(BOOL, DD_DISTRIBUTED_TRACING, "true") \ + CONFIG(BOOL, DD_AUTOFINISH_SPANS, "false") \ + CONFIG(BOOL, DD_TRACE_URL_AS_RESOURCE_NAMES_ENABLED, "true") \ + CONFIG(BOOL, DD_HTTP_SERVER_ROUTE_BASED_NAMING, "true") \ + CONFIG(BOOL, DD_TRACE_ANALYTICS_ENABLED, "false") \ + CONFIG(BOOL, DD_TRACE_APPEND_TRACE_IDS_TO_LOGS, "false") \ + CONFIG(BOOL, DD_TRACE_AUTO_FLUSH_ENABLED, "false") /* true in CLI */ \ + CONFIG(BOOL, DD_TRACE_MEASURE_COMPILE_TIME, "true") \ + CONFIG(BOOL, DD_TRACE_MEASURE_PEAK_MEMORY_USAGE, "true") \ + CONFIG(BOOL, DD_TELEMETRY_LOG_COLLECTION_ENABLED, "true") \ + CONFIG(BOOL, DD_TRACE_DB_CLIENT_SPLIT_BY_INSTANCE, "false") \ + CONFIG(BOOL, DD_TRACE_HTTP_CLIENT_SPLIT_BY_DOMAIN, "false") \ + CONFIG(BOOL, DD_TRACE_REDIS_CLIENT_SPLIT_BY_HOST, "false") \ + CONFIG(BOOL, DD_EXCEPTION_REPLAY_ENABLED, "false", .ini_change = ddtrace_alter_DD_EXCEPTION_REPLAY_ENABLED) \ + CONFIG(INT, DD_EXCEPTION_REPLAY_CAPTURE_MAX_FRAMES, "-1") \ + CONFIG(INT, DD_EXCEPTION_REPLAY_CAPTURE_INTERVAL_SECONDS, "3600") \ + CONFIG(STRING, DD_TRACE_MEMORY_LIMIT, "") \ + CONFIG(BOOL, DD_TRACE_FLUSH_COLLECT_CYCLES, "false") \ + CONFIG(BOOL, DD_TRACE_KAFKA_DISTRIBUTED_TRACING, "true") \ + CONFIG(BOOL, DD_TRACE_LARAVEL_QUEUE_DISTRIBUTED_TRACING, "true") \ + CONFIG(BOOL, DD_TRACE_SYMFONY_MESSENGER_DISTRIBUTED_TRACING, "true") \ + CONFIG(BOOL, DD_TRACE_SYMFONY_MESSENGER_MIDDLEWARES, "false") \ + CONFIG(BOOL, DD_TRACE_SYMFONY_HTTP_ROUTE, "true") \ + CONFIG(BOOL, DD_TRACE_REMOVE_ROOT_SPAN_LARAVEL_QUEUE, "true") \ + CONFIG(BOOL, DD_TRACE_REMOVE_ROOT_SPAN_SYMFONY_MESSENGER, "true") \ + CONFIG(BOOL, DD_TRACE_REMOVE_AUTOINSTRUMENTATION_ORPHANS, "false") \ + CONFIG(SET, DD_TRACE_RESOURCE_URI_FRAGMENT_REGEX, "") \ + CONFIG(SET, DD_TRACE_RESOURCE_URI_MAPPING_INCOMING, "") \ + CONFIG(SET, DD_TRACE_RESOURCE_URI_MAPPING_OUTGOING, "") \ + CONFIG(SET, DD_TRACE_RESOURCE_URI_QUERY_PARAM_ALLOWED, "") \ + CONFIG(SET, DD_TRACE_HTTP_URL_QUERY_PARAM_ALLOWED, "*") \ + CONFIG(SET, DD_TRACE_HTTP_POST_DATA_PARAM_ALLOWED, "") \ + CONFIG(INT, DD_TRACE_RATE_LIMIT, "100", .ini_change = zai_config_system_ini_change) \ + CONFIG(DOUBLE, DD_TRACE_SAMPLE_RATE, "-1", .ini_change = ddtrace_alter_DD_TRACE_SAMPLE_RATE, \ + .env_config_fallback = ddtrace_conf_otel_sample_rate) \ + CONFIG(JSON, DD_TRACE_SAMPLING_RULES, "[]") \ + CONFIG(CUSTOM(INT), DD_TRACE_SAMPLING_RULES_FORMAT, "glob", .parser = dd_parse_sampling_rules_format) \ + CONFIG(JSON, DD_SPAN_SAMPLING_RULES, "[]") \ + CONFIG(STRING, DD_SPAN_SAMPLING_RULES_FILE, "", .ini_change = ddtrace_alter_sampling_rules_file_config) \ + CONFIG(SET_OR_MAP_LOWERCASE, DD_TRACE_HEADER_TAGS, "", .ini_change = ddtrace_alter_DD_TRACE_HEADER_TAGS) \ + CONFIG(INT, DD_TRACE_X_DATADOG_TAGS_MAX_LENGTH, "512") \ + CONFIG(MAP, DD_TRACE_PEER_SERVICE_MAPPING, "") \ + CONFIG(BOOL, DD_TRACE_PEER_SERVICE_DEFAULTS_ENABLED, "false") \ + CONFIG(BOOL, DD_TRACE_REMOVE_INTEGRATION_SERVICE_NAMES_ENABLED, "false") \ + CONFIG(BOOL, DD_TRACE_PROPAGATE_SERVICE, "false") \ + CONFIG(SET_LOWERCASE, DD_TRACE_PROPAGATION_STYLE_EXTRACT, "datadog,tracecontext,B3,B3 single header,baggage") \ + CONFIG(SET_LOWERCASE, DD_TRACE_PROPAGATION_STYLE_INJECT, "datadog,tracecontext,baggage") \ + CONFIG(SET_LOWERCASE, DD_TRACE_PROPAGATION_STYLE, "datadog,tracecontext,baggage", \ + .env_config_fallback = ddtrace_conf_otel_propagators) \ + CONFIG(SET, DD_TRACE_BAGGAGE_TAG_KEYS, "user.id, session.id, account.id") \ + CONFIG(BOOL, DD_TRACE_IGNORE_AGENT_SAMPLING_RATES, "false", .ini_change = zai_config_system_ini_change) \ + CONFIG(SET, DD_TRACE_TRACED_INTERNAL_FUNCTIONS, "") \ + CONFIG(INT, DD_TRACE_DEBUG_PRNG_SEED, "-1", .ini_change = ddtrace_reseed_seed_change) \ + CONFIG(BOOL, DD_TRACE_SECURE_RANDOM, "false") \ + CONFIG(BOOL, DD_TRACE_GENERATE_ROOT_SPAN, "true", .ini_change = ddtrace_span_alter_root_span_config) \ + CONFIG(INT, DD_TRACE_SPANS_LIMIT, "1000") \ + CONFIG(BOOL, DD_TRACE_128_BIT_TRACEID_GENERATION_ENABLED, "true") \ + CONFIG(BOOL, DD_TRACE_128_BIT_TRACEID_LOGGING_ENABLED, "true") \ + CONFIG(INT, DD_TRACE_BGS_CONNECT_TIMEOUT, DD_CFG_EXPSTR(DD_TRACE_BGS_CONNECT_TIMEOUT_VAL), \ + .ini_change = zai_config_system_ini_change) \ + CONFIG(INT, DD_TRACE_BGS_TIMEOUT, DD_CFG_EXPSTR(DD_TRACE_BGS_TIMEOUT_VAL), \ + .ini_change = zai_config_system_ini_change) \ + CONFIG(INT, DD_TRACE_AGENT_FLUSH_AFTER_N_REQUESTS, "0") \ + CONFIG(INT, DD_TRACE_AGENT_RETRIES, "0", .ini_change = zai_config_system_ini_change) \ + 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") \ + CONFIG(BOOL, DD_TRACE_MONGODB_OBFUSCATION, "true") \ + CONFIG(BOOL, DD_TRACE_CLIENT_IP_ENABLED, "false") \ + CONFIG(CUSTOM(STRING), DD_TRACE_CLIENT_IP_HEADER, "", .parser = ddtrace_parse_client_ip_header_config) \ + CONFIG(BOOL, DD_TRACE_FORKED_PROCESS, "true") \ + CONFIG(INT, DD_TRACE_HOOK_LIMIT, "100") \ + CONFIG(INT, DD_TRACE_AGENT_STACK_INITIAL_SIZE, "131072", .ini_change = zai_config_system_ini_change) \ + CONFIG(BOOL, DD_TRACE_PROPAGATE_USER_ID_DEFAULT, "false") \ + CONFIG(CUSTOM(INT), DD_DBM_PROPAGATION_MODE, "disabled", .parser = dd_parse_dbm_mode) \ + CONFIG(BOOL, DD_DBM_INJECT_SQL_BASEHASH, "false") \ + CONFIG(SET, DD_TRACE_WORDPRESS_ADDITIONAL_ACTIONS, "") \ + CONFIG(BOOL, DD_TRACE_WORDPRESS_CALLBACKS, "true") \ + CONFIG(BOOL, DD_INTEGRATION_METRICS_ENABLED, "true", \ + .env_config_fallback = ddtrace_conf_otel_metrics_exporter) \ + CONFIG(BOOL, DD_METRICS_OTEL_ENABLED, "false") \ + CONFIG(BOOL, DD_LOGS_OTEL_ENABLED, "false") \ + CONFIG(BOOL, DD_TRACE_OTEL_ENABLED, "false") \ + CONFIG(STRING, DD_OPENAI_SERVICE, "") \ + CONFIG(BOOL, DD_OPENAI_METRICS_ENABLED, "true") \ + CONFIG(BOOL, DD_OPENAI_LOGS_ENABLED, "false") \ + CONFIG(INT, DD_OPENAI_SPAN_CHAR_LIMIT, "128") \ + CONFIG(DOUBLE, DD_OPENAI_SPAN_PROMPT_COMPLETION_SAMPLE_RATE, "1.0") \ + CONFIG(DOUBLE, DD_OPENAI_LOG_PROMPT_COMPLETION_SAMPLE_RATE, "0.1") \ + CONFIG(BOOL, DD_TRACE_WEBSOCKET_MESSAGES_ENABLED, "true") \ + CONFIG(BOOL, DD_TRACE_WEBSOCKET_MESSAGES_INHERIT_SAMPLING, "true") \ + CONFIG(BOOL, DD_TRACE_WEBSOCKET_MESSAGES_SEPARATE_TRACES, "true") \ + CONFIG(BOOL, DD_DYNAMIC_INSTRUMENTATION_ENABLED, "false", .ini_change = ddtrace_alter_dynamic_instrumentation_config) \ + CONFIG(SET, DD_DYNAMIC_INSTRUMENTATION_REDACTED_IDENTIFIERS, "", .ini_change = zai_config_system_ini_change) \ + CONFIG(BOOL, DD_APM_TRACING_ENABLED, "true") \ + CONFIG(SET, DD_DYNAMIC_INSTRUMENTATION_REDACTED_TYPES, "", .ini_change = zai_config_system_ini_change) \ + CONFIG(SET, DD_DYNAMIC_INSTRUMENTATION_REDACTION_EXCLUDED_IDENTIFIERS, "", .ini_change = zai_config_system_ini_change) \ + CONFIG(INT, DD_TRACE_BAGGAGE_MAX_ITEMS, "64") \ + CONFIG(INT, DD_TRACE_BAGGAGE_MAX_BYTES, "8192") \ + CONFIG(BOOL, DD_TRACE_INFERRED_PROXY_SERVICES_ENABLED, "false") \ + CONFIG(SET, DD_TRACE_HTTP_CLIENT_ERROR_STATUSES, "400-499", .ini_change = zai_config_system_ini_change) \ + CONFIG(SET, DD_TRACE_HTTP_SERVER_ERROR_STATUSES, "500-599", .ini_change = zai_config_system_ini_change) \ + CONFIG(BOOL, DD_CODE_ORIGIN_FOR_SPANS_ENABLED, "true", .ini_change = ddtrace_alter_DD_CODE_ORIGIN_FOR_SPANS_ENABLED) \ + CONFIG(INT, DD_CODE_ORIGIN_MAX_USER_FRAMES, "8") \ + CONFIG(BOOL, DD_TRACE_RESOURCE_RENAMING_ENABLED, "false") \ + CONFIG(BOOL, DD_TRACE_RESOURCE_RENAMING_ALWAYS_SIMPLIFIED_ENDPOINT, "false") \ + CONFIG(BOOL, DD_TRACE_STATS_COMPUTATION_ENABLED, "false") \ + DD_INTEGRATIONS + +#ifndef _WIN32 +# define DDTRACE_CONFIGURATION \ + CONFIG(BOOL, DD_TRACE_SIDECAR_TRACE_SENDER, DD_CFG_EXPSTR(DD_SIDECAR_TRACE_SENDER_DEFAULT), .ini_change = zai_config_system_ini_change) \ + DDTRACE_CONFIGURATION_ALL +#else +# define DDTRACE_CONFIGURATION DDTRACE_CONFIGURATION_ALL +#endif +#endif // DD_CONFIGURATION_H_MACROS + +#ifndef DD_CONFIGURATIONS_ONLY +#ifndef DD_CONFIGURATION_H +#define DD_CONFIGURATION_H + +#include + +enum ddtrace_dbm_propagation_mode { + DD_TRACE_DBM_PROPAGATION_DISABLED, + DD_TRACE_DBM_PROPAGATION_SERVICE, + DD_TRACE_DBM_PROPAGATION_FULL, +}; + +// To remove in 1.0 +enum ddtrace_sampling_rules_format { + DD_TRACE_SAMPLING_RULES_FORMAT_REGEX, + DD_TRACE_SAMPLING_RULES_FORMAT_GLOB +}; + +#define DD_CONFIGURATION DDTRACE_CONFIGURATION +#include + +#endif // DD_CONFIGURATION_H +#endif // DD_CONFIGURATIONS_ONLY diff --git a/tracer/configuration_dependencies.h b/tracer/configuration_dependencies.h new file mode 100644 index 00000000000..6024036415d --- /dev/null +++ b/tracer/configuration_dependencies.h @@ -0,0 +1,127 @@ +#include "configuration.h" +#include "tracer_otel_config.h" +#include "span.h" +#include "random.h" +#include "ip_extraction.h" +#include "live_debugger.h" + +static bool dd_parse_dbm_mode(zai_str value, zval *decoded_value, bool persistent) { + UNUSED(persistent); + if (zai_str_eq_ci_cstr(value, "disabled")) { + ZVAL_LONG(decoded_value, DD_TRACE_DBM_PROPAGATION_DISABLED); + } else if (zai_str_eq_ci_cstr(value, "service")) { + ZVAL_LONG(decoded_value, DD_TRACE_DBM_PROPAGATION_SERVICE); + } else if (zai_str_eq_ci_cstr(value, "full")) { + ZVAL_LONG(decoded_value, DD_TRACE_DBM_PROPAGATION_FULL); + } else { + return false; + } + + return true; +} + +static bool dd_parse_sampling_rules_format(zai_str value, zval *decoded_value, bool persistent) { + UNUSED(persistent); + if (zai_str_eq_ci_cstr(value, "regex")) { + ZVAL_LONG(decoded_value, DD_TRACE_SAMPLING_RULES_FORMAT_REGEX); + } else if (zai_str_eq_ci_cstr(value, "glob")) { + ZVAL_LONG(decoded_value, DD_TRACE_SAMPLING_RULES_FORMAT_GLOB); + } else { + return false; + } + + return true; +} + +static bool dd_parse_sidecar_connection_mode(zai_str value, zval *decoded_value, bool persistent) { + UNUSED(persistent); + if (zai_str_eq_ci_cstr(value, "auto")) { + ZVAL_LONG(decoded_value, DD_TRACE_SIDECAR_CONNECTION_MODE_AUTO); + } else if (zai_str_eq_ci_cstr(value, "subprocess")) { + ZVAL_LONG(decoded_value, DD_TRACE_SIDECAR_CONNECTION_MODE_SUBPROCESS); + } else if (zai_str_eq_ci_cstr(value, "thread")) { + ZVAL_LONG(decoded_value, DD_TRACE_SIDECAR_CONNECTION_MODE_THREAD); + } 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); + + if (value.len == 0) { + return true; + } + + const char *str = value.ptr; + const char *end = str + value.len; + const char *current = str; + + // Determine separator - prefer comma if present, otherwise use space + char sep = memchr(str, ',', value.len) ? ',': ' '; + + while (current < end) { + // Skip leading whitespace + while (current < end && (*current == ' ' || *current == sep)) current++; + if (current == end) { + // Abort if only separators are remaining + break; + } + + // Find next separator, this will be the end of the tag + const char *tag_end = memchr(current, sep, end - current); + if (!tag_end) { + tag_end = end; + } + // Prepare key and value + // Initialize key to be the entire tag and value to be empty + const char *key_start = current; + const char *key_end = tag_end; + const char *val_start = tag_end; + const char *val_end = tag_end; + // If the tag has a colon, use the index of the colon to split the tag into key and value + const char *colon = memchr(current, ':', tag_end - current); + if (colon) { + // Tag has a colon, use the index of the colon to split into key and value + key_end = colon; + val_start = colon + 1; + } + + // Strip whitespace from key + while (key_start < key_end && *key_start == ' ') key_start++; + while (key_end > key_start && key_end[-1] == ' ') key_end--; + // Only add if key is non-empty + if (key_start != key_end) { + // Strip whitespace from value + while (val_start < val_end && *val_start == ' ') val_start++; + while (val_end > val_start && val_end[-1] == ' ') val_end--; + + zval val; + ZVAL_STR(&val, zend_string_init(val_start, val_end - val_start, persistent)); + zend_hash_str_update(Z_ARRVAL_P(decoded_value), key_start, key_end - key_start, &val); + } + // Move to the start of the next tag + current = tag_end + 1; + } + + return true; +} + +#define INI_CHANGE_DYNAMIC_CONFIG(name, config) \ + static bool ddtrace_alter_##name(zval *old_value, zval *new_value, zend_string *new_str) { \ + UNUSED(old_value, new_value); \ + /* When RC writes, bypass the check for ddog_remote_config_alter_dynamic_config */ \ + if (!DATADOG_G(remote_config_state) || DATADOG_G(remote_config_writing)) { \ + return true; \ + } \ + return ddog_remote_config_alter_dynamic_config(DATADOG_G(remote_config_state), DDOG_CHARSLICE_C(config), zend_string_copy(new_str)); \ + } + +INI_CHANGE_DYNAMIC_CONFIG(DD_TRACE_HEADER_TAGS, "datadog.trace.header_tags") +INI_CHANGE_DYNAMIC_CONFIG(DD_TRACE_SAMPLE_RATE, "datadog.trace.sample_rate") +INI_CHANGE_DYNAMIC_CONFIG(DD_TRACE_LOGS_ENABLED, "datadog.logs_injection") +INI_CHANGE_DYNAMIC_CONFIG(DD_CODE_ORIGIN_FOR_SPANS_ENABLED, "datadog.code_origin_for_spans_enabled") +INI_CHANGE_DYNAMIC_CONFIG(DD_EXCEPTION_REPLAY_ENABLED, "datadog.exception_replay_enabled") diff --git a/tracer/ddtrace.c b/tracer/ddtrace.c new file mode 100644 index 00000000000..bb952ad42be --- /dev/null +++ b/tracer/ddtrace.c @@ -0,0 +1,706 @@ +#include "components-rs/common.h" +#include "components-rs/sidecar.h" +#include "zend_API.h" +#include "zend_hash.h" +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include "ddtrace.h" +#include +#include +#include +#include +#include +#include +#include +#if PHP_VERSION_ID < 80000 +#include +#include +#else +#include +#endif +#include +#include +#include +#ifndef _WIN32 +#include +#include +#else +#include +#endif + +#include +#include + +#include "asm_event.h" +#include "trace_source.h" +#include "auto_flush.h" +#include +#ifndef _WIN32 +#include "coms.h" +#endif +#include "config/config.h" +#include "configuration.h" +#ifndef _WIN32 +#include "dogstatsd_client.h" +#endif +#include "distributed_tracing_headers.h" +#include "engine_hooks.h" +#include "handlers_internal.h" +#include "inferred_proxy_headers.h" +#include "integrations/exec_integration.h" +#include "integrations/integrations.h" +#include "ip_extraction.h" +#include +#include "limiter/limiter.h" +#include "live_debugger.h" +#include "standalone_limiter.h" +#include "priority_sampling/priority_sampling.h" +#include "random.h" +#include "autoload_php_files.h" +#include "serializer.h" +#include +#include "span.h" +#include +#include "user_request.h" +#include "weak_resources.h" +#include + +#include "hook/uhook.h" +#include "handlers_fiber.h" +#include "git_metadata.h" +#include "tracer_telemetry.h" +#include + +_Atomic(int64_t) ddtrace_warn_legacy_api; + +// put this into startup so that other extensions running code as part of rinit do not crash +int ddtrace_startup(zend_extension *extension) { +#if PHP_VERSION_ID < 80000 + zai_interceptor_startup(datadog_module); +#else + zai_interceptor_startup(); +#endif + + ddtrace_fetch_profiling_symbols(); + + if (!datadog_disable) { + // We deliberately leave handler replacement during startup, even though this uses some config + // This touches global state, which, while unlikely, may play badly when interacting with other extensions, if done post-startup + ddtrace_internal_handlers_startup(); + } + return SUCCESS; +} + +void ddtrace_shutdown(zend_extension *extension) { + UNUSED(extension); + + if (datadog_disable != 1) { + ddtrace_internal_handlers_shutdown(); + } + + zai_interceptor_shutdown(); +} + +bool dd_save_sampling_rules_file_config(zend_string *path, int modify_type, int stage) { + if (FG(default_context) == NULL) { + FG(default_context) = php_stream_context_alloc(); + } + php_stream_context *context = FG(default_context); + php_stream *stream = php_stream_open_wrapper_ex(ZSTR_VAL(path), "rb", USE_PATH | REPORT_ERRORS, NULL, context); + if (!stream) { + return false; + } + + zend_string *file = php_stream_copy_to_mem(stream, (ssize_t) PHP_STREAM_COPY_ALL, 0); + php_stream_close(stream); + + bool altered = false; + if (file) { + altered = ZSTR_LEN(file) > 0 && SUCCESS == zend_alter_ini_entry_ex( + zai_config_memoized_entries[DATADOG_CONFIG_DD_SPAN_SAMPLING_RULES].ini_entries[0]->name, + file, modify_type, stage, 1); + zend_string_release(file); + } + return altered; +} + +bool ddtrace_alter_sampling_rules_file_config(zval *old_value, zval *new_value, zend_string *new_str) { + (void) old_value; + (void) new_str; + if (Z_STRLEN_P(new_value) == 0) { + return true; + } + + return dd_save_sampling_rules_file_config(Z_STR_P(new_value), PHP_INI_USER, PHP_INI_STAGE_RUNTIME); +} + +static inline void dd_alter_prop(size_t prop_offset, zval *old_value, zval *new_value, zend_string *new_str) { + UNUSED(old_value, new_str); + + ddtrace_span_properties *pspan = ddtrace_active_span_props(); + while (pspan) { + zval *property = (zval *) (prop_offset + (char *) pspan), garbage = *property; + ZVAL_COPY(property, new_value); + zval_ptr_dtor(&garbage); + pspan = pspan->parent; + } +} + +bool datadog_alter_dd_service(zval *old_value, zval *new_value, zend_string *new_str) { + dd_alter_prop(XtOffsetOf(ddtrace_span_properties, property_service), old_value, new_value, new_str); + if (DATADOG_G(request_initialized)) { + datadog_sidecar_submit_root_span_data_direct(&DATADOG_G(sidecar), NULL, new_str, get_DD_ENV(), get_DD_VERSION()); + } + return true; +} +bool datadog_alter_dd_env(zval *old_value, zval *new_value, zend_string *new_str) { + dd_alter_prop(XtOffsetOf(ddtrace_span_properties, property_env), old_value, new_value, new_str); + if (DATADOG_G(request_initialized)) { + datadog_sidecar_submit_root_span_data_direct(&DATADOG_G(sidecar), NULL, get_DD_SERVICE(), new_str, get_DD_VERSION()); + } + return true; +} +bool datadog_alter_dd_version(zval *old_value, zval *new_value, zend_string *new_str) { + dd_alter_prop(XtOffsetOf(ddtrace_span_properties, property_version), old_value, new_value, new_str); + if (DATADOG_G(request_initialized)) { + datadog_sidecar_submit_root_span_data_direct(&DATADOG_G(sidecar), NULL, get_DD_SERVICE(), get_DD_ENV(), new_str); + } + return true; +} + +void ddtrace_activate_once(void) { + // must run before the first zai_hook_activate as ddtrace_telemetry_setup installs a global hook + if (!datadog_disable) { +#ifndef _WIN32 + + if (!get_global_DD_TRACE_SIDECAR_TRACE_SENDER()) { + if (get_global_DD_TRACE_AGENT_FLUSH_AFTER_N_REQUESTS() == 0) { + // Set the default to 10 so that BGS flushes faster. With sidecar it's not needed generally. + zai_config_change_default_ini(DATADOG_CONFIG_DD_TRACE_AGENT_FLUSH_AFTER_N_REQUESTS, (zai_str) ZAI_STR_FROM_CSTR("10")); + } + if (get_DD_TRACE_AGENT_FLUSH_INTERVAL() == DD_TRACE_AGENT_FLUSH_INTERVAL_VAL) { + // Set the default to 5000 so that BGS does not flush too often. The sidecar can flush more often, but the BGS is per process. Keep it higher to avoid too much load on the agent. + zai_config_change_default_ini(DATADOG_CONFIG_DD_TRACE_AGENT_FLUSH_INTERVAL, (zai_str) ZAI_STR_FROM_CSTR("5000")); + } + ddtrace_coms_minit(get_global_DD_TRACE_AGENT_STACK_INITIAL_SIZE(), + get_global_DD_TRACE_AGENT_MAX_PAYLOAD_SIZE(), + get_global_DD_TRACE_AGENT_STACK_BACKLOG()); + zend_string *testing_token = get_global_DD_TRACE_AGENT_TEST_SESSION_TOKEN(); + if (ZSTR_LEN(testing_token)) { + ddtrace_coms_set_test_session_token(ZSTR_VAL(testing_token), ZSTR_LEN(testing_token)); + } + } + + if (DATADOG_G(sidecar) && get_global_DD_INSTRUMENTATION_TELEMETRY_ENABLED()) { + bool request_startup = PG(during_request_startup); + PG(during_request_startup) = false; + ddtrace_telemetry_first_init(); + PG(during_request_startup) = request_startup; + } +#endif + } +} + +void ddtrace_activate_early(void) { + zai_hook_rinit(); + zai_interceptor_activate(); + zai_uhook_rinit(); + ddtrace_telemetry_rinit(); + zend_hash_init(&DDTRACE_G(traced_spans), 8, unused, NULL, 0); + zend_hash_init(&DDTRACE_G(tracestate_unknown_dd_keys), 8, unused, NULL, 0); +} + +void ddtrace_activate_late(void) { + zend_string *sampling_rules_file = get_DD_SPAN_SAMPLING_RULES_FILE(); + if (ZSTR_LEN(sampling_rules_file) > 0 && !zend_string_equals(get_global_DD_SPAN_SAMPLING_RULES_FILE(), sampling_rules_file)) { + dd_save_sampling_rules_file_config(sampling_rules_file, PHP_INI_USER, PHP_INI_STAGE_RUNTIME); + } + + if (datadog_disable) { + datadog_disable_tracing_in_current_request(); + } + +#if PHP_VERSION_ID < 80000 + // This allows us to hook the ZEND_HANDLE_EXCEPTION pseudo opcode + ZEND_VM_SET_OPCODE_HANDLER(EG(exception_op)); + EG(exception_op)->opcode = ZEND_HANDLE_EXCEPTION; +#endif +} + +void ddtrace_ginit(zend_datadog_globals *ddtrace_globals) { +#if PHP_VERSION_ID < 70100 + zai_vm_interrupt = &ddtrace_globals->zai_vm_interrupt; +#endif + zai_hook_ginit(); +} + +void ddtrace_gshutdown(zend_datadog_globals *datadog_globals) { + zai_hook_gshutdown(); + + if (datadog_globals->sidecar) { + // Drain any accumulated background-sender metrics before the transport goes away. + ddtrace_telemetry_flush_bgs_metrics_final(datadog_globals); + } +} + + +#if PHP_VERSION_ID < 80500 +zend_string *datadog_known_strings[ZEND_STR__LAST]; +void ddtrace_init_known_strings(void) { +#if PHP_VERSION_ID < 80500 +#undef ZEND_STR_PARENT + datadog_known_strings[ZEND_STR_PARENT] = zend_string_init_interned(ZEND_STRL("parent"), 1); +#endif +#if PHP_VERSION_ID < 70300 +#undef ZEND_STR_NAME + datadog_known_strings[ZEND_STR_NAME] = zend_string_init_interned(ZEND_STRL("name"), 1); +#endif +#if PHP_VERSION_ID < 70200 +#undef ZEND_STR_RESOURCE + datadog_known_strings[ZEND_STR_RESOURCE] = zend_string_init_interned(ZEND_STRL("resource"), 1); +#endif +#if PHP_VERSION_ID < 70100 + datadog_known_strings[ZEND_STR_TRACE] = zend_string_init_interned(ZEND_STRL("trace"), 1); + datadog_known_strings[ZEND_STR_LINE] = zend_string_init_interned(ZEND_STRL("line"), 1); + datadog_known_strings[ZEND_STR_FILE] = zend_string_init_interned(ZEND_STRL("file"), 1); + datadog_known_strings[ZEND_STR_MESSAGE] = zend_string_init_interned(ZEND_STRL("message"), 1); + datadog_known_strings[ZEND_STR_CODE] = zend_string_init_interned(ZEND_STRL("code"), 1); + datadog_known_strings[ZEND_STR_TYPE] = zend_string_init_interned(ZEND_STRL("type"), 1); + datadog_known_strings[ZEND_STR_FUNCTION] = zend_string_init_interned(ZEND_STRL("function"), 1); + datadog_known_strings[ZEND_STR_OBJECT] = zend_string_init_interned(ZEND_STRL("object"), 1); + datadog_known_strings[ZEND_STR_CLASS] = zend_string_init_interned(ZEND_STRL("class"), 1); + datadog_known_strings[ZEND_STR_OBJECT_OPERATOR] = zend_string_init_interned(ZEND_STRL("->"), 1); + datadog_known_strings[ZEND_STR_PAAMAYIM_NEKUDOTAYIM] = zend_string_init_interned(ZEND_STRL("::"), 1); + datadog_known_strings[ZEND_STR_ARGS] = zend_string_init_interned(ZEND_STRL("args"), 1); + datadog_known_strings[ZEND_STR_UNKNOWN] = zend_string_init_interned(ZEND_STRL("unknown"), 1); + datadog_known_strings[ZEND_STR_EVAL] = zend_string_init_interned(ZEND_STRL("eval"), 1); + datadog_known_strings[ZEND_STR_INCLUDE] = zend_string_init_interned(ZEND_STRL("include"), 1); + datadog_known_strings[ZEND_STR_REQUIRE] = zend_string_init_interned(ZEND_STRL("require"), 1); + datadog_known_strings[ZEND_STR_INCLUDE_ONCE] = zend_string_init_interned(ZEND_STRL("include_once"), 1); + datadog_known_strings[ZEND_STR_REQUIRE_ONCE] = zend_string_init_interned(ZEND_STRL("require_once"), 1); + datadog_known_strings[ZEND_STR_PREVIOUS] = zend_string_init_interned(ZEND_STRL("previous"), 1); +#endif +} +#endif + +void ddtrace_register_functions_and_classes(int module_number); +void ddtrace_unregister_functions_and_classes(void); + +void ddtrace_pre_config_minit() { + if (datadog_active_sapi == DATADOG_PHP_SAPI_CLI) { + datadog_config_entries[DATADOG_CONFIG_DD_TRACE_AUTO_FLUSH_ENABLED].default_encoded_value = (zai_str) ZAI_STR_FROM_CSTR("true"); + } + +#ifndef _WIN32 + // PID 1 *obviously* needs to ensure the sidecar gets flushed. (As PID 1 terminating will just SIGKILL it.) + // As to PPID 1, common scenarios where PHP is a direct child of PID 1: + // - apache / fpm running in a container as PID 1 each + // - PHP CLI processes running in a container as part of a bash script + // - root processes of supervisord/systemd services - if these terminate, it's likely because the service or container shuts down. + // -> If the sidecar is part of a cgroup, it will terminate the sidecar as well. + if (getpid() == 1 || getppid() == 1) { + datadog_config_entries[DATADOG_CONFIG_DD_TRACE_FORCE_FLUSH_ON_SHUTDOWN].default_encoded_value = (zai_str) ZAI_STR_FROM_CSTR("true"); + datadog_config_entries[DATADOG_CONFIG_DD_TRACE_FORCE_FLUSH_ON_SIGTERM].default_encoded_value = (zai_str) ZAI_STR_FROM_CSTR("true"); + datadog_config_entries[DATADOG_CONFIG_DD_TRACE_FORCE_FLUSH_ON_SIGINT].default_encoded_value = (zai_str) ZAI_STR_FROM_CSTR("true"); + } + + // Background sender does not send a Content-Length header, but sidecar does. Force-enable it thus, as the background sender does not work at all. + if (getenv("AWS_LAMBDA_FUNCTION_NAME")) { + datadog_config_entries[DATADOG_CONFIG_DD_TRACE_SIDECAR_TRACE_SENDER].default_encoded_value = (zai_str) ZAI_STR_FROM_CSTR("true"); + } +#endif +} + +void ddtrace_minit_early(int module_number) { + ddog_init_span_func((void *)zend_string_release, (void *)zend_string_addref, dd_CharSlice_to_zend_string); + + +#if PHP_VERSION_ID < 80500 + ddtrace_init_known_strings(); +#endif + + zai_hook_minit(); + zai_uhook_minit(module_number); +#if PHP_VERSION_ID >= 80000 + zai_interceptor_minit(); +#endif +#if ZAI_JIT_BLACKLIST_ACTIVE + zai_jit_minit(); +#endif + + ddtrace_register_functions_and_classes(module_number); + + // Make sure it's available for appsec, before any early returns + dd_ip_extraction_startup(); +} + +void ddtrace_minit_late() { +#if PHP_VERSION_ID >= 80100 + ddtrace_setup_fiber_observers(); +#endif + + atomic_init(&ddtrace_warn_legacy_api, 1); + + ddtrace_initialize_span_sampling_limiter(); + ddtrace_limiter_create(); + ddtrace_standalone_limiter_create(); + +#ifndef _WIN32 + /* Snapshot proxy-related env vars once at startup to avoid getenv() + * from the background writer thread inside libcurl. */ + ddtrace_coms_minit_proxy_env(); + ddtrace_dogstatsd_client_minit(); +#endif + + ddtrace_autoload_minit(); + + ddtrace_engine_hooks_minit(); + ddtrace_init_proxy_info_map(); + + ddtrace_integrations_minit(); + ddtrace_serializer_startup(); + + ddtrace_live_debugger_minit(); + ddtrace_trace_source_minit(); +} + +void ddtrace_mshutdown() { + zai_uhook_mshutdown(); + zai_hook_mshutdown(); + + ddtrace_unregister_functions_and_classes(); + + if (datadog_disable == 1) { + return; + } + + if (DDTRACE_G(agent_rate_by_service)) { + zai_json_release_persistent_array(DDTRACE_G(agent_rate_by_service)); + DDTRACE_G(agent_rate_by_service) = NULL; + } + + ddtrace_integrations_mshutdown(); + +#ifndef _WIN32 + if (!get_global_DD_TRACE_SIDECAR_TRACE_SENDER()) { + ddtrace_coms_mshutdown(); + if (ddtrace_coms_flush_shutdown_writer_synchronous()) { + ddtrace_coms_curl_shutdown(); + } + /* All writer threads and curl handles are gone at this point, so + * it is safe to free the cached proxy env strings for ASan. */ + ddtrace_coms_mshutdown_proxy_env(); + } else /* ! part of the if outside the ifdef */ +#endif + if (get_global_DD_TRACE_FORCE_FLUSH_ON_SHUTDOWN() && DATADOG_G(sidecar)) { + ddog_sidecar_flush(&DATADOG_G(sidecar), (ddog_SidecarFlushOptions){.traces_and_stats = true, .telemetry = true}); + } + + ddtrace_engine_hooks_mshutdown(); + ddtrace_shutdown_proxy_info_map(); + + ddtrace_shutdown_span_sampling_limiter(); + ddtrace_limiter_destroy(); + ddtrace_standalone_limiter_destroy(); + + ddtrace_user_req_shutdown(); +} + +bool dd_rinit_once_done = false; + +void ddtrace_first_rinit(void) { + /* The env vars are memoized on MINIT before the SAPI env vars are available. + * We use the first RINIT to bust the env var cache and use the SAPI env vars. + * TODO Audit/remove config usages before RINIT and move config init to RINIT. + */ + + + // Uses config, cannot run earlier +#ifndef _WIN32 + if (!get_global_DD_TRACE_SIDECAR_TRACE_SENDER()) { + ddtrace_coms_init_and_start_writer(); + } +#endif + + dd_rinit_once_done = true; +} + +static void dd_initialize_request(void) { + DDTRACE_G(distributed_trace_id) = (datadog_trace_id){0}; + DDTRACE_G(distributed_parent_trace_id) = 0; + DDTRACE_G(additional_global_tags) = zend_new_array(0); + DDTRACE_G(default_priority_sampling) = DDTRACE_PRIORITY_SAMPLING_UNKNOWN; + DDTRACE_G(propagated_priority_sampling) = DDTRACE_PRIORITY_SAMPLING_UNSET; + DDTRACE_G(inferred_span_created) = false; + zend_hash_init(&DDTRACE_G(root_span_tags_preset), 8, unused, ZVAL_PTR_DTOR, 0); + zend_hash_init(&DDTRACE_G(propagated_root_span_tags), 8, unused, ZVAL_PTR_DTOR, 0); + zend_hash_init(&DDTRACE_G(tracestate_unknown_dd_keys), 8, unused, ZVAL_PTR_DTOR, 0); + zend_hash_init(&DDTRACE_G(baggage), 8, unused, ZVAL_PTR_DTOR, 0); + + ddtrace_asm_event_rinit(); + ddtrace_live_debugger_rinit(); + + if (!DATADOG_G(agent_config_reader) && !get_global_DD_TRACE_IGNORE_AGENT_SAMPLING_RATES()) { + if (get_global_DD_TRACE_SIDECAR_TRACE_SENDER()) { + if (datadog_endpoint) { + DATADOG_G(agent_config_reader) = ddog_agent_remote_config_reader_for_endpoint(datadog_endpoint); + } +#ifndef _WIN32 + } else if (ddtrace_coms_agent_config_handle) { + ddog_agent_remote_config_reader_for_anon_shm(ddtrace_coms_agent_config_handle, &DATADOG_G(agent_config_reader)); +#endif + } + } + + ddtrace_internal_handlers_rinit(); + + ddtrace_seed_prng(); + ddtrace_init_span_stacks(); + +#ifndef _WIN32 + ddtrace_dogstatsd_client_rinit(); + if (!get_global_DD_TRACE_SIDECAR_TRACE_SENDER()) { + ddtrace_coms_on_pid_change(); + } +#endif + + // Reset compile time after request init hook has compiled + ddtrace_compile_time_reset(); + + dd_prepare_for_new_trace(); + + ddtrace_distributed_tracing_result distributed_result = ddtrace_read_distributed_tracing_ids(ddtrace_read_zai_header, NULL); + ddtrace_apply_distributed_tracing_result(&distributed_result, NULL); + + if (get_DD_TRACE_GENERATE_ROOT_SPAN()) { + ddtrace_push_root_span(); + } +} + +void ddtrace_rinit(void) { +#if PHP_VERSION_ID < 80000 || (PHP_VERSION_ID >= 80400 && PHP_VERSION_ID < 80500) + zai_interceptor_rinit(); +#endif + + ddtrace_weak_resources_rinit(); + + if (!datadog_disable) { + // With internal functions also being hookable, they must not be hooked before the CG(map_ptr_base) is zeroed + zai_hook_activate(); + DDTRACE_G(active_stack) = NULL; // This should not be necessary, but somehow sometimes it may be a leftover from a previous request. + DDTRACE_G(active_stack) = ddtrace_init_root_span_stack(); +#if PHP_VERSION_ID < 80000 + ddtrace_autoload_rinit(); +#endif + } + + if (get_DD_TRACE_ENABLED()) { + dd_initialize_request(); + } +} + +static void dd_clean_globals(void) { + zend_array_destroy(DDTRACE_G(additional_global_tags)); + zend_hash_destroy(&DDTRACE_G(root_span_tags_preset)); + zend_hash_destroy(&DDTRACE_G(tracestate_unknown_dd_keys)); + zend_hash_destroy(&DDTRACE_G(propagated_root_span_tags)); + zend_hash_destroy(&DDTRACE_G(baggage)); + + if (DDTRACE_G(curl_multi_injecting_spans)) { + if (GC_DELREF(DDTRACE_G(curl_multi_injecting_spans)) == 0) { + rc_dtor_func((zend_refcounted *) DDTRACE_G(curl_multi_injecting_spans)); + } + DDTRACE_G(curl_multi_injecting_spans) = NULL; + } + + if (DDTRACE_G(dd_origin)) { + zend_string_release(DDTRACE_G(dd_origin)); + DDTRACE_G(dd_origin) = NULL; + } + + if (DDTRACE_G(tracestate)) { + zend_string_release(DDTRACE_G(tracestate)); + DDTRACE_G(tracestate) = NULL; + } + + ddtrace_internal_handlers_rshutdown(); +#ifndef _WIN32 + ddtrace_dogstatsd_client_rshutdown(); +#endif + + ddtrace_free_span_stacks(false); +#ifndef _WIN32 + if (!get_global_DD_TRACE_SIDECAR_TRACE_SENDER()) { + ddtrace_coms_rshutdown(); + } +#endif +} + +void dd_force_shutdown_tracing(bool fast_shutdown) { + DDTRACE_G(in_shutdown) = true; + + zend_try { + ddtrace_close_all_open_spans(true); // All remaining userland spans (and root span) + } zend_catch { + LOG(WARN, "Failed to close remaining spans due to bailout"); + } zend_end_try(); + + zend_try { + if (ddtrace_flush_tracer(false, true, fast_shutdown) == FAILURE) { + LOG(WARN, "Unable to flush the tracer"); + } + } zend_catch { + LOG(WARN, "Unable to flush the tracer due to bailout"); + } zend_end_try(); + + // we here need to disable the tracer, so that further hooks do not trigger + datadog_disable_tracing_in_current_request(); // implicitly calling dd_clean_globals + + // The hooks shall not be reset, just disabled at runtime. + zai_hook_clean(fast_shutdown); + + DDTRACE_G(in_shutdown) = false; +} + +static void dd_shutdown_hooks(bool fast_shutdown) { + zai_hook_clean(fast_shutdown); +} + +void ddtrace_rshutdown(bool fast_shutdown) { + zend_hash_destroy(&DDTRACE_G(traced_spans)); + + // this needs to be done before dropping the spans + // run unconditionally because ddtrace may've been disabled mid-request + ddtrace_exec_handlers_rshutdown(); + + if (get_DD_TRACE_ENABLED()) { + dd_force_shutdown_tracing(fast_shutdown); + } + + ddtrace_live_debugger_rshutdown(); + + if (!datadog_disable) { + dd_shutdown_hooks(fast_shutdown); + + ddtrace_autoload_rshutdown(); + + if (!fast_shutdown) { + OBJ_RELEASE(&DDTRACE_G(active_stack)->std); + } + DDTRACE_G(active_stack) = NULL; + } + + ddtrace_clean_git_object(); + ddtrace_weak_resources_rshutdown(); +} + +void ddtrace_post_deactivate(void) { + ddtrace_telemetry_rshutdown(); + + zai_interceptor_deactivate(); + + // we can only actually free our hooks hashtables in post_deactivate, as within RSHUTDOWN some user code may still run + zai_hook_rshutdown(); + zai_uhook_rshutdown(); +} + +void datadog_disable_tracing_in_current_request(void) { + // PHP 8 has ZSTR_CHAR('0') which is nicer... + zend_string *zero = zend_string_init("0", 1, 0); + zend_alter_ini_entry(zai_config_memoized_entries[DATADOG_CONFIG_DD_TRACE_ENABLED].ini_entries[0]->name, zero, + ZEND_INI_USER, ZEND_INI_STAGE_RUNTIME); + zend_string_release(zero); +} + +bool datadog_alter_dd_trace_disabled_config(zval *old_value, zval *new_value, zend_string *new_str) { + (void)new_str; + + if (Z_TYPE_P(old_value) == Z_TYPE_P(new_value)) { + return true; + } + + if (datadog_disable) { + return Z_TYPE_P(new_value) == IS_FALSE; // no changing to enabled allowed if globally disabled + } + + if (!DDTRACE_G(active_stack)) { + return true; // We must not do anything early in RINIT before the necessary structures are initialized at all + } + + if (Z_TYPE_P(old_value) == IS_FALSE) { + dd_initialize_request(); + } else if (!datadog_disable) { // if this is true, the request has not been initialized at all + ddtrace_close_all_open_spans(false); // All remaining userland spans (and root span) + dd_clean_globals(); + } + + return true; +} + +#if defined(__SANITIZE_ADDRESS__) && !defined(_WIN32) +#define JOIN_BGS_BEFORE_FORK 1 +#endif + +void ddtrace_internal_handle_prefork() { +#if JOIN_BGS_BEFORE_FORK + if (!get_global_DD_TRACE_SIDECAR_TRACE_SENDER()) { + ddtrace_coms_flush_shutdown_writer_synchronous(); + } +#endif +} + +void ddtrace_internal_handle_postfork() { +#if JOIN_BGS_BEFORE_FORK + if (!get_global_DD_TRACE_SIDECAR_TRACE_SENDER()) { + ddtrace_coms_restart_writer(); + } +#endif +} + +void ddtrace_internal_handle_fork() { +#ifndef _WIN32 + if (!get_global_DD_TRACE_SIDECAR_TRACE_SENDER()) { + ddtrace_coms_curl_shutdown(); + ddtrace_coms_clean_background_sender_after_fork(); + } +#endif + + ddtrace_seed_prng(); + if (!get_DD_TRACE_FORKED_PROCESS()) { + datadog_disable_tracing_in_current_request(); + } + if (get_DD_TRACE_ENABLED()) { + if (get_DD_DISTRIBUTED_TRACING()) { + DDTRACE_G(distributed_parent_trace_id) = ddtrace_peek_span_id(); + DDTRACE_G(distributed_trace_id) = ddtrace_peek_trace_id(); + } else { + DDTRACE_G(distributed_parent_trace_id) = 0; + DDTRACE_G(distributed_trace_id) = (datadog_trace_id){ 0 }; + } + ddtrace_free_span_stacks(true); + ddtrace_init_span_stacks(); + if (get_DD_TRACE_GENERATE_ROOT_SPAN()) { + ddtrace_push_root_span(); + } + } + +#ifndef _WIN32 + if (!get_global_DD_TRACE_SIDECAR_TRACE_SENDER()) { + ddtrace_coms_init_and_start_writer(); + + if (ddtrace_coms_agent_config_handle) { + ddog_agent_remote_config_reader_for_anon_shm(ddtrace_coms_agent_config_handle, &DATADOG_G(agent_config_reader)); + } + } +#endif +} + +// the following operations are performed in order to put the tracer in a state when a new trace can be started: +// - set a new trace (group) id +void dd_prepare_for_new_trace(void) { +#ifndef _WIN32 + DDTRACE_G(traces_group_id) = ddtrace_coms_next_group_id(); +#endif +} + diff --git a/tracer/ddtrace.h b/tracer/ddtrace.h new file mode 100644 index 00000000000..3a3bf90f9c3 --- /dev/null +++ b/tracer/ddtrace.h @@ -0,0 +1,59 @@ +#ifndef DDTRACE_H +#define DDTRACE_H +#ifndef _WIN32 +#include +#endif + +#include + +extern zend_class_entry *ddtrace_ce_span_data; +extern zend_class_entry *ddtrace_ce_inferred_span_data; +extern zend_class_entry *ddtrace_ce_root_span_data; +extern zend_class_entry *ddtrace_ce_span_stack; +extern zend_class_entry *ddtrace_ce_fatal_error; +extern zend_class_entry *ddtrace_ce_span_link; +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; + +typedef struct ddtrace_span_ids_t ddtrace_span_ids_t; +typedef struct ddtrace_span_data ddtrace_span_data; +typedef struct ddtrace_inferred_span_data ddtrace_inferred_span_data; +typedef struct ddtrace_root_span_data ddtrace_root_span_data; +typedef struct ddtrace_span_stack ddtrace_span_stack; +typedef struct ddtrace_span_link ddtrace_span_link; +typedef struct ddtrace_span_event ddtrace_span_event; +typedef struct ddtrace_exception_span_event ddtrace_exception_span_event; +typedef struct datadog_git_metadata datadog_git_metadata; + +typedef struct dd_refcounted_linked dd_refcounted_linked; + +static inline zend_array *ddtrace_property_array(zval *zv) { + ZVAL_DEREF(zv); + if (Z_TYPE_P(zv) != IS_ARRAY) { + zval garbage; + ZVAL_COPY_VALUE(&garbage, zv); + array_init(zv); + zval_ptr_dtor(&garbage); + } + SEPARATE_ARRAY(zv); + return Z_ARR_P(zv); +} + +extern bool dd_rinit_once_done; + +bool ddtrace_tracer_is_limited(void); +// prepare the tracer state to start handling a new trace +void dd_prepare_for_new_trace(void); +void datadog_disable_tracing_in_current_request(void); +bool datadog_alter_dd_trace_disabled_config(zval *old_value, zval *new_value, zend_string *new_str); +bool ddtrace_alter_sampling_rules_file_config(zval *old_value, zval *new_value, zend_string *new_str); +bool ddtrace_alter_default_propagation_style(zval *old_value, zval *new_value, zend_string *new_str); +bool datadog_alter_dd_service(zval *old_value, zval *new_value, zend_string *new_str); +bool datadog_alter_dd_env(zval *old_value, zval *new_value, zend_string *new_str); +bool datadog_alter_dd_version(zval *old_value, zval *new_value, zend_string *new_str); +void dd_force_shutdown_tracing(bool fast_shutdown); +void ddtrace_internal_handle_fork(void); + +#endif // DDTRACE_H diff --git a/ext/ddtrace.stub.php b/tracer/ddtrace.stub.php similarity index 100% rename from ext/ddtrace.stub.php rename to tracer/ddtrace.stub.php diff --git a/ext/ddtrace_arginfo.h b/tracer/ddtrace_arginfo.h similarity index 100% rename from ext/ddtrace_arginfo.h rename to tracer/ddtrace_arginfo.h diff --git a/tracer/ddtrace_globals.h b/tracer/ddtrace_globals.h new file mode 100644 index 00000000000..9573aa47e95 --- /dev/null +++ b/tracer/ddtrace_globals.h @@ -0,0 +1,97 @@ +#ifndef DDTRACE_GLOBALS_H +#define DDTRACE_GLOBALS_H +#ifndef _WIN32 +#include +#endif + +#include + +typedef struct ddtrace_span_ids_t ddtrace_span_ids_t; +typedef struct ddtrace_span_data ddtrace_span_data; +typedef struct ddtrace_inferred_span_data ddtrace_inferred_span_data; +typedef struct ddtrace_root_span_data ddtrace_root_span_data; +typedef struct ddtrace_span_stack ddtrace_span_stack; +typedef struct ddtrace_span_link ddtrace_span_link; +typedef struct ddtrace_span_event ddtrace_span_event; +typedef struct ddtrace_exception_span_event ddtrace_exception_span_event; +typedef struct datadog_git_metadata datadog_git_metadata; + +typedef struct dd_refcounted_linked dd_refcounted_linked; + +typedef struct { + zend_arena *arena; + dd_refcounted_linked *ephemerals; +} dd_capture_arena; + +typedef struct { + int type; + zend_string *message; +} ddtrace_error_data; + +// clang-format off +typedef struct { + zend_bool api_is_loaded; + zend_bool otel_is_loaded; + zend_bool legacy_tracer_is_loaded; + + uint32_t traces_group_id; + zend_array *additional_global_tags; + zend_array root_span_tags_preset; + zend_array propagated_root_span_tags; + zend_string *tracestate; + zend_array tracestate_unknown_dd_keys; + ddtrace_error_data active_error; + HashTable baggage; +#ifndef _WIN32 + dogstatsd_client dogstatsd_client; +#endif + zend_bool in_shutdown; + + zend_long default_priority_sampling; + zend_long propagated_priority_sampling; + ddtrace_span_stack *active_stack; // never NULL except tracer is disabled + ddtrace_span_stack *top_closed_stack; + HashTable traced_spans; // tie a span to a specific active execute_data + uint32_t open_spans_count; + uint32_t baggage_extract_count; + uint32_t baggage_inject_count; + uint32_t baggage_malformed_count; + uint32_t baggage_max_item_count; + uint32_t baggage_max_byte_count; + uint32_t baggage_extract_max_item_count; + uint32_t baggage_extract_max_byte_count; + uint32_t closed_spans_count; + uint32_t dropped_spans_count; + int64_t compile_time_microseconds; + datadog_trace_id distributed_trace_id; + uint64_t distributed_parent_trace_id; + zend_string *dd_origin; + zend_reference *curl_multi_injecting_spans; + + dd_capture_arena debugger_capture_arena; + ddog_Vec_DebuggerPayload exception_debugger_buffer; + HashTable active_live_debugger_hooks; + HashTable *agent_rate_by_service; + + HashTable telemetry_spans_created_per_integration; + +#if PHP_VERSION_ID >= 80000 + HashTable curl_headers; + // Multi-handle API: curl_multi_*() + HashTable curl_multi_handles; +#endif + + HashTable uhook_active_hooks; + HashTable uhook_closure_hooks; + + zend_object *git_object; + + bool inferred_span_created; + + HashTable resource_weak_storage; + dtor_func_t resource_dtor_func; +} ddtrace_globals; + +#define DDTRACE_G(v) (DATADOG_G(ddtrace).v) + +#endif // DDTRACE_H diff --git a/ext/distributed_tracing_headers.c b/tracer/distributed_tracing_headers.c similarity index 98% rename from ext/distributed_tracing_headers.c rename to tracer/distributed_tracing_headers.c index 2ca302c9b0a..78d02939b37 100644 --- a/ext/distributed_tracing_headers.c +++ b/tracer/distributed_tracing_headers.c @@ -1,11 +1,12 @@ #include "distributed_tracing_headers.h" #include "configuration.h" +#include "random.h" #include "tracer_tag_propagation/tracer_tag_propagation.h" #include "serializer.h" #include #include -ZEND_EXTERN_MODULE_GLOBALS(ddtrace); +ZEND_EXTERN_MODULE_GLOBALS(datadog); static inline bool dd_is_hex_char(char chr) { return (chr >= '0' && chr <= '9') || (chr >= 'a' && chr <= 'f'); @@ -181,7 +182,7 @@ static ddtrace_distributed_tracing_result ddtrace_read_distributed_tracing_ids_d if (read_header((zai_str)ZAI_STRL("X_DATADOG_TRACE_ID"), "x-datadog-trace-id", &trace_id_str, data)) { zval trace_zv; ZVAL_STR(&trace_zv, trace_id_str); - result.trace_id = (ddtrace_trace_id) {.low = ddtrace_parse_userland_span_id(&trace_zv)}; + result.trace_id = (datadog_trace_id) {.low = ddtrace_parse_userland_span_id(&trace_zv)}; zend_string_release(trace_id_str); } @@ -341,7 +342,7 @@ static ddtrace_distributed_tracing_result ddtrace_read_distributed_tracing_ids_t return result; } - ddtrace_trace_id trace_id = { + datadog_trace_id trace_id = { .high = ddtrace_parse_hex_span_id_str(tracedata->trace_id, 16), .low = ddtrace_parse_hex_span_id_str(&tracedata->trace_id[16], 16) }; @@ -482,8 +483,8 @@ static ddtrace_distributed_tracing_result ddtrace_read_distributed_tracing_ids_t ddtrace_distributed_tracing_result ddtrace_read_distributed_tracing_ids(ddtrace_read_header *read_header, void *data) { ddtrace_distributed_tracing_result result = {0}; - zend_array *extract = zai_config_is_modified(DDTRACE_CONFIG_DD_TRACE_PROPAGATION_STYLE) - && !zai_config_is_modified(DDTRACE_CONFIG_DD_TRACE_PROPAGATION_STYLE_EXTRACT) + zend_array *extract = zai_config_is_modified(DATADOG_CONFIG_DD_TRACE_PROPAGATION_STYLE) + && !zai_config_is_modified(DATADOG_CONFIG_DD_TRACE_PROPAGATION_STYLE_EXTRACT) ? get_DD_TRACE_PROPAGATION_STYLE() : get_DD_TRACE_PROPAGATION_STYLE_EXTRACT(); zend_string *extraction_style; @@ -625,7 +626,7 @@ void ddtrace_apply_distributed_tracing_result(ddtrace_distributed_tracing_result ZVAL_ARR(&zv, emalloc(sizeof(HashTable))); *Z_ARR(zv) = result->propagated_tags; - ddtrace_assign_variable(&span->property_propagated_tags, &zv); + datadog_assign_variable(&span->property_propagated_tags, &zv); zend_hash_copy(root_meta, &result->meta_tags, NULL); ddtrace_span_data *inferred_span = ddtrace_get_inferred_span(span); @@ -636,17 +637,17 @@ void ddtrace_apply_distributed_tracing_result(ddtrace_distributed_tracing_result if (result->origin) { ZVAL_STR(&zv, result->origin); - ddtrace_assign_variable(&span->property_origin, &zv); + datadog_assign_variable(&span->property_origin, &zv); } if (result->tracestate) { ZVAL_STR(&zv, result->tracestate); - ddtrace_assign_variable(&span->property_tracestate, &zv); + datadog_assign_variable(&span->property_tracestate, &zv); } ZVAL_ARR(&zv, emalloc(sizeof(HashTable))); *Z_ARR(zv) = result->tracestate_unknown_dd_keys; - ddtrace_assign_variable(&span->property_tracestate_tags, &zv); + datadog_assign_variable(&span->property_tracestate_tags, &zv); zend_array *existing_baggage = ddtrace_property_array(&span->property_baggage); zend_string *key; @@ -704,7 +705,7 @@ void ddtrace_apply_distributed_tracing_result(ddtrace_distributed_tracing_result if (result->trace_id.low || result->trace_id.high || result->priority_sampling != DDTRACE_PRIORITY_SAMPLING_UNKNOWN) { if (span) { ZVAL_LONG(&zv, result->priority_sampling); - ddtrace_assign_variable(&span->property_propagated_sampling_priority, &zv); + datadog_assign_variable(&span->property_propagated_sampling_priority, &zv); } else { DDTRACE_G(propagated_priority_sampling) = result->priority_sampling; } diff --git a/ext/distributed_tracing_headers.h b/tracer/distributed_tracing_headers.h similarity index 97% rename from ext/distributed_tracing_headers.h rename to tracer/distributed_tracing_headers.h index 397aed1f35f..9956444431b 100644 --- a/ext/distributed_tracing_headers.h +++ b/tracer/distributed_tracing_headers.h @@ -6,7 +6,7 @@ #include typedef struct { - ddtrace_trace_id trace_id; + datadog_trace_id trace_id; uint64_t parent_id; zend_string *origin; zend_string *tracestate; diff --git a/ext/dogstatsd_client.c b/tracer/dogstatsd_client.c similarity index 97% rename from ext/dogstatsd_client.c rename to tracer/dogstatsd_client.c index 1af24700176..d9f9142c1ca 100644 --- a/ext/dogstatsd_client.c +++ b/tracer/dogstatsd_client.c @@ -2,12 +2,12 @@ #include -#include "dogstatsd.h" +#include #include "configuration.h" #include "ddtrace.h" #include -ZEND_EXTERN_MODULE_GLOBALS(ddtrace); +ZEND_EXTERN_MODULE_GLOBALS(datadog); #define METRICS_CONST_TAGS "lang:php,lang_version:" PHP_VERSION ",tracer_version:" PHP_DDTRACE_VERSION #define DEFAULT_UDS_PATH "/var/run/datadog/dsd.socket" @@ -36,7 +36,7 @@ void ddtrace_dogstatsd_client_rinit(void) { while (health_metrics_enabled) { struct addrinfo *addrs = NULL; - char *url = ddtrace_dogstatsd_url(); + char *url = datadog_dogstatsd_url(); if (strlen(url) > 7 && strncmp("unix://", url, 7) == 0) { addrs = dd_alloc_unix_addr(url + 7, strlen(url) - 7); } else if (strlen(url) > 6 && strncmp("udp://", url, 6) == 0) { diff --git a/ext/dogstatsd_client.h b/tracer/dogstatsd_client.h similarity index 88% rename from ext/dogstatsd_client.h rename to tracer/dogstatsd_client.h index 1177fc0c1f3..7901732fb0b 100644 --- a/ext/dogstatsd_client.h +++ b/tracer/dogstatsd_client.h @@ -1,7 +1,7 @@ #ifndef DDTRACE_DOGSTATSD_CLIENT_H #define DDTRACE_DOGSTATSD_CLIENT_H -#include "compatibility.h" +#include void ddtrace_dogstatsd_client_minit(void); void ddtrace_dogstatsd_client_rinit(void); diff --git a/ext/endpoint_guessing.c b/tracer/endpoint_guessing.c similarity index 98% rename from ext/endpoint_guessing.c rename to tracer/endpoint_guessing.c index 3aff01b0e54..a4db744bb3f 100644 --- a/ext/endpoint_guessing.c +++ b/tracer/endpoint_guessing.c @@ -18,8 +18,6 @@ static inline bool is_digit(char c) { return c >= '0' && c <= '9'; } -static inline bool is_nonzero_digit(char c) { return c >= '1' && c <= '9'; } - static inline bool is_hex_alpha(char c) { return (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'); } static inline bool is_delim(char c) { return c == '.' || c == '_' || c == '-'; } @@ -185,7 +183,7 @@ static zend_string* guess_endpoint(const char* orig_url, size_t orig_url_len) { return smart_str_extract(&result); } -DDTRACE_PUBLIC zend_string* ddtrace_guess_endpoint_from_url(const char* url, size_t url_len) +DATADOG_PUBLIC zend_string* ddtrace_guess_endpoint_from_url(const char* url, size_t url_len) { return guess_endpoint(url, url_len); } diff --git a/ext/endpoint_guessing.h b/tracer/endpoint_guessing.h similarity index 59% rename from ext/endpoint_guessing.h rename to tracer/endpoint_guessing.h index 94088dcf723..cb986fd571d 100644 --- a/ext/endpoint_guessing.h +++ b/tracer/endpoint_guessing.h @@ -1,7 +1,7 @@ #pragma once #include "ddtrace.h" -#include "ddtrace_export.h" +#include void ddtrace_maybe_add_guessed_endpoint_tag(ddtrace_root_span_data *span); -DDTRACE_PUBLIC zend_string* ddtrace_guess_endpoint_from_url(const char* url, size_t url_len); +DATADOG_PUBLIC zend_string* ddtrace_guess_endpoint_from_url(const char* url, size_t url_len); diff --git a/ext/engine_api.c b/tracer/engine_api.c similarity index 100% rename from ext/engine_api.c rename to tracer/engine_api.c diff --git a/ext/engine_api.h b/tracer/engine_api.h similarity index 100% rename from ext/engine_api.h rename to tracer/engine_api.h diff --git a/ext/engine_hooks.c b/tracer/engine_hooks.c similarity index 94% rename from ext/engine_hooks.c rename to tracer/engine_hooks.c index a315cb32aa3..622af302a7e 100644 --- a/ext/engine_hooks.c +++ b/tracer/engine_hooks.c @@ -5,7 +5,7 @@ #include "ddtrace.h" #include -#include "zend_hrtime.h" +#include #include "span.h" #include "zend_extensions.h" #include @@ -19,7 +19,7 @@ #define GET_DL_ERROR() DL_ERROR() #endif -ZEND_EXTERN_MODULE_GLOBALS(ddtrace); +ZEND_EXTERN_MODULE_GLOBALS(datadog); static zend_op_array *(*_prev_compile_file)(zend_file_handle *file_handle, int type); @@ -73,7 +73,7 @@ void ddtrace_engine_hooks_mshutdown(void) { _compile_mshutdown(); } -static zend_op_array *_dd_compile_file(zend_file_handle *file_handle, int type) { +static zend_op_array *dd_compile_file(zend_file_handle *file_handle, int type) { zend_op_array *res; uint64_t start = zend_hrtime(); res = _prev_compile_file(file_handle, type); @@ -83,11 +83,11 @@ static zend_op_array *_dd_compile_file(zend_file_handle *file_handle, int type) static void _compile_minit(void) { _prev_compile_file = zend_compile_file; - zend_compile_file = _dd_compile_file; + zend_compile_file = dd_compile_file; } static void _compile_mshutdown(void) { - if (zend_compile_file == _dd_compile_file) { + if (zend_compile_file == dd_compile_file) { zend_compile_file = _prev_compile_file; } } diff --git a/ext/engine_hooks.h b/tracer/engine_hooks.h similarity index 97% rename from ext/engine_hooks.h rename to tracer/engine_hooks.h index fe130b7e5fc..5e8682b7f66 100644 --- a/ext/engine_hooks.h +++ b/tracer/engine_hooks.h @@ -9,11 +9,10 @@ #include #include -#include "compatibility.h" +#include #include "ddtrace.h" -#include "ddtrace_string.h" -ZEND_EXTERN_MODULE_GLOBALS(ddtrace) +ZEND_EXTERN_MODULE_GLOBALS(datadog) void ddtrace_engine_hooks_minit(void); void ddtrace_fetch_profiling_symbols(void); diff --git a/ext/exception_serialize.c b/tracer/exception_serialize.c similarity index 98% rename from ext/exception_serialize.c rename to tracer/exception_serialize.c index 2a933f19283..6bfed86d7a3 100644 --- a/ext/exception_serialize.c +++ b/tracer/exception_serialize.c @@ -5,20 +5,21 @@ #include "ddtrace.h" #include "configuration.h" #include "exception_serialize.h" -#include "compat_string.h" #include "SAPI.h" #include "components/log/log.h" -#include "sidecar.h" +#include +#include +#include #include "live_debugger.h" -#include "ext/hash/php_hash.h" +#include #include -ZEND_EXTERN_MODULE_GLOBALS(ddtrace); +ZEND_EXTERN_MODULE_GLOBALS(datadog); static void dd_exception_to_error_msg(zend_object *exception, ddog_SpanBytes *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 = ddtrace_convert_to_str(zai_exception_read_property(exception, ZSTR_KNOWN(ZEND_STR_FILE))); + zend_string *file = datadog_convert_to_str(zai_exception_read_property(exception, ZSTR_KNOWN(ZEND_STR_FILE))); char *error_text, *status_line = NULL; @@ -384,7 +385,7 @@ static void ddtrace_collect_exception_debug_data(zend_object *exception, zend_ob 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}); - if (!ddog_exception_hash_limiter_inc(DDTRACE_G(sidecar), (uint64_t)exception_long_hash, get_DD_EXCEPTION_REPLAY_CAPTURE_INTERVAL_SECONDS())) { + 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); goto cleanup; } @@ -500,7 +501,7 @@ void ddtrace_exception_to_meta(zend_object *exception, zend_string *service_name 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 = ddtrace_convert_to_str(zai_exception_read_property(exception, ZSTR_KNOWN(ZEND_STR_FILE))); + zend_string *file = datadog_convert_to_str(zai_exception_read_property(exception, ZSTR_KNOWN(ZEND_STR_FILE))); zend_string *complete_trace = zend_strpprintf(0, "%s\n\nNext %s%s%s in %s:" ZEND_LONG_FMT "\nStack trace:\n%s", ZSTR_VAL(trace_string), diff --git a/ext/exception_serialize.h b/tracer/exception_serialize.h similarity index 100% rename from ext/exception_serialize.h rename to tracer/exception_serialize.h diff --git a/ext/ddtrace.c b/tracer/functions.c similarity index 59% rename from ext/ddtrace.c rename to tracer/functions.c index 625c9cfa03b..75dd242d1dd 100644 --- a/ext/ddtrace.c +++ b/tracer/functions.c @@ -1,99 +1,34 @@ -#include "components-rs/common.h" -#include "components-rs/sidecar.h" -#include "zend_API.h" -#include "zend_hash.h" -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif #include "ddtrace.h" -#include -#include -#include +#include "configuration.h" +#include "span.h" #include -#include -#include -#include -#include -#include -#include -#if PHP_VERSION_ID < 80000 -#include -#include -#else -#include -#endif -#include -#include -#include -#ifndef _WIN32 -#include -#include -#include -#else -#include -#include -#endif - -#include -#include -#include - -#include -#include - -#include "asm_event.h" -#include "trace_source.h" +#include #include "auto_flush.h" -#include "compatibility.h" -#ifndef _WIN32 -#include "comms_php.h" -#include "coms.h" -#endif -#include "config/config.h" -#include "configuration.h" -#include "ddshared.h" -#include "ddtrace_string.h" -#ifndef _WIN32 -#include "dogstatsd_client.h" -#endif +#include "code_origins.h" #include "engine_hooks.h" -#include "excluded_modules.h" -#include "handlers_http.h" -#include "handlers_internal.h" -#include "integrations/exec_integration.h" -#include "integrations/integrations.h" -#include "ip_extraction.h" -#include "logging.h" +#include "handlers_exception.h" #include "memory_limit.h" -#include "limiter/limiter.h" -#include "standalone_limiter.h" -#include "priority_sampling/priority_sampling.h" -#include "process_tags.h" #include "random.h" -#include "autoload_php_files.h" -#include "remote_config.h" #include "serializer.h" -#include "sidecar.h" +#include "weak_resources.h" +#include +#include "handlers_http.h" +#include "ip_extraction.h" +#include "tracer_telemetry.h" +#include "tracer_tag_propagation/tracer_tag_propagation.h" +#include +#include +#include +#include +#include +#include +#include +#include #ifndef _WIN32 -#include "signals.h" -#else -#include "crashtracking_windows.h" +#include "comms_php.h" +#include "coms.h" #endif -#include "span.h" -#include "startup_logging.h" -#include "telemetry.h" -#include "threads.h" -#include "tracer_tag_propagation/tracer_tag_propagation.h" -#include "user_request.h" -#include "weak_resources.h" -#include "zend_hrtime.h" -#include - -#include "hook/uhook.h" -#include "handlers_fiber.h" -#include "handlers_exception.h" -#include "exceptions/exceptions.h" -#include "git.h" +#include // On PHP 7 we cannot declare arrays as internal values. Assign null and handle in create_object where necessary. #if PHP_VERSION_ID < 80000 @@ -108,12 +43,6 @@ #define ZVAL_EMPTY_STRING(z) ZVAL_NEW_STR(z, zend_string_init("", 0, 1)) #endif #include "ddtrace_arginfo.h" -#include "distributed_tracing_headers.h" -#include "inferred_proxy_headers.h" -#include "live_debugger.h" -#include "agent_info.h" -#include "code_origins.h" - #if PHP_VERSION_ID < 70200 #pragma pop_macro("ZVAL_EMPTY_STRING") #endif @@ -126,597 +55,7 @@ #define _error_code error_code #endif -bool ddtrace_has_excluded_module; -static zend_module_entry *ddtrace_module; -#if PHP_VERSION_ID >= 80000 && PHP_VERSION_ID < 80200 -static bool dd_has_other_observers; -static int dd_observer_extension_backup = -1; -#endif - -datadog_php_sapi ddtrace_active_sapi = DATADOG_PHP_SAPI_UNKNOWN; - -ddog_CharSlice php_version_rt; - -_Atomic(int64_t) ddtrace_warn_legacy_api; - -ZEND_DECLARE_MODULE_GLOBALS(ddtrace) - -#ifdef COMPILE_DL_DDTRACE -ZEND_GET_MODULE(ddtrace) -#ifdef ZTS -TSRM_TLS void *TSRMLS_CACHE = NULL; -#endif -#endif - -static int dd_main_pid; - -int ddtrace_disable = 0; // 0 = enabled, 1 = disabled via INI, 2 = disabled, but MINIT was fully executed -static ZEND_INI_MH(dd_OnUpdateDisabled) { - UNUSED(entry, mh_arg1, mh_arg2, mh_arg3, stage); - if (!ddtrace_disable) { - ddtrace_disable = zend_ini_parse_bool(new_value); - } - return SUCCESS; -} - -PHP_INI_BEGIN() - ZEND_INI_ENTRY("ddtrace.disable", "0", PHP_INI_SYSTEM, dd_OnUpdateDisabled) - - // Exposed for testing only - STD_PHP_INI_ENTRY("ddtrace.cgroup_file", "/proc/self/cgroup", PHP_INI_SYSTEM, OnUpdateString, cgroup_file, - zend_ddtrace_globals, ddtrace_globals) -PHP_INI_END() - -#if PHP_VERSION_ID >= 70300 && PHP_VERSION_ID < 70400 -static void ddtrace_sort_modules(void *base, size_t count, size_t siz, compare_func_t compare, swap_func_t swp) { - UNUSED(siz); - UNUSED(compare); - UNUSED(swp); - - // swap ddtrace and opcache for the rest of the modules lifecycle, so that opcache is always executed after ddtrace - for (Bucket *module = base, *end = module + count, *ddtrace_module = NULL; module < end; ++module) { - zend_module_entry *m = (zend_module_entry *)Z_PTR(module->val); - if (m->name == ddtrace_module_entry.name) { - ddtrace_module = module; - } - if (ddtrace_module && strcmp(m->name, "Zend OPcache") == 0) { - Bucket tmp = *ddtrace_module; - *ddtrace_module = *module; - *module = tmp; - break; - } - } -} -#endif - -#if PHP_VERSION_ID >= 80000 && PHP_VERSION_ID < 80200 -// On PHP 8.0.0-8.0.16 and 8.1.0-8.1.2 call_attribute_constructor would stack allocate a dummy frame, which could have become inaccessible upon access. -// Thus, we implement the fix which was applied to PHP itself as well: we move the stack allocated data to the VM stack. -// See also https://github.com/php/php-src/commit/f7c3f6e7e25471da9cfb2ba082a77cc3c85bc6ed -static void dd_patched_zend_call_known_function( - zend_function *fn, zend_object *object, zend_class_entry *called_scope, zval *retval_ptr, - uint32_t param_count, zval *params, HashTable *named_params) -{ - zval retval; - zend_fcall_info fci; - zend_fcall_info_cache fcic; - - // If current_execute_data is on the stack, move it to the VM stack - zend_execute_data *execute_data = EG(current_execute_data); - if (execute_data) { - bool is_stack_ex = (uintptr_t)&retval + 0xfffff > (uintptr_t)execute_data && (uintptr_t)&retval - 0xfffff < (uintptr_t)execute_data; - bool is_stack_func = (uintptr_t)&retval + 0xfffff > (uintptr_t)EX(func) && (uintptr_t)&retval - 0xfffff < (uintptr_t)EX(func); - if (is_stack_ex || is_stack_func) { - zend_execute_data *call = zend_vm_stack_push_call_frame_ex( - ZEND_MM_ALIGNED_SIZE_EX(sizeof(zend_execute_data), sizeof(zval)) + - (is_stack_func ? ZEND_MM_ALIGNED_SIZE_EX(sizeof(zend_op), sizeof(zval)) + ZEND_MM_ALIGNED_SIZE_EX(sizeof(zend_function), sizeof(zval)) : 0), - 0, EX(func), 0, NULL); - - memcpy(call, execute_data, sizeof(zend_execute_data)); - if (is_stack_func) { - zend_op *opline = (zend_op *)(call + 1); - memcpy(opline, EX(opline), sizeof(zend_op)); - zend_function *func = (zend_function *)(opline + 1); - memcpy(func, EX(func), sizeof(zend_function)); - func->common.fn_flags |= ZEND_ACC_CALL_VIA_TRAMPOLINE; // See https://github.com/php/php-src/commit/2f6a06ccb0ef78e6122bb9e67f9b8b1ad07776e1 - - call->opline = opline; - call->func = func; - } else { - call->opline = EX(opline); - } - - EG(current_execute_data) = call; - } - } - - // here follows the original implementation of zend_call_known_function - - fci.size = sizeof(fci); - fci.object = object; - fci.retval = retval_ptr ? retval_ptr : &retval; - fci.param_count = param_count; - fci.params = params; - fci.named_params = named_params; - ZVAL_UNDEF(&fci.function_name); /* Unused */ - - fcic.function_handler = fn; - fcic.object = object; - fcic.called_scope = called_scope; - - zend_result result = zend_call_function(&fci, &fcic); - if (UNEXPECTED(result == FAILURE)) { - if (!EG(exception)) { - zend_error_noreturn(E_CORE_ERROR, "Couldn't execute method %s%s%s", - fn->common.scope ? ZSTR_VAL(fn->common.scope->name) : "", - fn->common.scope ? "::" : "", ZSTR_VAL(fn->common.function_name)); - } - } - - if (!retval_ptr) { - zval_ptr_dtor(&retval); - } -} - -// We need to hijack zend_call_known_function as that's what's being called by call_attribute_constructor, and call_attribute_constructor itself is not exported. -static void dd_patch_zend_call_known_function(void) { -#ifdef _WIN32 - SYSTEM_INFO si; - GetSystemInfo(&si); - size_t page_size = (size_t)si.dwPageSize; -#else - size_t page_size = sysconf(_SC_PAGESIZE); -#endif - void *page = (void *)(~(page_size - 1) & (uintptr_t)zend_call_known_function); - // 20 is the largest size of a trampoline we have to inject - if ((((uintptr_t)zend_call_known_function + 20) & page_size) < 20) { - page_size <<= 1; // if overlapping pages, use two - } - -#ifdef _WIN32 - DWORD old_protection; - if (!VirtualProtect(page, page_size, PAGE_READWRITE, &old_protection)) -#else - if (mprotect(page, page_size, PROT_READ | PROT_WRITE) != 0) -#endif - { // Some architectures enforce W^X (either write _or_ execute, but not both). - LOG(ERROR, "Could not alter the memory protection for zend_call_known_function. Tracer execution continues, but may crash when encountering attributes."); - return; // Make absolutely sure we can write - } - -#ifdef __aarch64__ - // x13 is a scratch register - uint32_t absolute_jump_instrs[] = { - 0x1000006D, // adr x13, 12 (load address from memory after this) - 0xF94001AD, // ldr x13, [x13] - 0xD61F01A0, // br x13 - }; - // The magical 12 is sizeof(absolute_jump_instrs) and hardcoded in the assembly above. - memcpy(zend_call_known_function, absolute_jump_instrs, 12); - *(void **)(12 + (uintptr_t)zend_call_known_function) = dd_patched_zend_call_known_function; -#else - // $r10 doesn't really have special meaning - uint8_t absolute_jump_instrs[] = { - 0x49, 0xBA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov $r10, imm_addr - 0x41, 0xFF, 0xE2 // jmp $r10 - }; - *(void **)&absolute_jump_instrs[2] = dd_patched_zend_call_known_function; - memcpy(zend_call_known_function, absolute_jump_instrs, sizeof(absolute_jump_instrs)); -#endif - -#ifdef _WIN32 - VirtualProtect(page, page_size, old_protection, &old_protection /* dummy, but must be valid */); -#else - mprotect(page, page_size, PROT_READ | PROT_EXEC); -#endif -} -#endif - -// put this into startup so that other extensions running code as part of rinit do not crash -static int ddtrace_startup(zend_extension *extension) { - UNUSED(extension); - - ddtrace_fetch_profiling_symbols(); - -#if PHP_VERSION_ID >= 70300 && PHP_VERSION_ID < 70400 - // Turns out with zai config we have dynamically allocated INI entries. This does not play well with PHP 7.3 - // As of PHP 7.3 opcache stores INI entry values in SHM. However, only as of PHP 7.4 opcache delays detaching SHM. - // In PHP 7.3 SHM is freed in MSHUTDOWN, which may be executed before our extension, if we do not force an order. - // We have to sort this manually here, as opcache only registers itself as extension during zend_extension.startup. - zend_hash_sort_ex(&module_registry, ddtrace_sort_modules, NULL, 0); -#endif - -#if PHP_VERSION_ID >= 80000 && PHP_VERSION_ID < 80200 - dd_has_other_observers = ZEND_OBSERVER_ENABLED; -#endif - -#if PHP_VERSION_ID < 80000 - zai_interceptor_startup(ddtrace_module); -#else - zai_interceptor_startup(); -#endif - -#if PHP_VERSION_ID >= 80000 && PHP_VERSION_ID < 80200 -#if PHP_VERSION_ID < 80100 -#define BUG_STACK_ALLOCATED_CALL_PATCH_VERSION 16 -#else -#define BUG_STACK_ALLOCATED_CALL_PATCH_VERSION 3 -#endif - zend_long patch_version = Z_LVAL_P(zend_get_constant_str(ZEND_STRL("PHP_RELEASE_VERSION"))); - if (patch_version < BUG_STACK_ALLOCATED_CALL_PATCH_VERSION) { - dd_patch_zend_call_known_function(); - } -#endif - - if (!ddtrace_disable) { - ddtrace_excluded_modules_startup(); - // We deliberately leave handler replacement during startup, even though this uses some config - // This touches global state, which, while unlikely, may play badly when interacting with other extensions, if done post-startup - ddtrace_internal_handlers_startup(); - } - return SUCCESS; -} - -static void ddtrace_shutdown(struct _zend_extension *extension) { - UNUSED(extension); - - if (ddtrace_disable != 1) { - ddtrace_internal_handlers_shutdown(); - } - - zai_interceptor_shutdown(); -} - -bool dd_save_sampling_rules_file_config(zend_string *path, int modify_type, int stage) { - if (FG(default_context) == NULL) { - FG(default_context) = php_stream_context_alloc(); - } - php_stream_context *context = FG(default_context); - php_stream *stream = php_stream_open_wrapper_ex(ZSTR_VAL(path), "rb", USE_PATH | REPORT_ERRORS, NULL, context); - if (!stream) { - return false; - } - - zend_string *file = php_stream_copy_to_mem(stream, (ssize_t) PHP_STREAM_COPY_ALL, 0); - php_stream_close(stream); - - bool altered = false; - if (file) { - altered = ZSTR_LEN(file) > 0 && SUCCESS == zend_alter_ini_entry_ex( - zai_config_memoized_entries[DDTRACE_CONFIG_DD_SPAN_SAMPLING_RULES].ini_entries[0]->name, - file, modify_type, stage, 1); - zend_string_release(file); - } - return altered; -} - -bool ddtrace_alter_sampling_rules_file_config(zval *old_value, zval *new_value, zend_string *new_str) { - (void) old_value; - (void) new_str; - if (Z_STRLEN_P(new_value) == 0) { - return true; - } - - return dd_save_sampling_rules_file_config(Z_STR_P(new_value), PHP_INI_USER, PHP_INI_STAGE_RUNTIME); -} - -static inline void dd_alter_prop(size_t prop_offset, zval *old_value, zval *new_value, zend_string *new_str) { - UNUSED(old_value, new_str); - - ddtrace_span_properties *pspan = ddtrace_active_span_props(); - while (pspan) { - zval *property = (zval *) (prop_offset + (char *) pspan), garbage = *property; - ZVAL_COPY(property, new_value); - zval_ptr_dtor(&garbage); - pspan = pspan->parent; - } -} - -bool ddtrace_alter_dd_service(zval *old_value, zval *new_value, zend_string *new_str) { - dd_alter_prop(XtOffsetOf(ddtrace_span_properties, property_service), old_value, new_value, new_str); - if (DDTRACE_G(request_initialized)) { - ddtrace_sidecar_submit_root_span_data_direct(&DDTRACE_G(sidecar), NULL, new_str, get_DD_ENV(), get_DD_VERSION()); - } - return true; -} -bool ddtrace_alter_dd_env(zval *old_value, zval *new_value, zend_string *new_str) { - dd_alter_prop(XtOffsetOf(ddtrace_span_properties, property_env), old_value, new_value, new_str); - if (DDTRACE_G(request_initialized)) { - ddtrace_sidecar_submit_root_span_data_direct(&DDTRACE_G(sidecar), NULL, get_DD_SERVICE(), new_str, get_DD_VERSION()); - } - return true; -} -bool ddtrace_alter_dd_version(zval *old_value, zval *new_value, zend_string *new_str) { - dd_alter_prop(XtOffsetOf(ddtrace_span_properties, property_version), old_value, new_value, new_str); - if (DDTRACE_G(request_initialized)) { - ddtrace_sidecar_submit_root_span_data_direct(&DDTRACE_G(sidecar), NULL, get_DD_SERVICE(), get_DD_ENV(), new_str); - } - return true; -} - -static void dd_activate_once(void) { - ddtrace_config_first_rinit(); - if (dd_main_pid != getpid()) { // equal to session id if not a fork - ddtrace_generate_runtime_id(); - } - - // must run before the first zai_hook_activate as ddtrace_telemetry_setup installs a global hook - if (!ddtrace_disable) { - bool appsec_activation = false; - bool appsec_config = false; - -#ifndef _WIN32 - // Only disable sidecar sender when explicitly disabled - bool bgs_fallback = DD_SIDECAR_TRACE_SENDER_DEFAULT && get_global_DD_TRACE_SIDECAR_TRACE_SENDER() && zai_config_memoized_entries[DDTRACE_CONFIG_DD_TRACE_SIDECAR_TRACE_SENDER].name_index == ZAI_CONFIG_ORIGIN_DEFAULT && !get_global_DD_INSTRUMENTATION_TELEMETRY_ENABLED(); - zend_string *bgs_service = NULL; - if (bgs_fallback) { - // We enabled sending traces through the sidecar by default - // That said a few customers have explicitly disabled telemetry to disable the sidecar - // So if telemetry is disabled, we will disable the sidecar and send a one shot telemetry call - ddtrace_change_default_ini(DDTRACE_CONFIG_DD_TRACE_SIDECAR_TRACE_SENDER, (zai_str) ZAI_STR_FROM_CSTR("0")); - if ((bgs_service = get_DD_SERVICE())) { - zend_string_addref(bgs_service); - } else { - bgs_service = ddtrace_default_service_name(); - } - } - - // if we're to enable appsec, we need to enable sidecar - bool enable_sidecar = ddtrace_sidecar_should_enable(&appsec_activation, &appsec_config); - - if (enable_sidecar) -#endif - { - bool request_startup = PG(during_request_startup); - PG(during_request_startup) = false; - ddtrace_sidecar_setup(appsec_activation, appsec_config); - PG(during_request_startup) = request_startup; - } -#ifndef _WIN32 - if (!get_global_DD_TRACE_SIDECAR_TRACE_SENDER()) { - if (get_global_DD_TRACE_AGENT_FLUSH_AFTER_N_REQUESTS() == 0) { - // Set the default to 10 so that BGS flushes faster. With sidecar it's not needed generally. - ddtrace_change_default_ini(DDTRACE_CONFIG_DD_TRACE_AGENT_FLUSH_AFTER_N_REQUESTS, (zai_str) ZAI_STR_FROM_CSTR("10")); - } - if (get_DD_TRACE_AGENT_FLUSH_INTERVAL() == DD_TRACE_AGENT_FLUSH_INTERVAL_VAL) { - // Set the default to 5000 so that BGS does not flush too often. The sidecar can flush more often, but the BGS is per process. Keep it higher to avoid too much load on the agent. - ddtrace_change_default_ini(DDTRACE_CONFIG_DD_TRACE_AGENT_FLUSH_INTERVAL, (zai_str) ZAI_STR_FROM_CSTR("5000")); - } - ddtrace_coms_minit(get_global_DD_TRACE_AGENT_STACK_INITIAL_SIZE(), - get_global_DD_TRACE_AGENT_MAX_PAYLOAD_SIZE(), - get_global_DD_TRACE_AGENT_STACK_BACKLOG(), - bgs_fallback ? ZSTR_VAL(bgs_service) : NULL); - zend_string *testing_token = get_global_DD_TRACE_AGENT_TEST_SESSION_TOKEN(); - if (ZSTR_LEN(testing_token)) { - ddtrace_coms_set_test_session_token(ZSTR_VAL(testing_token), ZSTR_LEN(testing_token)); - } - if (bgs_fallback) { - zend_string_release(bgs_service); - } - } -#endif - } -} - -static pthread_once_t dd_activate_once_control = PTHREAD_ONCE_INIT; - -static bool dd_is_cli_autodisabled(const char *arg) { - const char *slashend = strrchr(arg, '/'); - const char *backslashend = strrchr(arg, '\\'); - arg = MAX(MAX(slashend, backslashend) + 1, arg); - return strcmp(arg, "composer") == 0 || strcmp(arg, "composer.phar") == 0; -} - -static void ddtrace_activate(void) { - ddog_reset_logger(); - - zai_hook_rinit(); - zai_interceptor_activate(); - zai_uhook_rinit(); - ddtrace_telemetry_rinit(); - zend_hash_init(&DDTRACE_G(traced_spans), 8, unused, NULL, 0); - zend_hash_init(&DDTRACE_G(tracestate_unknown_dd_keys), 8, unused, NULL, 0); - - if (!ddtrace_disable && ddtrace_has_excluded_module == true) { - ddtrace_disable = 2; - } - - // ZAI config is always set up - pthread_once(&dd_activate_once_control, dd_activate_once); - zai_config_rinit(); - - if (!ddtrace_disable && (get_global_DD_INSTRUMENTATION_TELEMETRY_ENABLED() || get_global_DD_TRACE_SIDECAR_TRACE_SENDER())) { - ddtrace_sidecar_ensure_active(); - } - - ddtrace_sidecar_activate(); - - zend_string *sampling_rules_file = get_DD_SPAN_SAMPLING_RULES_FILE(); - if (ZSTR_LEN(sampling_rules_file) > 0 && !zend_string_equals(get_global_DD_SPAN_SAMPLING_RULES_FILE(), sampling_rules_file)) { - dd_save_sampling_rules_file_config(sampling_rules_file, PHP_INI_USER, PHP_INI_STAGE_RUNTIME); - } - - if (!ddtrace_disable && strcmp(sapi_module.name, "cli") == 0) { - if (zai_config_memoized_entries[DDTRACE_CONFIG_DD_TRACE_CLI_ENABLED].name_index == ZAI_CONFIG_ORIGIN_DEFAULT && SG(request_info).argv && dd_is_cli_autodisabled(SG(request_info).argv[0])) { - zend_string *zero = zend_string_init("0", 1, 0); - zend_alter_ini_entry(zai_config_memoized_entries[DDTRACE_CONFIG_DD_TRACE_CLI_ENABLED].ini_entries[0]->name, zero, - ZEND_INI_USER, ZEND_INI_STAGE_RUNTIME); - zend_string_release(zero); - } - if (!get_DD_TRACE_CLI_ENABLED()) { - ddtrace_disable = 2; - } - } - - if (ddtrace_disable) { - ddtrace_disable_tracing_in_current_request(); - } - -#if PHP_VERSION_ID < 80000 - // This allows us to hook the ZEND_HANDLE_EXCEPTION pseudo opcode - ZEND_VM_SET_OPCODE_HANDLER(EG(exception_op)); - EG(exception_op)->opcode = ZEND_HANDLE_EXCEPTION; -#endif -} - -static void ddtrace_deactivate(void) { -#if PHP_VERSION_ID >= 80000 && PHP_VERSION_ID < 80200 - if (dd_observer_extension_backup != -1) { - zend_observer_fcall_op_array_extension = dd_observer_extension_backup; - dd_observer_extension_backup = -1; - } -#endif -} - -static zend_extension _dd_zend_extension_entry = {"ddtrace", - PHP_DDTRACE_VERSION, - "Datadog", - "https://github.com/DataDog/dd-trace-php", - "Copyright Datadog", - ddtrace_startup, - ddtrace_shutdown, - ddtrace_activate, - ddtrace_deactivate, - NULL, -#if PHP_VERSION_ID < 80000 - zai_interceptor_op_array_pass_two, -#else - NULL, -#endif - NULL, - NULL, - NULL, -#if PHP_VERSION_ID < 80000 - zai_interceptor_op_array_ctor, -#else - NULL, -#endif - zai_hook_unresolve_op_array, - - STANDARD_ZEND_EXTENSION_PROPERTIES}; - -static void php_ddtrace_init_globals(zend_ddtrace_globals *ng) { memset(ng, 0, sizeof(zend_ddtrace_globals)); } - -static PHP_GINIT_FUNCTION(ddtrace) { -#if defined(COMPILE_DL_DDTRACE) && defined(ZTS) - ZEND_TSRMLS_CACHE_UPDATE(); -#endif - php_ddtrace_init_globals(ddtrace_globals); -#if PHP_VERSION_ID < 70100 - zai_vm_interrupt = &ddtrace_globals->zai_vm_interrupt; -#endif -#if ZTS - ddtrace_thread_ginit(); -#endif - ddtrace_globals->sidecar_universal_service_tags_mutex = tsrm_mutex_alloc(); - zai_hook_ginit(); - zend_hash_init(&ddtrace_globals->git_metadata, 8, unused, (dtor_func_t)ddtrace_git_metadata_dtor, 1); -} - -// Rust code will call __cxa_thread_atexit_impl. This is a weak symbol; it's defined by glibc. -// The problem is that calls to __cxa_thread_atexit_impl cause shared libraries to remain referenced until the calling thread terminates. -// However in NTS builds the calling thread is the main thread and thus the shared object (i.e. ddtrace.so) WILL remain loaded. -// This is problematic with e.g. apache which, upon reloading will unload all PHP modules including PHP itself, then reload. -// This prevents us from a) having the weak symbols updated to the new locations and b) having ddtrace updates going live without hard restart. -// Thus, we need to intercept it: define it ourselves so that the linker will force the rust code to call our code here. -// Then we can collect the callbacks and invoke them ourselves right at thread shutdown, i.e. GSHUTDOWN. -#ifdef CXA_THREAD_ATEXIT_WRAPPER -#define CXA_THREAD_ATEXIT_PHP ((void *)0) -#define CXA_THREAD_ATEXIT_UNINITIALIZED ((void *)1) -#define CXA_THREAD_ATEXIT_UNAVAILABLE ((void *)2) - -static int (*glibc__cxa_thread_atexit_impl)(void (*func)(void *), void *obj, void *dso_symbol) = CXA_THREAD_ATEXIT_UNINITIALIZED; -static pthread_key_t dd_cxa_thread_atexit_key; // fallback for sidecar - -struct dd_rust_thread_destructor { - void (*dtor)(void *); - void *obj; - struct dd_rust_thread_destructor *next; -}; -// Use __thread explicitly: ZEND_TLS is empty on NTS builds. -static __thread struct dd_rust_thread_destructor *dd_rust_thread_destructors = NULL; -ZEND_TLS bool dd_is_main_thread = false; - -void dd_run_rust_thread_destructors(void *unused) { - UNUSED(unused); - struct dd_rust_thread_destructor *entry = dd_rust_thread_destructors; - dd_rust_thread_destructors = NULL; // destructors _may_ be invoked multiple times. We need to reset thus. - while (entry) { - struct dd_rust_thread_destructor *cur = entry; - cur->dtor(cur->obj); - entry = entry->next; - free(cur); - } -} - -// Note: this symbol is not public -int __cxa_thread_atexit_impl(void (*func)(void *), void *obj, void *dso_symbol) { - if (glibc__cxa_thread_atexit_impl == CXA_THREAD_ATEXIT_UNINITIALIZED) { - glibc__cxa_thread_atexit_impl = NULL; // DL_FETCH_SYMBOL(RTLD_DEFAULT, "__cxa_thread_atexit_impl"); - if (glibc__cxa_thread_atexit_impl == NULL) { - // no race condition here: logging is initialized in MINIT, at which point only a single thread lives - glibc__cxa_thread_atexit_impl = CXA_THREAD_ATEXIT_UNAVAILABLE; - pthread_key_create(&dd_cxa_thread_atexit_key, dd_run_rust_thread_destructors); - } - } - - if (glibc__cxa_thread_atexit_impl != CXA_THREAD_ATEXIT_PHP && glibc__cxa_thread_atexit_impl != CXA_THREAD_ATEXIT_UNAVAILABLE) { - return glibc__cxa_thread_atexit_impl(func, obj, dso_symbol); - } - - if (glibc__cxa_thread_atexit_impl == CXA_THREAD_ATEXIT_UNAVAILABLE) { - pthread_setspecific(dd_cxa_thread_atexit_key, (void *)0x1); // needs to be non-NULL - } - - struct dd_rust_thread_destructor *entry = malloc(sizeof(struct dd_rust_thread_destructor)); - entry->dtor = func; - entry->obj = obj; - entry->next = dd_rust_thread_destructors; - dd_rust_thread_destructors = entry; - return 0; -} - -static void dd_clean_main_thread_locals() { - dd_run_rust_thread_destructors(NULL); -} -#endif - -static PHP_GSHUTDOWN_FUNCTION(ddtrace) { -#if ZTS - ddtrace_thread_gshutdown(); -#endif - if (ddtrace_globals->agent_config_reader) { - ddog_agent_remote_config_reader_drop(ddtrace_globals->agent_config_reader); - } - if (ddtrace_globals->remote_config_state) { - ddog_shutdown_remote_config(ddtrace_globals->remote_config_state); - } - if (ddtrace_globals->agent_info_reader) { - ddog_drop_agent_info_reader(ddtrace_globals->agent_info_reader); - } - zai_hook_gshutdown(); - if (ddtrace_globals->telemetry_buffer) { - ddog_sidecar_telemetry_buffer_drop(ddtrace_globals->telemetry_buffer); - } - - if (ddtrace_globals->telemetry_cache) { - ddog_sidecar_telemetry_cache_drop(ddtrace_globals->telemetry_cache); - } - - zend_hash_destroy(&ddtrace_globals->git_metadata); - - // Drop the per-thread sidecar transport (thread-lifetime, one per thread). - ddtrace_sidecar_gshutdown(ddtrace_globals); - - tsrm_mutex_free(ddtrace_globals->sidecar_universal_service_tags_mutex); - -#ifdef CXA_THREAD_ATEXIT_WRAPPER - // FrankenPHP calls `ts_free_thread()` in rshutdown - if (!dd_is_main_thread && ddtrace_active_sapi != DATADOG_PHP_SAPI_FRANKENPHP) { - dd_run_rust_thread_destructors(NULL); - } -#endif -} +ZEND_EXTERN_MODULE_GLOBALS(datadog); static void dd_span_event_construct(ddtrace_span_event *event, zend_string *name, zend_long timestamp, zval *attributes) { @@ -898,7 +237,7 @@ ZEND_METHOD(DDTrace_SpanLink, fromHeaders) { return; } - ZVAL_STR(&link->property_trace_id, ddtrace_trace_id_as_hex_string(result.trace_id)); + 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)); array_init(&link->property_attributes); zend_hash_copy(Z_ARR(link->property_attributes), &result.meta_tags, NULL); @@ -1186,9 +525,9 @@ static zval *ddtrace_root_span_data_write(zend_object *object, zend_string *memb } cache_slot = NULL; } else if (zend_string_equals_literal(prop_name, "traceId")) { - span->trace_id = Z_TYPE_P(value) == IS_STRING ? ddtrace_parse_hex_trace_id(Z_STRVAL_P(value), Z_STRLEN_P(value)) : (ddtrace_trace_id){ 0 }; + span->trace_id = Z_TYPE_P(value) == IS_STRING ? ddtrace_parse_hex_trace_id(Z_STRVAL_P(value), Z_STRLEN_P(value)) : (datadog_trace_id){ 0 }; if (!span->trace_id.low && !span->trace_id.high) { - span->trace_id = (ddtrace_trace_id) { + span->trace_id = (datadog_trace_id) { .low = span->span_id, .time = get_DD_TRACE_128_BIT_TRACEID_GENERATION_ENABLED() ? span->start / ZEND_NANO_IN_SEC : 0, }; @@ -1215,895 +554,216 @@ static zval *ddtrace_root_span_data_write(zend_object *object, zend_string *memb cache_slot = NULL; } -#if PHP_VERSION_ID >= 70400 - zval *ret = ddtrace_span_data_readonly(object, member, value, cache_slot); -#else - ddtrace_span_data_readonly(object, member, value, cache_slot); -#endif - if (root_span_data_changed) { - ddtrace_sidecar_submit_root_span_data(); - } -#if PHP_VERSION_ID >= 70400 - return ret; -#endif -} - -#if PHP_VERSION_ID < 80000 -static zval *ddtrace_span_stack_read_property(zval *object, zval *member, int type, void **cache_slot, zval *rv) { - zend_string *prop_name = Z_TYPE_P(member) == IS_STRING ? Z_STR_P(member) : ZSTR_EMPTY_ALLOC(); - ddtrace_span_stack *stack = (ddtrace_span_stack *)Z_OBJ_P(object); -#else -static zval *ddtrace_span_stack_read_property(zend_object *object, zend_string *member, int type, void **cache_slot, zval *rv) { - zend_string *prop_name = member; - ddtrace_span_stack *stack = (ddtrace_span_stack *)object; -#endif - if ((type == BP_VAR_W || type == BP_VAR_RW || type == BP_VAR_UNSET) - && zend_string_equals_literal(prop_name, "active")) { - ZVAL_COPY(rv, &stack->property_active); - return rv; - } - return zend_std_read_property(object, member, type, cache_slot, rv); -} - -#if PHP_VERSION_ID < 80000 -static zval *ddtrace_span_stack_get_property_ptr_ptr(zval *object, zval *member, int type, void **cache_slot) { - zend_string *prop_name = Z_TYPE_P(member) == IS_STRING ? Z_STR_P(member) : ZSTR_EMPTY_ALLOC(); -#else -static zval *ddtrace_span_stack_get_property_ptr_ptr(zend_object *object, zend_string *member, int type, void **cache_slot) { - zend_string *prop_name = member; -#endif - if ((type == BP_VAR_W || type == BP_VAR_RW || type == BP_VAR_UNSET) - && zend_string_equals_literal(prop_name, "active")) { - return NULL; // prevent cache fill; read_property handles the copy - } - return zend_std_get_property_ptr_ptr(object, member, type, cache_slot); -} - -#if PHP_VERSION_ID < 80000 -#if PHP_VERSION_ID >= 70400 -static zval *ddtrace_span_stack_readonly(zval *object, zval *member, zval *value, void **cache_slot) { -#else -static void ddtrace_span_stack_readonly(zval *object, zval *member, zval *value, void **cache_slot) { -#endif - zend_object *obj = Z_OBJ_P(object); - zend_string *prop_name = Z_TYPE_P(member) == IS_STRING ? Z_STR_P(member) : ZSTR_EMPTY_ALLOC(); -#else -static zval *ddtrace_span_stack_readonly(zend_object *object, zend_string *member, zval *value, void **cache_slot) { - zend_object *obj = object; - zend_string *prop_name = member; -#endif - if (zend_string_equals_literal(prop_name, "parent")) { - zend_throw_error(zend_ce_error, "Cannot modify readonly property %s::$%s", ZSTR_VAL(obj->ce->name), ZSTR_VAL(prop_name)); -#if PHP_VERSION_ID >= 70400 - return &EG(uninitialized_zval); -#else - return; -#endif - } - -#if PHP_VERSION_ID >= 70400 - return zend_std_write_property(object, member, value, cache_slot); -#else - zend_std_write_property(object, member, value, cache_slot); -#endif -} - -PHP_METHOD(DDTrace_SpanData, getDuration) { - ddtrace_span_data *span = OBJ_SPANDATA(Z_OBJ_P(ZEND_THIS)); - RETURN_LONG(span->duration); -} - -PHP_METHOD(DDTrace_SpanData, getStartTime) { - ddtrace_span_data *span = OBJ_SPANDATA(Z_OBJ_P(ZEND_THIS)); - RETURN_LONG(span->start); -} - -PHP_METHOD(DDTrace_SpanData, getLink) { - ddtrace_span_data *span = OBJ_SPANDATA(Z_OBJ_P(ZEND_THIS)); - - span->flags |= DDTRACE_SPAN_FLAG_NOT_DROPPABLE; - - zval fci_zv; - object_init_ex(&fci_zv, ddtrace_ce_span_link); - ddtrace_span_link *link = (ddtrace_span_link *)Z_OBJ_P(&fci_zv); - - ZVAL_STR(&link->property_trace_id, ddtrace_trace_id_as_hex_string(span->root ? span->root->trace_id : (ddtrace_trace_id){ .low = span->span_id, .high = 0 })); - ZVAL_STR(&link->property_span_id, ddtrace_span_id_as_hex_string(span->span_id)); - - RETURN_OBJ(Z_OBJ(fci_zv)); -} - -PHP_METHOD(DDTrace_SpanData, hexId) { - ddtrace_span_data *span = OBJ_SPANDATA(Z_OBJ_P(ZEND_THIS)); - RETURN_STR(ddtrace_span_id_as_hex_string(span->span_id)); -} - -static void dd_register_span_data_ce(void) { - ddtrace_ce_span_data = register_class_DDTrace_SpanData(); - ddtrace_ce_span_data->create_object = ddtrace_span_data_create; - - memcpy(&ddtrace_span_data_handlers, &std_object_handlers, sizeof(zend_object_handlers)); - ddtrace_span_data_handlers.offset = XtOffsetOf(ddtrace_span_data, std); - ddtrace_span_data_handlers.clone_obj = ddtrace_span_data_clone_obj; - 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_ce_inferred_span_data = register_class_DDTrace_InferredSpanData(ddtrace_ce_span_data); - ddtrace_ce_inferred_span_data->create_object = ddtrace_inferred_span_data_create; - - memcpy(&ddtrace_inferred_span_data_handlers, &ddtrace_span_data_handlers, sizeof(zend_object_handlers)); - ddtrace_inferred_span_data_handlers.offset = XtOffsetOf(ddtrace_inferred_span_data, std); - ddtrace_inferred_span_data_handlers.clone_obj = ddtrace_inferred_span_data_clone_obj; - - - ddtrace_ce_root_span_data = register_class_DDTrace_RootSpanData(ddtrace_ce_span_data); - ddtrace_ce_root_span_data->create_object = ddtrace_root_span_data_create; - -#if PHP_VERSION_ID >= 80000 && PHP_VERSION_ID < 80100 - // Work around wrong reference source for typed internal properties by preventing duplication of them - // php -d extension=zend_test -r '$c = new _ZendTestChildClass; $i = &$c->intProp;' - // php: /usr/local/src/php/Zend/zend_execute.c:3390: zend_ref_del_type_source: Assertion `source_list->ptr == prop' failed. - zend_hash_init(&dd_root_span_data_duplicated_properties_table, zend_hash_num_elements(&ddtrace_ce_span_data->properties_info), NULL, NULL, true); - for (uint32_t i = 0; i < zend_hash_num_elements(&ddtrace_ce_span_data->properties_info); ++i) { - Bucket *bucket = &ddtrace_ce_root_span_data->properties_info.arData[i]; - zend_hash_add_ptr(&dd_root_span_data_duplicated_properties_table, bucket->key, Z_PTR(bucket->val)); - Z_PTR(bucket->val) = ddtrace_ce_root_span_data->properties_info_table[i] = Z_PTR(ddtrace_ce_span_data->properties_info.arData[i].val); - } -#endif - - memcpy(&ddtrace_root_span_data_handlers, &ddtrace_span_data_handlers, sizeof(zend_object_handlers)); - ddtrace_root_span_data_handlers.offset = XtOffsetOf(ddtrace_root_span_data, std); - ddtrace_root_span_data_handlers.clone_obj = ddtrace_root_span_data_clone_obj; - ddtrace_root_span_data_handlers.write_property = ddtrace_root_span_data_write; - - ddtrace_ce_span_stack = register_class_DDTrace_SpanStack(); - ddtrace_ce_span_stack->create_object = ddtrace_span_stack_create; - - memcpy(&ddtrace_span_stack_handlers, &std_object_handlers, sizeof(zend_object_handlers)); - ddtrace_span_stack_handlers.clone_obj = ddtrace_span_stack_clone_obj; - ddtrace_span_stack_handlers.dtor_obj = ddtrace_span_stack_dtor_obj; - ddtrace_span_stack_handlers.read_property = ddtrace_span_stack_read_property; - ddtrace_span_stack_handlers.get_property_ptr_ptr = ddtrace_span_stack_get_property_ptr_ptr; - ddtrace_span_stack_handlers.write_property = ddtrace_span_stack_readonly; - -} - -/* DDTrace\FatalError */ -zend_class_entry *ddtrace_ce_fatal_error; - -static void dd_register_fatal_error_ce(void) { - zend_class_entry ce; - INIT_NS_CLASS_ENTRY(ce, "DDTrace", "FatalError", NULL); - ddtrace_ce_fatal_error = zend_register_internal_class_ex(&ce, zend_ce_exception); -} - -zend_class_entry *ddtrace_ce_integration; -zend_class_entry *ddtrace_ce_git_metadata; -zend_object_handlers ddtrace_git_metadata_handlers; - -static zend_object *ddtrace_git_metadata_create(zend_class_entry *class_type) { - zend_object *object = zend_objects_new(class_type); - object_properties_init(object, class_type); - object->handlers = &ddtrace_git_metadata_handlers; - return object; -} - -static void ddtrace_free_obj_wrapper(zend_object *object) { - zend_object_std_dtor(object); -} - -static bool dd_is_compatible_sapi() { - switch (ddtrace_active_sapi) { - case DATADOG_PHP_SAPI_APACHE2HANDLER: - case DATADOG_PHP_SAPI_CGI_FCGI: - case DATADOG_PHP_SAPI_CLI: - case DATADOG_PHP_SAPI_CLI_SERVER: - case DATADOG_PHP_SAPI_FPM_FCGI: - case DATADOG_PHP_SAPI_FRANKENPHP: - case DATADOG_PHP_SAPI_TEA: - return true; - - default: - return false; - } -} - -static void dd_disable_if_incompatible_sapi_detected(void) { - if (UNEXPECTED(!dd_is_compatible_sapi())) { - LOG(WARN, "Incompatible SAPI detected '%s'; disabling ddtrace", sapi_module.name); - ddtrace_disable = 1; - } -} - -#if PHP_VERSION_ID < 80500 -zend_string *ddtrace_known_strings[ZEND_STR__LAST]; -void ddtrace_init_known_strings(void) { -#if PHP_VERSION_ID < 80500 -#undef ZEND_STR_PARENT - ddtrace_known_strings[ZEND_STR_PARENT] = zend_string_init_interned(ZEND_STRL("parent"), 1); -#endif -#if PHP_VERSION_ID < 70300 -#undef ZEND_STR_NAME - ddtrace_known_strings[ZEND_STR_NAME] = zend_string_init_interned(ZEND_STRL("name"), 1); -#endif -#if PHP_VERSION_ID < 70200 -#undef ZEND_STR_RESOURCE - ddtrace_known_strings[ZEND_STR_RESOURCE] = zend_string_init_interned(ZEND_STRL("resource"), 1); -#endif -#if PHP_VERSION_ID < 70100 - ddtrace_known_strings[ZEND_STR_TRACE] = zend_string_init_interned(ZEND_STRL("trace"), 1); - ddtrace_known_strings[ZEND_STR_LINE] = zend_string_init_interned(ZEND_STRL("line"), 1); - ddtrace_known_strings[ZEND_STR_FILE] = zend_string_init_interned(ZEND_STRL("file"), 1); - ddtrace_known_strings[ZEND_STR_MESSAGE] = zend_string_init_interned(ZEND_STRL("message"), 1); - ddtrace_known_strings[ZEND_STR_CODE] = zend_string_init_interned(ZEND_STRL("code"), 1); - ddtrace_known_strings[ZEND_STR_TYPE] = zend_string_init_interned(ZEND_STRL("type"), 1); - ddtrace_known_strings[ZEND_STR_FUNCTION] = zend_string_init_interned(ZEND_STRL("function"), 1); - ddtrace_known_strings[ZEND_STR_OBJECT] = zend_string_init_interned(ZEND_STRL("object"), 1); - ddtrace_known_strings[ZEND_STR_CLASS] = zend_string_init_interned(ZEND_STRL("class"), 1); - ddtrace_known_strings[ZEND_STR_OBJECT_OPERATOR] = zend_string_init_interned(ZEND_STRL("->"), 1); - ddtrace_known_strings[ZEND_STR_PAAMAYIM_NEKUDOTAYIM] = zend_string_init_interned(ZEND_STRL("::"), 1); - ddtrace_known_strings[ZEND_STR_ARGS] = zend_string_init_interned(ZEND_STRL("args"), 1); - ddtrace_known_strings[ZEND_STR_UNKNOWN] = zend_string_init_interned(ZEND_STRL("unknown"), 1); - ddtrace_known_strings[ZEND_STR_EVAL] = zend_string_init_interned(ZEND_STRL("eval"), 1); - ddtrace_known_strings[ZEND_STR_INCLUDE] = zend_string_init_interned(ZEND_STRL("include"), 1); - ddtrace_known_strings[ZEND_STR_REQUIRE] = zend_string_init_interned(ZEND_STRL("require"), 1); - ddtrace_known_strings[ZEND_STR_INCLUDE_ONCE] = zend_string_init_interned(ZEND_STRL("include_once"), 1); - ddtrace_known_strings[ZEND_STR_REQUIRE_ONCE] = zend_string_init_interned(ZEND_STRL("require_once"), 1); - ddtrace_known_strings[ZEND_STR_PREVIOUS] = zend_string_init_interned(ZEND_STRL("previous"), 1); -#endif -} -#endif - -static PHP_MINIT_FUNCTION(ddtrace) { - UNUSED(type); - zval *php_version = zend_get_constant_str(ZEND_STRL("PHP_VERSION")); - if (php_version && Z_TYPE_P(php_version) == IS_STRING) { - php_version_rt = (ddog_CharSlice){Z_STRVAL_P(php_version), Z_STRLEN_P(php_version)}; - } else { - zend_error(E_CORE_WARNING, "Failed to get PHP_VERSION constant"); - return FAILURE; - } - - ddog_init_span_func((void *)zend_string_release, (void *)zend_string_addref, ddtrace_zend_string_init); - - ddtrace_active_sapi = datadog_php_sapi_from_name(datadog_php_string_view_from_cstr(sapi_module.name)); - -#ifdef CXA_THREAD_ATEXIT_WRAPPER - // FrankenPHP calls `ts_free_thread()` in rshutdown - if (ddtrace_active_sapi != DATADOG_PHP_SAPI_FRANKENPHP) { - dd_is_main_thread = true; - glibc__cxa_thread_atexit_impl = CXA_THREAD_ATEXIT_PHP; - atexit(dd_clean_main_thread_locals); - } -#endif - - // Reset on every minit for `apachectl graceful`. - dd_activate_once_control = (pthread_once_t)PTHREAD_ONCE_INIT; - -#if PHP_VERSION_ID < 80500 - ddtrace_init_known_strings(); -#endif - - zai_hook_minit(); - zai_uhook_minit(module_number); -#if PHP_VERSION_ID >= 80000 - zai_interceptor_minit(); -#endif -#if ZAI_JIT_BLACKLIST_ACTIVE - zai_jit_minit(); -#endif - -#if PHP_VERSION_ID < 70300 || (defined(_WIN32) && PHP_VERSION_ID >= 80300 && PHP_VERSION_ID < 80400) - ddtrace_startup_hrtime(); -#endif - - register_ddtrace_symbols(module_number); - REGISTER_INI_ENTRIES(); - - zval *ddtrace_module_zv = zend_hash_str_find(&module_registry, ZEND_STRL("ddtrace")); - if (ddtrace_module_zv) { - ddtrace_module = Z_PTR_P(ddtrace_module_zv); - } - - dd_main_pid = getpid(); - ddtrace_generate_session_id(); - - // Make sure it's available for appsec, before any early returns - dd_ip_extraction_startup(); - - // config initialization needs to be at the top - // This also initialiyzed logging, so no logs may be emitted before this. - ddtrace_log_init(); - if (!ddtrace_config_minit(module_number)) { - return FAILURE; - } - if (ZSTR_LEN(get_global_DD_SPAN_SAMPLING_RULES_FILE()) > 0) { - dd_save_sampling_rules_file_config(get_global_DD_SPAN_SAMPLING_RULES_FILE(), PHP_INI_SYSTEM, PHP_INI_STAGE_STARTUP); - } - - dd_disable_if_incompatible_sapi_detected(); - atomic_init(&ddtrace_warn_legacy_api, 1); - - /* This allows an extension (e.g. extension=ddtrace.so) to have zend_engine - * hooks too, but not loadable as zend_extension=ddtrace.so. - * See http://www.phpinternalsbook.com/php7/extensions_design/zend_extensions.html#hybrid-extensions - * {{{ */ - zend_register_extension(&_dd_zend_extension_entry, ddtrace_module_entry.handle); - // The original entry is copied into the module registry when the module is - // registered, so we search the module registry to find the right - // zend_module_entry to modify. - zend_module_entry *mod_ptr = - zend_hash_str_find_ptr(&module_registry, PHP_DDTRACE_EXTNAME, sizeof(PHP_DDTRACE_EXTNAME) - 1); - if (mod_ptr == NULL) { - // This shouldn't happen, possibly a bug if it does. - zend_error(E_CORE_WARNING, - "Failed to find ddtrace extension in " - "registered modules. Please open a bug report."); - - return FAILURE; - } - mod_ptr->handle = NULL; - /* }}} */ - - if (ddtrace_disable) { - return SUCCESS; - } - -#if PHP_VERSION_ID >= 80100 - ddtrace_setup_fiber_observers(); -#endif - -#ifndef _WIN32 - ddtrace_set_coredumpfilter(); -#endif - - ddtrace_initialize_span_sampling_limiter(); - ddtrace_limiter_create(); - ddtrace_standalone_limiter_create(); - - ddtrace_log_minit(); - -#ifndef _WIN32 - /* Snapshot proxy-related env vars once at startup to avoid getenv() - * from the background writer thread inside libcurl. */ - ddtrace_coms_minit_proxy_env(); - ddtrace_dogstatsd_client_minit(); -#endif - - ddshared_minit(); - ddtrace_autoload_minit(); - ddtrace_sidecar_minit(); - - dd_register_span_data_ce(); - dd_register_fatal_error_ce(); - ddtrace_ce_integration = register_class_DDTrace_Integration(); - 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_exception_span_event = register_class_DDTrace_ExceptionSpanEvent(ddtrace_ce_span_event); - ddtrace_ce_git_metadata = register_class_DDTrace_GitMetadata(); - ddtrace_ce_git_metadata->create_object = ddtrace_git_metadata_create; - memcpy(&ddtrace_git_metadata_handlers, &std_object_handlers, sizeof(zend_object_handlers)); - // We need a free_obj wrapper as zend_objects_store_free_object_storage will skip freeing of classes with the default free_obj handler when fast_shutdown is active. This will mess with our refcount and leak cached git metadata. - ddtrace_git_metadata_handlers.free_obj = ddtrace_free_obj_wrapper; - - ddtrace_engine_hooks_minit(); - ddtrace_init_proxy_info_map(); - - ddtrace_integrations_minit(); - ddtrace_serializer_startup(); - - ddtrace_live_debugger_minit(); - ddtrace_minit_remote_config(); - ddtrace_trace_source_minit(); - -#ifndef _WIN32 - ddtrace_signals_minit(); -#endif - - return SUCCESS; -} - -static PHP_MSHUTDOWN_FUNCTION(ddtrace) { - UNUSED(module_number, type); - - zai_uhook_mshutdown(); - zai_hook_mshutdown(); - - UNREGISTER_INI_ENTRIES(); - - if (ddtrace_disable == 1) { - zai_config_mshutdown(); - zai_json_shutdown_bindings(); - return SUCCESS; - } - - ddtrace_mshutdown_remote_config(); - - if (DDTRACE_G(agent_rate_by_service)) { - zai_json_release_persistent_array(DDTRACE_G(agent_rate_by_service)); - DDTRACE_G(agent_rate_by_service) = NULL; - } - - ddtrace_integrations_mshutdown(); - -#ifndef _WIN32 - ddtrace_signals_mshutdown(); - - if (!get_global_DD_TRACE_SIDECAR_TRACE_SENDER()) { - ddtrace_coms_mshutdown(); - if (ddtrace_coms_flush_shutdown_writer_synchronous()) { - ddtrace_coms_curl_shutdown(); - } - /* All writer threads and curl handles are gone at this point, so - * it is safe to free the cached proxy env strings for ASan. */ - ddtrace_coms_mshutdown_proxy_env(); - } else /* ! part of the if outside the ifdef */ -#endif - if (get_global_DD_TRACE_FORCE_FLUSH_ON_SHUTDOWN() && DDTRACE_G(sidecar)) { - ddog_sidecar_flush(&DDTRACE_G(sidecar), (ddog_SidecarFlushOptions){.traces_and_stats = true, .telemetry = true}); - } - - ddtrace_log_mshutdown(); - - ddtrace_engine_hooks_mshutdown(); - ddtrace_shutdown_proxy_info_map(); - - ddtrace_shutdown_span_sampling_limiter(); - ddtrace_limiter_destroy(); - ddtrace_standalone_limiter_destroy(); - zai_config_mshutdown(); - zai_json_shutdown_bindings(); - - ddtrace_user_req_shutdown(); - - ddtrace_sidecar_shutdown(); - - ddtrace_process_tags_mshutdown(); - -#if PHP_VERSION_ID >= 80000 && PHP_VERSION_ID < 80100 - // See dd_register_span_data_ce for explanation - zend_string *key; - void *prop_info; - ZEND_HASH_FOREACH_STR_KEY_PTR(&dd_root_span_data_duplicated_properties_table, key, prop_info) { - ZVAL_PTR(zend_hash_find(&ddtrace_ce_root_span_data->properties_info, key), prop_info); // no update to avoid dtor - } ZEND_HASH_FOREACH_END(); -#endif - - return SUCCESS; -} - -static bool dd_rinit_once_done = false; - -static void dd_rinit_once(void) { - /* The env vars are memoized on MINIT before the SAPI env vars are available. - * We use the first RINIT to bust the env var cache and use the SAPI env vars. - * TODO Audit/remove config usages before RINIT and move config init to RINIT. - */ - ddtrace_startup_logging_first_rinit(); - - // Collect process tags now that script path is available - if (get_global_DD_EXPERIMENTAL_PROPAGATE_PROCESS_TAGS_ENABLED()) { - ddtrace_process_tags_first_rinit(); - ddtrace_sidecar_update_process_tags(); - } - - // Uses config, cannot run earlier -#ifndef _WIN32 - ddtrace_signals_first_rinit(); - if (!get_global_DD_TRACE_SIDECAR_TRACE_SENDER()) { - ddtrace_coms_init_and_start_writer(); - } -#else - if (get_DD_INSTRUMENTATION_TELEMETRY_ENABLED() && get_DD_CRASHTRACKING_ENABLED()) { - init_crash_tracking(); - } -#endif - - dd_rinit_once_done = true; -} - -static pthread_once_t dd_rinit_once_control = PTHREAD_ONCE_INIT; - -static void dd_initialize_request(void) { - DDTRACE_G(distributed_trace_id) = (ddtrace_trace_id){0}; - DDTRACE_G(distributed_parent_trace_id) = 0; - DDTRACE_G(additional_global_tags) = zend_new_array(0); - DDTRACE_G(default_priority_sampling) = DDTRACE_PRIORITY_SAMPLING_UNKNOWN; - DDTRACE_G(propagated_priority_sampling) = DDTRACE_PRIORITY_SAMPLING_UNSET; - DDTRACE_G(inferred_span_created) = false; - zend_hash_init(&DDTRACE_G(root_span_tags_preset), 8, unused, ZVAL_PTR_DTOR, 0); - zend_hash_init(&DDTRACE_G(propagated_root_span_tags), 8, unused, ZVAL_PTR_DTOR, 0); - zend_hash_init(&DDTRACE_G(tracestate_unknown_dd_keys), 8, unused, ZVAL_PTR_DTOR, 0); - zend_hash_init(&DDTRACE_G(baggage), 8, unused, ZVAL_PTR_DTOR, 0); - - // Do after env check, so that RC data is not updated before RC init - DDTRACE_G(request_initialized) = true; - - if (!DDTRACE_G(remote_config_state) && ddtrace_endpoint) { - DDTRACE_G(remote_config_state) = ddog_init_remote_config_state(ddtrace_endpoint, get_DD_DYNAMIC_INSTRUMENTATION_ENABLED()); - } - - // We need to init RC for the sidecar to write to it immediately - if (DDTRACE_G(remote_config_state)) { - ddtrace_rinit_remote_config(); - } - - ddtrace_sidecar_rinit(); - ddtrace_asm_event_rinit(); - - // Things that should only run on the first RINIT after each minit. - pthread_once(&dd_rinit_once_control, dd_rinit_once); - - if (!DDTRACE_G(agent_config_reader) && !get_global_DD_TRACE_IGNORE_AGENT_SAMPLING_RATES()) { - if (get_global_DD_TRACE_SIDECAR_TRACE_SENDER()) { - if (ddtrace_endpoint) { - DDTRACE_G(agent_config_reader) = ddog_agent_remote_config_reader_for_endpoint(ddtrace_endpoint); - } -#ifndef _WIN32 - } else if (ddtrace_coms_agent_config_handle) { - ddog_agent_remote_config_reader_for_anon_shm(ddtrace_coms_agent_config_handle, &DDTRACE_G(agent_config_reader)); -#endif - } - } - - ddtrace_internal_handlers_rinit(); - - ddtrace_log_rinit(PG(error_log)); - - ddtrace_seed_prng(); - ddtrace_init_span_stacks(); - -#ifndef _WIN32 - ddtrace_dogstatsd_client_rinit(); - if (!get_global_DD_TRACE_SIDECAR_TRACE_SENDER()) { - ddtrace_coms_on_pid_change(); - } -#endif - - ddtrace_agent_info_rinit(); - - // Single combined read: applies env, container-hash, and concentrator config. - ddtrace_apply_agent_info(); - - // Reset compile time after request init hook has compiled - ddtrace_compile_time_reset(); - - dd_prepare_for_new_trace(); - - ddtrace_distributed_tracing_result distributed_result = ddtrace_read_distributed_tracing_ids(ddtrace_read_zai_header, NULL); - ddtrace_apply_distributed_tracing_result(&distributed_result, NULL); - - if (get_DD_TRACE_GENERATE_ROOT_SPAN()) { - ddtrace_push_root_span(); +#if PHP_VERSION_ID >= 70400 + zval *ret = ddtrace_span_data_readonly(object, member, value, cache_slot); +#else + ddtrace_span_data_readonly(object, member, value, cache_slot); +#endif + if (root_span_data_changed) { + datadog_sidecar_submit_root_span_data(); } -} - -static PHP_RINIT_FUNCTION(ddtrace) { - UNUSED(module_number, type); - -#if PHP_VERSION_ID < 80000 || (PHP_VERSION_ID >= 80400 && PHP_VERSION_ID < 80500) - zai_interceptor_rinit(); +#if PHP_VERSION_ID >= 70400 + return ret; #endif +} - ddtrace_weak_resources_rinit(); - - if (!ddtrace_disable) { - // With internal functions also being hookable, they must not be hooked before the CG(map_ptr_base) is zeroed - zai_hook_activate(); - DDTRACE_G(active_stack) = NULL; // This should not be necessary, but somehow sometimes it may be a leftover from a previous request. - DDTRACE_G(active_stack) = ddtrace_init_root_span_stack(); #if PHP_VERSION_ID < 80000 - ddtrace_autoload_rinit(); +static zval *ddtrace_span_stack_read_property(zval *object, zval *member, int type, void **cache_slot, zval *rv) { + zend_string *prop_name = Z_TYPE_P(member) == IS_STRING ? Z_STR_P(member) : ZSTR_EMPTY_ALLOC(); + ddtrace_span_stack *stack = (ddtrace_span_stack *)Z_OBJ_P(object); +#else +static zval *ddtrace_span_stack_read_property(zend_object *object, zend_string *member, int type, void **cache_slot, zval *rv) { + zend_string *prop_name = member; + ddtrace_span_stack *stack = (ddtrace_span_stack *)object; #endif + if ((type == BP_VAR_W || type == BP_VAR_RW || type == BP_VAR_UNSET) + && zend_string_equals_literal(prop_name, "active")) { + ZVAL_COPY(rv, &stack->property_active); + return rv; } - - if (get_DD_TRACE_ENABLED()) { - dd_initialize_request(); - } - - return SUCCESS; + return zend_std_read_property(object, member, type, cache_slot, rv); } -static void dd_clean_globals(void) { - zend_array_destroy(DDTRACE_G(additional_global_tags)); - zend_hash_destroy(&DDTRACE_G(root_span_tags_preset)); - zend_hash_destroy(&DDTRACE_G(tracestate_unknown_dd_keys)); - zend_hash_destroy(&DDTRACE_G(propagated_root_span_tags)); - zend_hash_destroy(&DDTRACE_G(baggage)); - - if (DDTRACE_G(curl_multi_injecting_spans)) { - if (GC_DELREF(DDTRACE_G(curl_multi_injecting_spans)) == 0) { - rc_dtor_func((zend_refcounted *) DDTRACE_G(curl_multi_injecting_spans)); - } - DDTRACE_G(curl_multi_injecting_spans) = NULL; - } - - if (DDTRACE_G(dd_origin)) { - zend_string_release(DDTRACE_G(dd_origin)); - DDTRACE_G(dd_origin) = NULL; - } - - if (DDTRACE_G(tracestate)) { - zend_string_release(DDTRACE_G(tracestate)); - DDTRACE_G(tracestate) = NULL; - } - - ddtrace_internal_handlers_rshutdown(); -#ifndef _WIN32 - ddtrace_dogstatsd_client_rshutdown(); +#if PHP_VERSION_ID < 80000 +static zval *ddtrace_span_stack_get_property_ptr_ptr(zval *object, zval *member, int type, void **cache_slot) { + zend_string *prop_name = Z_TYPE_P(member) == IS_STRING ? Z_STR_P(member) : ZSTR_EMPTY_ALLOC(); +#else +static zval *ddtrace_span_stack_get_property_ptr_ptr(zend_object *object, zend_string *member, int type, void **cache_slot) { + zend_string *prop_name = member; #endif - - ddtrace_free_span_stacks(false); -#ifndef _WIN32 - if (!get_global_DD_TRACE_SIDECAR_TRACE_SENDER()) { - ddtrace_coms_rshutdown(); + if ((type == BP_VAR_W || type == BP_VAR_RW || type == BP_VAR_UNSET) + && zend_string_equals_literal(prop_name, "active")) { + return NULL; // prevent cache fill; read_property handles the copy } -#endif + return zend_std_get_property_ptr_ptr(object, member, type, cache_slot); } -static void dd_shutdown_hooks_and_observer(bool fast_shutdown) { - zai_hook_clean(fast_shutdown); - -#if PHP_VERSION_ID >= 80000 && PHP_VERSION_ID < 80200 -#if PHP_VERSION_ID < 80100 -#define RUN_TIME_CACHE_OBSERVER_PATCH_VERSION 18 +#if PHP_VERSION_ID < 80000 +#if PHP_VERSION_ID >= 70400 +static zval *ddtrace_span_stack_readonly(zval *object, zval *member, zval *value, void **cache_slot) { #else -#define RUN_TIME_CACHE_OBSERVER_PATCH_VERSION 4 +static void ddtrace_span_stack_readonly(zval *object, zval *member, zval *value, void **cache_slot) { +#endif + zend_object *obj = Z_OBJ_P(object); + zend_string *prop_name = Z_TYPE_P(member) == IS_STRING ? Z_STR_P(member) : ZSTR_EMPTY_ALLOC(); +#else +static zval *ddtrace_span_stack_readonly(zend_object *object, zend_string *member, zval *value, void **cache_slot) { + zend_object *obj = object; + zend_string *prop_name = member; +#endif + if (zend_string_equals_literal(prop_name, "parent")) { + zend_throw_error(zend_ce_error, "Cannot modify readonly property %s::$%s", ZSTR_VAL(obj->ce->name), ZSTR_VAL(prop_name)); +#if PHP_VERSION_ID >= 70400 + return &EG(uninitialized_zval); +#else + return; #endif - - zend_long patch_version = Z_LVAL_P(zend_get_constant_str(ZEND_STRL("PHP_RELEASE_VERSION"))); - if (patch_version < RUN_TIME_CACHE_OBSERVER_PATCH_VERSION) { - // Just do it if we think to be the only observer ... don't want to break other functionalities - if (!dd_has_other_observers) { - // We really should not have to do it. But there is a bug before PHP 8.0.18 and 8.1.4 respectively, causing observer fcall info being freed before stream shutdown (which may still invoke user code) - dd_observer_extension_backup = zend_observer_fcall_op_array_extension; - zend_observer_fcall_op_array_extension = -1; - } } + +#if PHP_VERSION_ID >= 70400 + return zend_std_write_property(object, member, value, cache_slot); +#else + zend_std_write_property(object, member, value, cache_slot); #endif } -void dd_force_shutdown_tracing(bool fast_shutdown) { - DDTRACE_G(in_shutdown) = true; - - zend_try { - ddtrace_close_all_open_spans(true); // All remaining userland spans (and root span) - } zend_catch { - LOG(WARN, "Failed to close remaining spans due to bailout"); - } zend_end_try(); - - zend_try { - if (ddtrace_flush_tracer(false, true, fast_shutdown) == FAILURE) { - LOG(WARN, "Unable to flush the tracer"); - } - } zend_catch { - LOG(WARN, "Unable to flush the tracer due to bailout"); - } zend_end_try(); - - // we here need to disable the tracer, so that further hooks do not trigger - ddtrace_disable_tracing_in_current_request(); // implicitly calling dd_clean_globals - - // The hooks shall not be reset, just disabled at runtime. - dd_shutdown_hooks_and_observer(fast_shutdown); - - DDTRACE_G(in_shutdown) = false; +PHP_METHOD(DDTrace_SpanData, getDuration) { + ddtrace_span_data *span = OBJ_SPANDATA(Z_OBJ_P(ZEND_THIS)); + RETURN_LONG(span->duration); } -static void dd_finalize_sidecar_lifecycle(bool clear_id) { - if (DDTRACE_G(request_initialized)) { - ddtrace_sidecar_finalize(clear_id); - } +PHP_METHOD(DDTrace_SpanData, getStartTime) { + ddtrace_span_data *span = OBJ_SPANDATA(Z_OBJ_P(ZEND_THIS)); + RETURN_LONG(span->start); } -static PHP_RSHUTDOWN_FUNCTION(ddtrace) { - UNUSED(module_number, type); - - // We deliberately select to not free some data structures, as to avoid the overhead of freeing them. - // Just proper destruction can have significant and easily measurable overhead on applications. - // Prior to PHP 7.2 fast shutdown was an opcache only feature -#if ZEND_DEBUG || PHP_VERSION_ID < 70200 - bool fast_shutdown = 0; -#elif defined(__SANITIZE_ADDRESS__) - char *force_fast_shutdown = getenv("ZEND_ASAN_FORCE_FAST_SHUTDOWN"); - bool fast_shutdown = ( - is_zend_mm() - || (force_fast_shutdown && ZEND_ATOL(force_fast_shutdown)) - ) && !EG(full_tables_cleanup); -#else - bool fast_shutdown = is_zend_mm() && !EG(full_tables_cleanup); -#endif +PHP_METHOD(DDTrace_SpanData, getLink) { + ddtrace_span_data *span = OBJ_SPANDATA(Z_OBJ_P(ZEND_THIS)); - zend_hash_destroy(&DDTRACE_G(traced_spans)); + span->flags |= DDTRACE_SPAN_FLAG_NOT_DROPPABLE; - // this needs to be done before dropping the spans - // run unconditionally because ddtrace may've been disabled mid-request - ddtrace_exec_handlers_rshutdown(); + zval fci_zv; + object_init_ex(&fci_zv, ddtrace_ce_span_link); + ddtrace_span_link *link = (ddtrace_span_link *)Z_OBJ_P(&fci_zv); - if (get_DD_TRACE_ENABLED()) { - dd_force_shutdown_tracing(fast_shutdown); - } else if (!ddtrace_disable) { - dd_shutdown_hooks_and_observer(fast_shutdown); - } + ZVAL_STR(&link->property_trace_id, datadog_trace_id_as_hex_string(span->root ? span->root->trace_id : (datadog_trace_id){ .low = span->span_id, .high = 0 })); + ZVAL_STR(&link->property_span_id, ddtrace_span_id_as_hex_string(span->span_id)); - if (DDTRACE_G(remote_config_state)) { - ddtrace_rshutdown_remote_config(); - } + RETURN_OBJ(Z_OBJ(fci_zv)); +} - if (!ddtrace_disable) { - ddtrace_autoload_rshutdown(); +PHP_METHOD(DDTrace_SpanData, hexId) { + ddtrace_span_data *span = OBJ_SPANDATA(Z_OBJ_P(ZEND_THIS)); + RETURN_STR(ddtrace_span_id_as_hex_string(span->span_id)); +} - if (!fast_shutdown) { - OBJ_RELEASE(&DDTRACE_G(active_stack)->std); - } - DDTRACE_G(active_stack) = NULL; - } +static void dd_register_span_data_ce(void) { + ddtrace_ce_span_data = register_class_DDTrace_SpanData(); + ddtrace_ce_span_data->create_object = ddtrace_span_data_create; - dd_finalize_sidecar_lifecycle(true); - DDTRACE_G(request_initialized) = false; + memcpy(&ddtrace_span_data_handlers, &std_object_handlers, sizeof(zend_object_handlers)); + ddtrace_span_data_handlers.offset = XtOffsetOf(ddtrace_span_data, std); + ddtrace_span_data_handlers.clone_obj = ddtrace_span_data_clone_obj; + 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_telemetry_rshutdown(); - ddtrace_sidecar_rshutdown(); + 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; - if (DDTRACE_G(last_service_name)) { - zend_string_release(DDTRACE_G(last_service_name)); - DDTRACE_G(last_service_name) = NULL; - } - if (DDTRACE_G(last_env_name)) { - zend_string_release(DDTRACE_G(last_env_name)); - DDTRACE_G(last_env_name) = NULL; - } - if (DDTRACE_G(last_version)) { - zend_string_release(DDTRACE_G(last_version)); - DDTRACE_G(last_version) = NULL; - } + memcpy(&ddtrace_inferred_span_data_handlers, &ddtrace_span_data_handlers, sizeof(zend_object_handlers)); + ddtrace_inferred_span_data_handlers.offset = XtOffsetOf(ddtrace_inferred_span_data, std); + ddtrace_inferred_span_data_handlers.clone_obj = ddtrace_inferred_span_data_clone_obj; - ddtrace_clean_git_object(); - ddtrace_weak_resources_rshutdown(); - return SUCCESS; -} + ddtrace_ce_root_span_data = register_class_DDTrace_RootSpanData(ddtrace_ce_span_data); + ddtrace_ce_root_span_data->create_object = ddtrace_root_span_data_create; -#if PHP_VERSION_ID < 80000 -int ddtrace_post_deactivate(void) { -#else -zend_result ddtrace_post_deactivate(void) { +#if PHP_VERSION_ID >= 80000 && PHP_VERSION_ID < 80100 + // Work around wrong reference source for typed internal properties by preventing duplication of them + // php -d extension=zend_test -r '$c = new _ZendTestChildClass; $i = &$c->intProp;' + // php: /usr/local/src/php/Zend/zend_execute.c:3390: zend_ref_del_type_source: Assertion `source_list->ptr == prop' failed. + zend_hash_init(&dd_root_span_data_duplicated_properties_table, zend_hash_num_elements(&ddtrace_ce_span_data->properties_info), NULL, NULL, true); + for (uint32_t i = 0; i < zend_hash_num_elements(&ddtrace_ce_span_data->properties_info); ++i) { + Bucket *bucket = &ddtrace_ce_root_span_data->properties_info.arData[i]; + zend_hash_add_ptr(&dd_root_span_data_duplicated_properties_table, bucket->key, Z_PTR(bucket->val)); + Z_PTR(bucket->val) = ddtrace_ce_root_span_data->properties_info_table[i] = Z_PTR(ddtrace_ce_span_data->properties_info.arData[i].val); + } #endif - zai_interceptor_deactivate(); - // we can only actually free our hooks hashtables in post_deactivate, as within RSHUTDOWN some user code may still run - zai_hook_rshutdown(); - zai_uhook_rshutdown(); + memcpy(&ddtrace_root_span_data_handlers, &ddtrace_span_data_handlers, sizeof(zend_object_handlers)); + ddtrace_root_span_data_handlers.offset = XtOffsetOf(ddtrace_root_span_data, std); + ddtrace_root_span_data_handlers.clone_obj = ddtrace_root_span_data_clone_obj; + ddtrace_root_span_data_handlers.write_property = ddtrace_root_span_data_write; - // zai config may be accessed indirectly via other modules RSHUTDOWN, so delay this until the last possible time - zai_config_rshutdown(); + ddtrace_ce_span_stack = register_class_DDTrace_SpanStack(); + ddtrace_ce_span_stack->create_object = ddtrace_span_stack_create; - return SUCCESS; -} + memcpy(&ddtrace_span_stack_handlers, &std_object_handlers, sizeof(zend_object_handlers)); + ddtrace_span_stack_handlers.clone_obj = ddtrace_span_stack_clone_obj; + ddtrace_span_stack_handlers.dtor_obj = ddtrace_span_stack_dtor_obj; + ddtrace_span_stack_handlers.read_property = ddtrace_span_stack_read_property; + ddtrace_span_stack_handlers.get_property_ptr_ptr = ddtrace_span_stack_get_property_ptr_ptr; + ddtrace_span_stack_handlers.write_property = ddtrace_span_stack_readonly; -void ddtrace_disable_tracing_in_current_request(void) { - // PHP 8 has ZSTR_CHAR('0') which is nicer... - zend_string *zero = zend_string_init("0", 1, 0); - zend_alter_ini_entry(zai_config_memoized_entries[DDTRACE_CONFIG_DD_TRACE_ENABLED].ini_entries[0]->name, zero, - ZEND_INI_USER, ZEND_INI_STAGE_RUNTIME); - zend_string_release(zero); } -bool ddtrace_alter_dd_trace_disabled_config(zval *old_value, zval *new_value, zend_string *new_str) { - (void)new_str; - - if (Z_TYPE_P(old_value) == Z_TYPE_P(new_value)) { - return true; - } - - if (ddtrace_disable) { - return Z_TYPE_P(new_value) == IS_FALSE; // no changing to enabled allowed if globally disabled - } - - if (!DDTRACE_G(active_stack)) { - return true; // We must not do anything early in RINIT before the necessary structures are initialized at all - } - - if (Z_TYPE_P(old_value) == IS_FALSE) { - dd_initialize_request(); - } else if (!ddtrace_disable) { // if this is true, the request has not been initialized at all - ddtrace_close_all_open_spans(false); // All remaining userland spans (and root span) - dd_clean_globals(); - } +/* DDTrace\FatalError */ +zend_class_entry *ddtrace_ce_fatal_error; - return true; +static void dd_register_fatal_error_ce(void) { + zend_class_entry ce; + INIT_NS_CLASS_ENTRY(ce, "DDTrace", "FatalError", NULL); + ddtrace_ce_fatal_error = zend_register_internal_class_ex(&ce, zend_ce_exception); } -static size_t datadog_info_print(const char *str) { return php_output_write(str, strlen(str)); } +zend_class_entry *ddtrace_ce_integration; +zend_class_entry *ddtrace_ce_git_metadata; +zend_object_handlers datadog_git_metadata_handlers; -static void _dd_info_tracer_config(void) { - smart_str buf = {0}; - ddtrace_startup_logging_json(&buf, PHP_JSON_PRETTY_PRINT); - php_info_print_table_row(2, "DATADOG TRACER CONFIGURATION", ZSTR_VAL(buf.s)); - smart_str_free(&buf); +static zend_object *datadog_git_metadata_create(zend_class_entry *class_type) { + zend_object *object = zend_objects_new(class_type); + object_properties_init(object, class_type); + object->handlers = &datadog_git_metadata_handlers; + return object; } -static void _dd_info_diagnostics_row(const char *key, const char *value) { - if (sapi_module.phpinfo_as_text) { - php_info_print_table_row(2, key, value); - return; - } - datadog_info_print(""); - datadog_info_print(key); - datadog_info_print(""); - datadog_info_print(value); - datadog_info_print(""); +static void ddtrace_free_obj_wrapper(zend_object *object) { + zend_object_std_dtor(object); } -static void _dd_info_diagnostics_table(void) { - php_info_print_table_start(); - php_info_print_table_colspan_header(2, "Diagnostics"); - - HashTable *ht; - ALLOC_HASHTABLE(ht); - zend_hash_init(ht, 8, NULL, ZVAL_PTR_DTOR, 0); - - ddtrace_startup_diagnostics(ht, false); - - zend_string *key; - zval *val; - ZEND_HASH_FOREACH_STR_KEY_VAL_IND(ht, key, val) { - switch (Z_TYPE_P(val)) { - case IS_STRING: - _dd_info_diagnostics_row(ZSTR_VAL(key), Z_STRVAL_P(val)); - break; - case IS_NULL: - _dd_info_diagnostics_row(ZSTR_VAL(key), "NULL"); - break; - case IS_TRUE: - case IS_FALSE: - _dd_info_diagnostics_row(ZSTR_VAL(key), Z_TYPE_P(val) == IS_TRUE ? "true" : "false"); - break; - default: - _dd_info_diagnostics_row(ZSTR_VAL(key), "{unknown type}"); - break; - } - } - ZEND_HASH_FOREACH_END(); +void ddtrace_register_functions_and_classes(int module_number) { + register_ddtrace_symbols(module_number); - php_info_print_table_row(2, "Diagnostic checks", zend_hash_num_elements(ht) == 0 ? "passed" : "failed"); + dd_register_span_data_ce(); + dd_register_fatal_error_ce(); + ddtrace_ce_integration = register_class_DDTrace_Integration(); + 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_exception_span_event = register_class_DDTrace_ExceptionSpanEvent(ddtrace_ce_span_event); - zend_hash_destroy(ht); - FREE_HASHTABLE(ht); + ddtrace_ce_git_metadata = register_class_DDTrace_GitMetadata(); + ddtrace_ce_git_metadata->create_object = datadog_git_metadata_create; + memcpy(&datadog_git_metadata_handlers, &std_object_handlers, sizeof(zend_object_handlers)); + // We need a free_obj wrapper as zend_objects_store_free_object_storage will skip freeing of classes with the default free_obj handler when fast_shutdown is active. This will mess with our refcount and leak cached git metadata. + datadog_git_metadata_handlers.free_obj = ddtrace_free_obj_wrapper; - php_info_print_table_end(); + zend_register_functions(NULL, ext_functions, NULL, datadog_module_entry.type); } -static PHP_MINFO_FUNCTION(ddtrace) { - UNUSED(zend_module); - - php_info_print_box_start(0); - datadog_info_print("Datadog PHP tracer extension"); - if (!sapi_module.phpinfo_as_text) { - datadog_info_print("
For help, check out "); - datadog_info_print( - "the documentation."); - } else { - datadog_info_print( - "\nFor help, check out the documentation at " - "https://docs.datadoghq.com/tracing/languages/php/"); - } - datadog_info_print(!sapi_module.phpinfo_as_text ? "

" : "\n"); - datadog_info_print("(c) Datadog 2020\n"); - php_info_print_box_end(); - - php_info_print_table_start(); - php_info_print_table_row(2, "Datadog tracing support", ddtrace_disable ? "disabled" : "enabled"); - php_info_print_table_row(2, "Version", PHP_DDTRACE_VERSION); - _dd_info_tracer_config(); - php_info_print_table_end(); - - if (!ddtrace_disable) { - _dd_info_diagnostics_table(); - } +void ddtrace_unregister_functions_and_classes() { +#if PHP_VERSION_ID < 80300 + zend_unregister_functions(ext_functions, sizeof(ext_functions) / sizeof(zend_function_entry) - 1, NULL); +#endif - DISPLAY_INI_ENTRIES(); +#if PHP_VERSION_ID >= 80000 && PHP_VERSION_ID < 80100 + // See dd_register_span_data_ce for explanation + zend_string *key; + void *prop_info; + ZEND_HASH_FOREACH_STR_KEY_PTR(&dd_root_span_data_duplicated_properties_table, key, prop_info) { + ZVAL_PTR(zend_hash_find(&ddtrace_ce_root_span_data->properties_info, key), prop_info); // no update to avoid dtor + } ZEND_HASH_FOREACH_END(); +#endif } /* {{{ proto string DDTrace\add_global_tag(string $key, string $value) */ @@ -2478,7 +1138,7 @@ PHP_FUNCTION(dd_trace_disable_in_request) { RETURN_THROWS(); } - ddtrace_disable_tracing_in_current_request(); + datadog_disable_tracing_in_current_request(); RETURN_BOOL(1); } @@ -2488,7 +1148,7 @@ PHP_FUNCTION(dd_trace_reset) { RETURN_THROWS(); } - if (ddtrace_disable) { + if (datadog_disable) { RETURN_BOOL(0); } @@ -2542,8 +1202,6 @@ PHP_FUNCTION(dd_trace_check_memory_under_limit) { RETURN_BOOL(ddtrace_is_memory_under_limit()); } -typedef zend_long ddtrace_zpplong_t; - PHP_FUNCTION(ddtrace_config_app_name) { zend_string *default_app_name = NULL, *app_name = get_DD_SERVICE(); if (zend_parse_parameters(ZEND_NUM_ARGS(), "|S", &default_app_name) != SUCCESS) { @@ -2574,8 +1232,8 @@ PHP_FUNCTION(ddtrace_config_trace_enabled) { } PHP_FUNCTION(ddtrace_config_integration_enabled) { - ddtrace_string name; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &name.ptr, &name.len) != SUCCESS) { + zend_string *name; + if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &name) != SUCCESS) { RETURN_NULL(); } @@ -2587,12 +1245,12 @@ PHP_FUNCTION(ddtrace_config_integration_enabled) { if (integration == NULL) { RETURN_TRUE; } - RETVAL_BOOL(ddtrace_config_integration_enabled(integration->name)); + RETVAL_BOOL(ddtrace_integrations[integration->name].is_enabled()); } PHP_FUNCTION(DDTrace_Config_integration_analytics_enabled) { - ddtrace_string name; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &name.ptr, &name.len) != SUCCESS) { + zend_string *name; + if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &name) != SUCCESS) { RETURN_NULL(); } ddtrace_integration *integration = ddtrace_get_integration_from_string(name); @@ -2603,8 +1261,8 @@ PHP_FUNCTION(DDTrace_Config_integration_analytics_enabled) { } PHP_FUNCTION(DDTrace_Config_integration_analytics_sample_rate) { - ddtrace_string name; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &name.ptr, &name.len) != SUCCESS) { + zend_string *name; + if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &name) != SUCCESS) { RETURN_NULL(); } ddtrace_integration *integration = ddtrace_get_integration_from_string(name); @@ -2632,7 +1290,7 @@ PHP_FUNCTION(DDTrace_System_container_id) { PHP_FUNCTION(DDTrace_System_process_tags_base_hash) { UNUSED(execute_data); - zend_string *base_hash = ddtrace_process_tags_get_base_hash(); + zend_string *base_hash = datadog_process_tags_get_base_hash(); if (base_hash) { RETVAL_STRINGL(ZSTR_VAL(base_hash), ZSTR_LEN(base_hash)); } else { @@ -2641,9 +1299,9 @@ PHP_FUNCTION(DDTrace_System_process_tags_base_hash) { } PHP_FUNCTION(DDTrace_Testing_trigger_error) { - ddtrace_string message; - ddtrace_zpplong_t error_type; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "sl", &message.ptr, &message.len, &error_type) != SUCCESS) { + zend_string *message; + zend_long error_type; + if (zend_parse_parameters(ZEND_NUM_ARGS(), "Sl", &message, &error_type) != SUCCESS) { RETURN_NULL(); } @@ -2663,7 +1321,7 @@ PHP_FUNCTION(DDTrace_Testing_trigger_error) { case E_RECOVERABLE_ERROR: case E_DEPRECATED: case E_USER_DEPRECATED: - zend_error(level, "%s", message.ptr); + zend_error(level, "%s", ZSTR_VAL(message)); break; default: @@ -2673,15 +1331,12 @@ PHP_FUNCTION(DDTrace_Testing_trigger_error) { } PHP_FUNCTION(DDTrace_Testing_normalize_tag_value) { - ddtrace_string value; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &value.ptr, &value.len) != SUCCESS) { + zend_string *value; + if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &value) != SUCCESS) { RETURN_EMPTY_STRING(); } - const char* normalized = ddog_normalize_process_tag_value((ddog_CharSlice){ - .ptr = value.ptr, - .len = value.len - }); + const char* normalized = ddog_normalize_process_tag_value(dd_zend_string_to_CharSlice(value)); if (normalized) { zend_string *result = zend_string_init(normalized, strlen(normalized), 0); @@ -2707,64 +1362,11 @@ PHP_FUNCTION(DDTrace_Internal_add_span_flag) { RETURN_NULL(); } -void dd_internal_handle_fork(void) { - // CHILD PROCESS -#ifndef _WIN32 - if (!get_global_DD_TRACE_SIDECAR_TRACE_SENDER()) { - ddtrace_coms_curl_shutdown(); - ddtrace_coms_clean_background_sender_after_fork(); - } -#endif - - ddtrace_sidecar_handle_fork(); - if (DDTRACE_G(agent_config_reader)) { - ddog_agent_remote_config_reader_drop(DDTRACE_G(agent_config_reader)); - DDTRACE_G(agent_config_reader) = NULL; - } - if (DDTRACE_G(remote_config_state)) { - ddog_shutdown_remote_config(DDTRACE_G(remote_config_state)); - DDTRACE_G(remote_config_state) = NULL; - } - if (DDTRACE_G(agent_info_reader)) { - ddog_drop_agent_info_reader(DDTRACE_G(agent_info_reader)); - DDTRACE_G(agent_info_reader) = NULL; - } - ddtrace_seed_prng(); - ddtrace_generate_runtime_id(); - if (!get_DD_TRACE_FORKED_PROCESS()) { - ddtrace_disable_tracing_in_current_request(); - } - if (get_DD_TRACE_ENABLED()) { - if (get_DD_DISTRIBUTED_TRACING()) { - DDTRACE_G(distributed_parent_trace_id) = ddtrace_peek_span_id(); - DDTRACE_G(distributed_trace_id) = ddtrace_peek_trace_id(); - } else { - DDTRACE_G(distributed_parent_trace_id) = 0; - DDTRACE_G(distributed_trace_id) = (ddtrace_trace_id){ 0 }; - } - ddtrace_free_span_stacks(true); - ddtrace_init_span_stacks(); - if (get_DD_TRACE_GENERATE_ROOT_SPAN()) { - ddtrace_push_root_span(); - } - } - -#ifndef _WIN32 - if (!get_global_DD_TRACE_SIDECAR_TRACE_SENDER()) { - ddtrace_coms_init_and_start_writer(); - - if (ddtrace_coms_agent_config_handle) { - ddog_agent_remote_config_reader_for_anon_shm(ddtrace_coms_agent_config_handle, &DDTRACE_G(agent_config_reader)); - } - } -#endif -} - /* {{{ proto void DDTrace\handle_fork(): void */ PHP_FUNCTION(DDTrace_Internal_handle_fork) { UNUSED(execute_data); UNUSED(return_value); - dd_internal_handle_fork(); + datadog_internal_handle_fork(); } PHP_FUNCTION(DDTrace_dogstatsd_count) { @@ -2779,7 +1381,7 @@ PHP_FUNCTION(DDTrace_dogstatsd_count) { Z_PARAM_ARRAY(tags) ZEND_PARSE_PARAMETERS_END(); - ddtrace_sidecar_dogstatsd_count(metric, value, tags); + datadog_sidecar_dogstatsd_count(metric, value, tags); RETURN_NULL(); } @@ -2796,7 +1398,7 @@ PHP_FUNCTION(DDTrace_dogstatsd_distribution) { Z_PARAM_ARRAY(tags) ZEND_PARSE_PARAMETERS_END(); - ddtrace_sidecar_dogstatsd_distribution(metric, value, tags); + datadog_sidecar_dogstatsd_distribution(metric, value, tags); RETURN_NULL(); } @@ -2813,7 +1415,7 @@ PHP_FUNCTION(DDTrace_dogstatsd_gauge) { Z_PARAM_ARRAY(tags) ZEND_PARSE_PARAMETERS_END(); - ddtrace_sidecar_dogstatsd_gauge(metric, value, tags); + datadog_sidecar_dogstatsd_gauge(metric, value, tags); RETURN_NULL(); } @@ -2830,7 +1432,7 @@ PHP_FUNCTION(DDTrace_dogstatsd_histogram) { Z_PARAM_ARRAY(tags) ZEND_PARSE_PARAMETERS_END(); - ddtrace_sidecar_dogstatsd_histogram(metric, value, tags); + datadog_sidecar_dogstatsd_histogram(metric, value, tags); RETURN_NULL(); } @@ -2847,7 +1449,7 @@ PHP_FUNCTION(DDTrace_dogstatsd_set) { Z_PARAM_ARRAY(tags) ZEND_PARSE_PARAMETERS_END(); - ddtrace_sidecar_dogstatsd_set(metric, value, tags); + datadog_sidecar_dogstatsd_set(metric, value, tags); RETURN_NULL(); } @@ -2855,18 +1457,18 @@ PHP_FUNCTION(DDTrace_dogstatsd_set) { PHP_FUNCTION(DDTrace_are_endpoints_collected) { UNUSED(execute_data); - if (!DDTRACE_G(sidecar) || !ddtrace_sidecar_instance_id || !DDTRACE_G(sidecar_queue_id)) { + if (!DATADOG_G(sidecar) || !datadog_sidecar_instance_id || !DATADOG_G(sidecar_queue_id)) { RETURN_TRUE; // Skip overhead if unnecessary } - if (!DDTRACE_G(last_service_name) || !DDTRACE_G(last_env_name)) { + if (!DATADOG_G(last_service_name) || !DATADOG_G(last_env_name)) { RETURN_FALSE; } - ddog_CharSlice service_name = dd_zend_string_to_CharSlice(DDTRACE_G(last_service_name)); - ddog_CharSlice env_name = dd_zend_string_to_CharSlice(DDTRACE_G(last_env_name)); + ddog_CharSlice service_name = dd_zend_string_to_CharSlice(DATADOG_G(last_service_name)); + ddog_CharSlice env_name = dd_zend_string_to_CharSlice(DATADOG_G(last_env_name)); - RETURN_BOOL(ddog_sidecar_telemetry_are_endpoints_collected(ddtrace_telemetry_cache(), service_name, env_name)); + RETURN_BOOL(ddog_sidecar_telemetry_are_endpoints_collected(datadog_telemetry_cache(), service_name, env_name)); } static ddog_Method dd_string_to_method(zend_string *method) { @@ -2911,7 +1513,7 @@ PHP_FUNCTION(DDTrace_add_endpoint) { RETURN_FALSE; } - if (!DDTRACE_G(sidecar) || !ddtrace_sidecar_instance_id || !DDTRACE_G(sidecar_queue_id)) { + if (!DATADOG_G(sidecar) || !datadog_sidecar_instance_id || !DATADOG_G(sidecar_queue_id)) { RETURN_FALSE; } @@ -2927,7 +1529,7 @@ PHP_FUNCTION(DDTrace_add_endpoint) { (int)resource_name_slice.len, (char *)resource_name_slice.ptr, resource_name_slice.len, (int)method->len, ZSTR_VAL(method), (size_t)method->len); - ddog_sidecar_telemetry_addEndpoint_buffer(ddtrace_telemetry_buffer(), method_enum, path_slice, operation_name_slice, resource_name_slice); + ddog_sidecar_telemetry_addEndpoint_buffer(datadog_telemetry_buffer(), method_enum, path_slice, operation_name_slice, resource_name_slice); RETURN_TRUE; } @@ -2936,25 +1538,25 @@ PHP_FUNCTION(DDTrace_flush_endpoints) { UNUSED(execute_data); UNUSED(return_value); - if (!DDTRACE_G(sidecar) || !ddtrace_sidecar_instance_id || !DDTRACE_G(sidecar_queue_id) || !DDTRACE_G(telemetry_buffer)) { + if (!DATADOG_G(sidecar) || !datadog_sidecar_instance_id || !DATADOG_G(sidecar_queue_id) || !DATADOG_G(telemetry_buffer)) { return; } - if (!DDTRACE_G(last_service_name) || !DDTRACE_G(last_env_name)) { + if (!DATADOG_G(last_service_name) || !DATADOG_G(last_env_name)) { return; } - ddog_CharSlice service_name = dd_zend_string_to_CharSlice(DDTRACE_G(last_service_name)); - ddog_CharSlice env_name = dd_zend_string_to_CharSlice(DDTRACE_G(last_env_name)); + ddog_CharSlice service_name = dd_zend_string_to_CharSlice(DATADOG_G(last_service_name)); + ddog_CharSlice env_name = dd_zend_string_to_CharSlice(DATADOG_G(last_env_name)); - ddtrace_ffi_try("Failed flushing endpoint telemetry buffer", - ddog_sidecar_telemetry_filter_flush(&DDTRACE_G(sidecar), ddtrace_sidecar_instance_id, &DDTRACE_G(sidecar_queue_id), ddtrace_telemetry_buffer(), ddtrace_telemetry_cache(), service_name, env_name)); + datadog_ffi_try("Failed flushing endpoint telemetry buffer", + ddog_sidecar_telemetry_filter_flush(&DATADOG_G(sidecar), datadog_sidecar_instance_id, &DATADOG_G(sidecar_queue_id), datadog_telemetry_buffer(), datadog_telemetry_cache(), service_name, env_name)); } PHP_FUNCTION(dd_trace_send_traces_via_thread) { char *payload = NULL; - ddtrace_zpplong_t num_traces = 0; - ddtrace_zppstrlen_t payload_len = 0; + 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 @@ -3029,10 +1631,10 @@ PHP_FUNCTION(dd_trace_internal_fn) { RETVAL_FALSE; if (ZSTR_LEN(function_val) > 0) { if (FUNCTION_NAME_MATCHES("finalize_telemetry")) { - ddog_QueueId queueId = DDTRACE_G(sidecar_queue_id); - dd_finalize_sidecar_lifecycle(false); - DDTRACE_G(sidecar_queue_id) = queueId; // usually we want to stop using it, except here - ddtrace_telemetry_lifecycle_end(); + ddog_QueueId queueId = DATADOG_G(sidecar_queue_id); + datadog_sidecar_finalize(false); + DATADOG_G(sidecar_queue_id) = queueId; // usually we want to stop using it, except here + datadog_telemetry_lifecycle_end(); RETVAL_TRUE; } else if (params_count == 3 && FUNCTION_NAME_MATCHES("force_overwrite_property")) { zval *obj = ZVAL_VARARG_PARAM(params, 0); @@ -3050,7 +1652,7 @@ PHP_FUNCTION(dd_trace_internal_fn) { } } else if (params_count == 1 && FUNCTION_NAME_MATCHES("detect_composer_installed_json")) { ddog_CharSlice path = dd_zend_string_to_CharSlice(Z_STR_P(ZVAL_VARARG_PARAM(params, 0))); - ddtrace_detect_composer_installed_json(&DDTRACE_G(sidecar), ddtrace_sidecar_instance_id, &DDTRACE_G(sidecar_queue_id), path); + ddtrace_detect_composer_installed_json(&DATADOG_G(sidecar), datadog_sidecar_instance_id, &DATADOG_G(sidecar_queue_id), path); RETVAL_TRUE; } else if (params_count == 2 && FUNCTION_NAME_MATCHES("mark_integration_loaded")) { zval *name = ZVAL_VARARG_PARAM(params, 0); @@ -3065,7 +1667,7 @@ PHP_FUNCTION(dd_trace_internal_fn) { // Store the config name and value in the HashTable zval value_copy; ZVAL_COPY(&value_copy, config_value); - zend_hash_update(&DDTRACE_G(otel_config_telemetry), Z_STR_P(config_name), &value_copy); + zend_hash_update(&DATADOG_G(otel_config_telemetry), Z_STR_P(config_name), &value_copy); RETVAL_TRUE; } } else if (params_count == 3 && FUNCTION_NAME_MATCHES("track_telemetry_metrics")) { @@ -3073,48 +1675,48 @@ PHP_FUNCTION(dd_trace_internal_fn) { zval *metric_value = ZVAL_VARARG_PARAM(params, 1); zval *tags = ZVAL_VARARG_PARAM(params, 2); if (Z_TYPE_P(metric_name) == IS_STRING && Z_TYPE_P(tags) == IS_STRING) { - ddtrace_metric_register_buffer(Z_STR_P(metric_name), DDOG_METRIC_TYPE_COUNT, DDOG_METRIC_NAMESPACE_TRACERS); - ddtrace_metric_add_point(Z_STR_P(metric_name), zval_get_double(metric_value), Z_STR_P(tags)); + datadog_metric_register_buffer(Z_STR_P(metric_name), DDOG_METRIC_TYPE_COUNT, DDOG_METRIC_NAMESPACE_TRACERS); + datadog_metric_add_point(Z_STR_P(metric_name), zval_get_double(metric_value), Z_STR_P(tags)); RETVAL_TRUE; } } else if (FUNCTION_NAME_MATCHES("dump_sidecar")) { - if (!DDTRACE_G(sidecar)) { + if (!DATADOG_G(sidecar)) { RETURN_FALSE; } - ddog_CharSlice slice = ddog_sidecar_dump(&DDTRACE_G(sidecar)); + ddog_CharSlice slice = ddog_sidecar_dump(&DATADOG_G(sidecar)); RETVAL_STRINGL(slice.ptr, slice.len); free((void *) slice.ptr); } else if (FUNCTION_NAME_MATCHES("stats_sidecar")) { - if (!DDTRACE_G(sidecar)) { + if (!DATADOG_G(sidecar)) { RETURN_FALSE; } - ddog_CharSlice slice = ddog_sidecar_stats(&DDTRACE_G(sidecar)); + ddog_CharSlice slice = ddog_sidecar_stats(&DATADOG_G(sidecar)); RETVAL_STRINGL(slice.ptr, slice.len); free((void *) slice.ptr); } else if (FUNCTION_NAME_MATCHES("break_sidecar_connection")) { - if (!DDTRACE_G(sidecar)) { + if (!DATADOG_G(sidecar)) { RETURN_FALSE; } - ddog_sidecar_send_garbage(&DDTRACE_G(sidecar)); - ddtrace_generate_runtime_id(); - ddtrace_force_new_instance_id(); + ddog_sidecar_send_garbage(&DATADOG_G(sidecar)); + datadog_generate_runtime_id(); + datadog_force_new_instance_id(); RETURN_TRUE; } else if (FUNCTION_NAME_MATCHES("reload_process_tags")) { - if (ddtrace_process_tags_enabled()) { - ddtrace_process_tags_reload(); - ddtrace_sidecar_update_process_tags(); + if (datadog_process_tags_enabled()) { + datadog_process_tags_reload(); + datadog_sidecar_update_process_tags(); } RETVAL_TRUE; } else if (params_count == 1 && FUNCTION_NAME_MATCHES("set_container_tags_hash")) { zval *container_tags_hash = ZVAL_VARARG_PARAM(params, 0); if (Z_TYPE_P(container_tags_hash) == IS_STRING) { - ddtrace_process_tags_set_container_tags_hash(Z_STR_P(container_tags_hash)); + datadog_process_tags_set_container_tags_hash(Z_STR_P(container_tags_hash)); RETVAL_TRUE; } else { RETVAL_FALSE; } } else if (FUNCTION_NAME_MATCHES("synchronous_flush")) { - uint32_t timeout = 100; + uint32_t timeout = 1000; if (params_count == 1) { timeout = Z_LVAL_P(ZVAL_VARARG_PARAM(params, 0)); } @@ -3125,8 +1727,8 @@ PHP_FUNCTION(dd_trace_internal_fn) { } } else #endif - if (DDTRACE_G(sidecar)) { - ddtrace_ffi_try("Failed synchronously flushing traces", ddog_sidecar_flush(&DDTRACE_G(sidecar), (ddog_SidecarFlushOptions){.traces_and_stats = true})); + if (DATADOG_G(sidecar)) { + datadog_ffi_try("Failed synchronously flushing traces", ddog_sidecar_flush(&DATADOG_G(sidecar), (ddog_SidecarFlushOptions){.traces_and_stats = true})); } RETVAL_TRUE; #ifndef _WIN32 @@ -3179,7 +1781,7 @@ PHP_FUNCTION(dd_trace_internal_fn) { uint32_t waited = 0; while (!ddog_is_agent_info_ready() && waited < timeout_ms) { // Actively read the SHM so we pick up the update the sidecar wrote. - ddtrace_apply_agent_info(); + datadog_apply_agent_info(); usleep(10000); // 10ms waited += 10; } @@ -3187,8 +1789,8 @@ PHP_FUNCTION(dd_trace_internal_fn) { } else if (FUNCTION_NAME_MATCHES("get_loaded_remote_configs")) { // Returns a PHP array mapping loaded RC config IDs to their content summary. // e.g. ["datadog/2/LIVE_DEBUGGING/logProbe_log.../config" => ["type"=>"probe","id"=>"log..."]] - if (DDTRACE_G(remote_config_state)) { - char *rc_json = ddog_remote_config_get_loaded_configs(DDTRACE_G(remote_config_state)); + if (DATADOG_G(remote_config_state)) { + char *rc_json = ddog_remote_config_get_loaded_configs(DATADOG_G(remote_config_state)); if (zai_json_decode_assoc_safe(return_value, rc_json, strlen(rc_json), 128, false) != SUCCESS) { array_init(return_value); } @@ -3196,11 +1798,13 @@ PHP_FUNCTION(dd_trace_internal_fn) { } else { array_init(return_value); } - return; + } else if (FUNCTION_NAME_MATCHES("get_remote_config_state")) { + // Returns a placeholder; actual state is accessed via globals + RETVAL_LONG((zend_long)(uintptr_t)DATADOG_G(remote_config_state)); } else if (FUNCTION_NAME_MATCHES("get_agent_info")) { // Returns a PHP array decoded from the agent /info JSON payload. - if (DDTRACE_G(agent_info_reader)) { - char *info_json = ddog_agent_info_as_json(DDTRACE_G(agent_info_reader)); + if (DATADOG_G(agent_info_reader)) { + char *info_json = ddog_agent_info_as_json(DATADOG_G(agent_info_reader)); if (info_json) { if (zai_json_decode_assoc_safe(return_value, info_json, strlen(info_json), 128, false) != SUCCESS) { array_init(return_value); @@ -3212,12 +1816,11 @@ PHP_FUNCTION(dd_trace_internal_fn) { } else { array_init(return_value); } - return; } else if (FUNCTION_NAME_MATCHES("get_agent_sampling_config")) { // Returns a PHP array decoded from the agent sampling/remote-config JSON payload. - if (DDTRACE_G(agent_config_reader)) { + if (DATADOG_G(agent_config_reader)) { ddog_CharSlice agent_rc_data = {0}; - ddog_agent_remote_config_read(DDTRACE_G(agent_config_reader), &agent_rc_data); + ddog_agent_remote_config_read(DATADOG_G(agent_config_reader), &agent_rc_data); if (agent_rc_data.len > 0) { if (zai_json_decode_assoc_safe(return_value, agent_rc_data.ptr, (int)agent_rc_data.len, 128, false) != SUCCESS) { array_init(return_value); @@ -3228,7 +1831,6 @@ PHP_FUNCTION(dd_trace_internal_fn) { } else { array_init(return_value); } - return; } } } @@ -3258,7 +1860,7 @@ PHP_FUNCTION(dd_trace_set_trace_id) { RETURN_THROWS(); } - ddtrace_trace_id new_trace_id = ddtrace_parse_userland_trace_id(trace_id); + datadog_trace_id new_trace_id = ddtrace_parse_userland_trace_id(trace_id); if (new_trace_id.low || new_trace_id.high || (ZSTR_LEN(trace_id) == 1 && ZSTR_VAL(trace_id)[0] == '0')) { DDTRACE_G(distributed_trace_id) = new_trace_id; RETURN_TRUE; @@ -3303,8 +1905,8 @@ PHP_FUNCTION(dd_trace_synchronous_flush) { } } else #endif - if (DDTRACE_G(sidecar)) { - ddtrace_ffi_try("Failed synchronously flushing traces", ddog_sidecar_flush(&DDTRACE_G(sidecar), (ddog_SidecarFlushOptions){.traces_and_stats = true})); + if (DATADOG_G(sidecar)) { + datadog_ffi_try("Failed synchronously flushing traces", ddog_sidecar_flush(&DATADOG_G(sidecar), (ddog_SidecarFlushOptions){.traces_and_stats = true})); } RETURN_NULL(); } @@ -3560,7 +2162,7 @@ PHP_FUNCTION(DDTrace_trace_id) { RETURN_THROWS(); } - RETURN_STR(ddtrace_trace_id_as_string(ddtrace_peek_trace_id())); + RETURN_STR(datadog_trace_id_as_string(ddtrace_peek_trace_id())); } /* {{{ proto string \DDTrace\logs_correlation_trace_id() */ @@ -3569,17 +2171,17 @@ PHP_FUNCTION(DDTrace_logs_correlation_trace_id) { RETURN_THROWS(); } - ddtrace_trace_id trace_id = ddtrace_peek_trace_id(); + datadog_trace_id trace_id = ddtrace_peek_trace_id(); if (get_DD_TRACE_128_BIT_TRACEID_LOGGING_ENABLED()) { // The format of the injected trace id is conditional based on the higher-order 64 bits of the trace id uint64_t high = trace_id.high; if (high == 0) { // If zero, the injected trace id will be its decimal string encoding (preserving the current behavior of 64-bit TraceIds) - RETURN_STR(ddtrace_trace_id_as_string(trace_id)); + RETURN_STR(datadog_trace_id_as_string(trace_id)); } else { // The injected trace id will be encoded as 32 lower-case hexadecimal characters with zero-padding as necessary - RETURN_STR(ddtrace_trace_id_as_hex_string(trace_id)); + RETURN_STR(datadog_trace_id_as_hex_string(trace_id)); } } else { // The injected trace id is the decimal encoding of the lower-order 64-bits of the trace id @@ -3595,7 +2197,7 @@ PHP_FUNCTION(DDTrace_current_context) { array_init(return_value); - add_assoc_str_ex(return_value, ZEND_STRL("trace_id"), ddtrace_trace_id_as_string(ddtrace_peek_trace_id())); + add_assoc_str_ex(return_value, ZEND_STRL("trace_id"), datadog_trace_id_as_string(ddtrace_peek_trace_id())); add_assoc_str_ex(return_value, ZEND_STRL("span_id"), ddtrace_span_id_as_string(ddtrace_peek_span_id())); zval zv; @@ -3665,9 +2267,9 @@ PHP_FUNCTION(DDTrace_set_distributed_tracing_context) { RETURN_FALSE; } - ddtrace_trace_id new_trace_id; + datadog_trace_id new_trace_id; if (ZSTR_LEN(trace_id_str) == 1 && ZSTR_VAL(trace_id_str)[0] == '0') { - new_trace_id = (ddtrace_trace_id){ 0 }; + new_trace_id = (datadog_trace_id){ 0 }; } else if (!(new_trace_id = ddtrace_parse_userland_trace_id(trace_id_str)).low && !new_trace_id.high) { RETURN_FALSE; } @@ -3685,7 +2287,7 @@ PHP_FUNCTION(DDTrace_set_distributed_tracing_context) { if (root_span) { root_span->parent_id = new_parent_id; if (!new_trace_id.low && !new_trace_id.high) { - root_span->trace_id = (ddtrace_trace_id) { + root_span->trace_id = (datadog_trace_id) { .low = root_span->span_id, .time = get_DD_TRACE_128_BIT_TRACEID_GENERATION_ENABLED() ? root_span->start / ZEND_NANO_IN_SEC : 0, }; @@ -3702,7 +2304,7 @@ PHP_FUNCTION(DDTrace_set_distributed_tracing_context) { if (root_span) { zval zv; ZVAL_STR_COPY(&zv, origin); - ddtrace_assign_variable(&root_span->property_origin, &zv); + datadog_assign_variable(&root_span->property_origin, &zv); } else { if (DDTRACE_G(dd_origin)) { zend_string_release(DDTRACE_G(dd_origin)); @@ -3981,7 +2583,7 @@ PHP_FUNCTION(DDTrace_startup_logs) { } smart_str buf = {0}; - ddtrace_startup_logging_json(&buf, 0); + datadog_startup_logging_json(&buf, 0); ZVAL_NEW_STR(return_value, buf.s); } @@ -4065,26 +2667,3 @@ PHP_FUNCTION(DDTrace_resource_weak_get) { } RETURN_COPY(ret); } - -static const zend_module_dep ddtrace_module_deps[] = { - ZEND_MOD_REQUIRED("json") - ZEND_MOD_REQUIRED("standard") - ZEND_MOD_OPTIONAL("openetelemetry") // make sure we load after otel to insert the hook function if it doesn't exist yet - ZEND_MOD_END}; - -zend_module_entry ddtrace_module_entry = {STANDARD_MODULE_HEADER_EX, NULL, - ddtrace_module_deps, PHP_DDTRACE_EXTNAME, - ext_functions, PHP_MINIT(ddtrace), - PHP_MSHUTDOWN(ddtrace), PHP_RINIT(ddtrace), - PHP_RSHUTDOWN(ddtrace), PHP_MINFO(ddtrace), - PHP_DDTRACE_VERSION, PHP_MODULE_GLOBALS(ddtrace), - PHP_GINIT(ddtrace), PHP_GSHUTDOWN(ddtrace), - ddtrace_post_deactivate, STANDARD_MODULE_PROPERTIES_EX}; - -// the following operations are performed in order to put the tracer in a state when a new trace can be started: -// - set a new trace (group) id -void dd_prepare_for_new_trace(void) { -#ifndef _WIN32 - DDTRACE_G(traces_group_id) = ddtrace_coms_next_group_id(); -#endif -} diff --git a/tracer/git_metadata.c b/tracer/git_metadata.c new file mode 100644 index 00000000000..7f3b24a0374 --- /dev/null +++ b/tracer/git_metadata.c @@ -0,0 +1,52 @@ +#include "span.h" +#include "git_metadata.h" +#include + +ZEND_EXTERN_MODULE_GLOBALS(datadog); + +static datadog_git_metadata empty_git_object = { 0 }; + +void ddtrace_inject_git_metadata(zval *carrier) { + if (DDTRACE_G(git_object) == &empty_git_object.std) { + return; + } + + if (!DDTRACE_G(git_object)) { + zend_string *commit = NULL, *repo = NULL; + if (!datadog_get_git_metadata(&commit, &repo)) { + DDTRACE_G(git_object) = &empty_git_object.std; + return; + } + + zval git_obj; + object_init_ex(&git_obj, ddtrace_ce_git_metadata); + datadog_git_metadata *git_metadata = (datadog_git_metadata *) Z_OBJ(git_obj); + DDTRACE_G(git_object) = &git_metadata->std; + + if (commit) { + ZVAL_STR_COPY(&git_metadata->property_commit, commit); + } else { + ZVAL_NULL(&git_metadata->property_commit); + } + + if (repo) { + ZVAL_STR_COPY(&git_metadata->property_repository, repo); + } else { + ZVAL_NULL(&git_metadata->property_repository); + } + } + + ZVAL_OBJ_COPY(carrier, DDTRACE_G(git_object)); +} + +void ddtrace_clean_git_object(void) { + if (DDTRACE_G(git_object) == &empty_git_object.std) { + DDTRACE_G(git_object) = NULL; + return; + } + + if (DDTRACE_G(git_object)) { + zend_object_release(DDTRACE_G(git_object)); + DDTRACE_G(git_object) = NULL; + } +} diff --git a/tracer/git_metadata.h b/tracer/git_metadata.h new file mode 100644 index 00000000000..b833959003b --- /dev/null +++ b/tracer/git_metadata.h @@ -0,0 +1,8 @@ +#ifndef DDTRACE_GIT_H +#define DDTRACE_GIT_H +#include + +void ddtrace_inject_git_metadata(zval *carrier); +void ddtrace_clean_git_object(void); + +#endif // DDTRACE_GIT_H diff --git a/ext/handlers_curl.c b/tracer/handlers_curl.c similarity index 100% rename from ext/handlers_curl.c rename to tracer/handlers_curl.c diff --git a/ext/handlers_curl_php7.c b/tracer/handlers_curl_php7.c similarity index 99% rename from ext/handlers_curl_php7.c rename to tracer/handlers_curl_php7.c index e6a4557903c..5709c6849d6 100644 --- a/ext/handlers_curl_php7.c +++ b/tracer/handlers_curl_php7.c @@ -610,7 +610,7 @@ void ddtrace_curl_handlers_startup(void) { dd_curl_wrap_handler_ce.type = ZEND_INTERNAL_CLASS; dd_curl_wrap_handler_ce.create_object = dd_curl_wrap_ctor_obj; zend_initialize_class_data(&dd_curl_wrap_handler_ce, false); - dd_curl_wrap_handler_ce.info.internal.module = &ddtrace_module_entry; + dd_curl_wrap_handler_ce.info.internal.module = &datadog_module_entry; zend_declare_property_null(&dd_curl_wrap_handler_ce, "handler", sizeof("handler") - 1, ZEND_ACC_PUBLIC); memcpy(&dd_curl_wrap_handler_handlers, &std_object_handlers, sizeof(zend_object_handlers)); dd_curl_wrap_handler_handlers.get_closure = dd_curl_wrap_get_closure; diff --git a/ext/handlers_exception.c b/tracer/handlers_exception.c similarity index 99% rename from ext/handlers_exception.c rename to tracer/handlers_exception.c index 6760a906e0f..54398be2668 100644 --- a/ext/handlers_exception.c +++ b/tracer/handlers_exception.c @@ -409,7 +409,7 @@ dd_exception_handler_get_closure(zend_object *obj, zend_class_entry **ce_ptr, ze } #if PHP_VERSION_ID >= 80100 -void dd_exception_handler_freed(zend_object *object) { +static void dd_exception_handler_freed(zend_object *object) { zend_object_std_dtor(object); if (!EG(current_execute_data) && get_DD_TRACE_ENABLED()) { @@ -527,7 +527,7 @@ void ddtrace_exception_handlers_startup(void) { INIT_NS_CLASS_ENTRY(dd_exception_or_error_handler_ce, "DDTrace", "ExceptionHandler", NULL); dd_exception_or_error_handler_ce.type = ZEND_INTERNAL_CLASS; zend_initialize_class_data(&dd_exception_or_error_handler_ce, false); - dd_exception_or_error_handler_ce.info.internal.module = &ddtrace_module_entry; + dd_exception_or_error_handler_ce.info.internal.module = &datadog_module_entry; zend_declare_property_null(&dd_exception_or_error_handler_ce, "handler", sizeof("handler") - 1, ZEND_ACC_PUBLIC); memcpy(&dd_error_handler_handlers, &std_object_handlers, sizeof(zend_object_handlers)); dd_error_handler_handlers.get_closure = dd_exception_handler_get_closure; diff --git a/ext/handlers_exception.h b/tracer/handlers_exception.h similarity index 100% rename from ext/handlers_exception.h rename to tracer/handlers_exception.h diff --git a/ext/handlers_fiber.c b/tracer/handlers_fiber.c similarity index 99% rename from ext/handlers_fiber.c rename to tracer/handlers_fiber.c index 16f51cd3781..4999f6b0205 100644 --- a/ext/handlers_fiber.c +++ b/tracer/handlers_fiber.c @@ -10,7 +10,7 @@ static int dd_resource_handle; -ZEND_EXTERN_MODULE_GLOBALS(ddtrace); +ZEND_EXTERN_MODULE_GLOBALS(datadog); // PHP-8.1 crashes hard on any bailout originating from a fiber with observers enabled. Work around it. // a) It does not update the observed frame on fibers diff --git a/ext/handlers_fiber.h b/tracer/handlers_fiber.h similarity index 100% rename from ext/handlers_fiber.h rename to tracer/handlers_fiber.h diff --git a/ext/handlers_http.h b/tracer/handlers_http.h similarity index 98% rename from ext/handlers_http.h rename to tracer/handlers_http.h index b2ad4ff15e7..52479f39c1e 100644 --- a/ext/handlers_http.h +++ b/tracer/handlers_http.h @@ -3,12 +3,13 @@ #include "configuration.h" #include "ddtrace.h" #include "priority_sampling/priority_sampling.h" +#include "random.h" #include "tracer_tag_propagation/tracer_tag_propagation.h" #include "span.h" #include #include -ZEND_EXTERN_MODULE_GLOBALS(ddtrace); +ZEND_EXTERN_MODULE_GLOBALS(datadog); static inline zend_string *ddtrace_format_tracestate(zend_string *tracestate, uint64_t span_id, zend_string *origin, zend_long sampling_priority, zend_string *propagated_tags, zend_array *tracestate_unknown_dd_keys) { smart_str str = {0}; @@ -365,7 +366,7 @@ static inline void ddtrace_inject_distributed_headers_config(zend_array *array, ADD_HEADER("x-datadog-origin", "%s", ZSTR_VAL(origin)); } } - ddtrace_trace_id trace_id = ddtrace_peek_trace_id(); + datadog_trace_id trace_id = ddtrace_peek_trace_id(); uint64_t span_id = ddtrace_peek_span_id(); if (trace_id.low || trace_id.high) { if (send_datadog) { @@ -492,8 +493,8 @@ static inline void ddtrace_inject_distributed_headers_config(zend_array *array, } static inline void ddtrace_inject_distributed_headers(zend_array *array, header_format format) { - zend_array *inject = zai_config_is_modified(DDTRACE_CONFIG_DD_TRACE_PROPAGATION_STYLE) - && !zai_config_is_modified(DDTRACE_CONFIG_DD_TRACE_PROPAGATION_STYLE_INJECT) + zend_array *inject = zai_config_is_modified(DATADOG_CONFIG_DD_TRACE_PROPAGATION_STYLE) + && !zai_config_is_modified(DATADOG_CONFIG_DD_TRACE_PROPAGATION_STYLE_INJECT) ? get_DD_TRACE_PROPAGATION_STYLE() : get_DD_TRACE_PROPAGATION_STYLE_INJECT(); ddtrace_inject_distributed_headers_config(array, format, inject); } diff --git a/ext/handlers_httpstreams.c b/tracer/handlers_httpstreams.c similarity index 100% rename from ext/handlers_httpstreams.c rename to tracer/handlers_httpstreams.c diff --git a/ext/handlers_internal.c b/tracer/handlers_internal.c similarity index 94% rename from ext/handlers_internal.c rename to tracer/handlers_internal.c index 648886d3e24..7d04911f7bf 100644 --- a/ext/handlers_internal.c +++ b/tracer/handlers_internal.c @@ -1,6 +1,5 @@ #include "handlers_internal.h" -#include "arrays.h" #include "ddtrace.h" #include "integrations/exec_integration.h" @@ -29,11 +28,7 @@ void ddtrace_free_unregistered_class(zend_class_entry *ce) { void ddtrace_curl_handlers_startup(void); void ddtrace_exception_handlers_startup(void); -void ddtrace_pcntl_handlers_startup(void); void ddtrace_kafka_handlers_startup(void); -#ifndef _WIN32 -void ddtrace_signal_block_handlers_startup(void); -#endif void ddtrace_instrument_stream_wrappers(void); #if PHP_VERSION_ID >= 80000 && PHP_VERSION_ID < 80200 @@ -146,8 +141,6 @@ void ddtrace_internal_handlers_startup() { // curl is different; it has pieces that always run. ddtrace_curl_handlers_startup(); - // pcntl handlers have to run even if tracing of pcntl extension is not enabled. - ddtrace_pcntl_handlers_startup(); // exception handlers have to run otherwise wrapping will fail horribly ddtrace_exception_handlers_startup(); @@ -156,10 +149,6 @@ void ddtrace_internal_handlers_startup() { ddtrace_exec_handlers_startup(); ddtrace_kafka_handlers_startup(); -#ifndef _WIN32 - // Block remote-config signals of some functions - ddtrace_signal_block_handlers_startup(); -#endif } void ddtrace_internal_handlers_shutdown(void) { diff --git a/ext/handlers_internal.h b/tracer/handlers_internal.h similarity index 60% rename from ext/handlers_internal.h rename to tracer/handlers_internal.h index 2d9f5dffa53..cbf40c385e4 100644 --- a/ext/handlers_internal.h +++ b/tracer/handlers_internal.h @@ -3,11 +3,7 @@ #include -#include "handlers_api.h" -#include "ddtrace_string.h" - -void ddtrace_replace_internal_function(const HashTable *ht, ddtrace_string fname); -void ddtrace_replace_internal_functions(const HashTable *ht, size_t functions_len, ddtrace_string functions[]); +#include void ddtrace_free_unregistered_class(zend_class_entry *ce); diff --git a/ext/handlers_kafka.c b/tracer/handlers_kafka.c similarity index 97% rename from ext/handlers_kafka.c rename to tracer/handlers_kafka.c index f1ce39dfcc6..9d2d7aaa4fd 100644 --- a/ext/handlers_kafka.c +++ b/tracer/handlers_kafka.c @@ -1,9 +1,10 @@ #include #include #include "configuration.h" -#include "handlers_api.h" +#include "ddtrace.h" +#include -ZEND_EXTERN_MODULE_GLOBALS(ddtrace); +ZEND_EXTERN_MODULE_GLOBALS(datadog); #define MAX_PRODUCEV_ARGS 7 diff --git a/ext/hook/uhook.c b/tracer/hook/uhook.c similarity index 99% rename from ext/hook/uhook.c rename to tracer/hook/uhook.c index 9a5bee3be0a..5280312eb58 100644 --- a/ext/hook/uhook.c +++ b/tracer/hook/uhook.c @@ -6,10 +6,11 @@ #include #include -#include "../compatibility.h" +#include #include "../configuration.h" -#include "../telemetry.h" +#include #include +#include "../span.h" #define HOOK_INSTANCE 0x1 @@ -18,11 +19,11 @@ #include #include "uhook.h" -#include "compat_string.h" +#include #include #include -ZEND_EXTERN_MODULE_GLOBALS(ddtrace); +ZEND_EXTERN_MODULE_GLOBALS(datadog); extern void (*profiling_interrupt_function)(zend_execute_data *); @@ -214,7 +215,7 @@ void dd_uhook_report_sandbox_error(zend_execute_data *execute_data, zend_object const char *type = ZSTR_VAL(ex->ce->name); const char *msg = regular_exception ? ZSTR_VAL(zai_exception_message(ex)): ""; zend_long exline = regular_exception ? zval_get_long(zai_exception_read_property(ex, ZSTR_KNOWN(ZEND_STR_LINE))) : 0; - zend_string *exfile = regular_exception ? ddtrace_convert_to_str(zai_exception_read_property(ex, ZSTR_KNOWN(ZEND_STR_FILE))) : NULL; + zend_string *exfile = regular_exception ? datadog_convert_to_str(zai_exception_read_property(ex, ZSTR_KNOWN(ZEND_STR_FILE))) : NULL; log("%s thrown in ddtrace's closure defined at %s:%d for %s%s%s(): %s in %s on line %d", type, deffile, defline, scope, colon, name, msg, regular_exception ? ZSTR_VAL(exfile) : "Unknown", exline); if (get_global_DD_INSTRUMENTATION_TELEMETRY_ENABLED() && get_DD_TELEMETRY_LOG_COLLECTION_ENABLED()) { @@ -1177,7 +1178,7 @@ void zai_uhook_minit(int module_number) { ddtrace_hook_data_returned_prop_info = zend_hash_str_find_ptr(&ddtrace_hook_data_ce->properties_info, ZEND_STRL("returned")); #endif - zend_register_functions(NULL, ext_functions, NULL, MODULE_PERSISTENT); + zend_register_functions(NULL, ext_functions, NULL, datadog_module_entry.type); register_uhook_symbols(module_number); #if PHP_VERSION_ID >= 80000 diff --git a/ext/hook/uhook.h b/tracer/hook/uhook.h similarity index 100% rename from ext/hook/uhook.h rename to tracer/hook/uhook.h diff --git a/ext/hook/uhook.stub.php b/tracer/hook/uhook.stub.php similarity index 100% rename from ext/hook/uhook.stub.php rename to tracer/hook/uhook.stub.php diff --git a/ext/hook/uhook_arginfo.h b/tracer/hook/uhook_arginfo.h similarity index 100% rename from ext/hook/uhook_arginfo.h rename to tracer/hook/uhook_arginfo.h diff --git a/ext/hook/uhook_attributes.c b/tracer/hook/uhook_attributes.c similarity index 99% rename from ext/hook/uhook_attributes.c rename to tracer/hook/uhook_attributes.c index f6fa6cd97e3..a1e6f32fec5 100644 --- a/ext/hook/uhook_attributes.c +++ b/tracer/hook/uhook_attributes.c @@ -3,6 +3,7 @@ #include #include "../ddtrace.h" #include "../configuration.h" +#include "../span.h" #include "uhook_attributes_arginfo.h" #include "uhook.h" diff --git a/ext/hook/uhook_attributes.stub.php b/tracer/hook/uhook_attributes.stub.php similarity index 100% rename from ext/hook/uhook_attributes.stub.php rename to tracer/hook/uhook_attributes.stub.php diff --git a/ext/hook/uhook_attributes_arginfo.h b/tracer/hook/uhook_attributes_arginfo.h similarity index 100% rename from ext/hook/uhook_attributes_arginfo.h rename to tracer/hook/uhook_attributes_arginfo.h diff --git a/ext/hook/uhook_legacy.c b/tracer/hook/uhook_legacy.c similarity index 100% rename from ext/hook/uhook_legacy.c rename to tracer/hook/uhook_legacy.c diff --git a/ext/hook/uhook_otel.c b/tracer/hook/uhook_otel.c similarity index 99% rename from ext/hook/uhook_otel.c rename to tracer/hook/uhook_otel.c index 926279cbeee..89ecd44c34e 100644 --- a/ext/hook/uhook_otel.c +++ b/tracer/hook/uhook_otel.c @@ -92,7 +92,7 @@ static bool dd_uhook_begin(zend_ulong invocation, zend_execute_data *execute_dat uint32_t num_args = fbc->common.num_args; // As per zend_handle_named_arg() #if PHP_VERSION_ID < 80600 - if (UNEXPECTED(fbc->type != ZEND_USER_FUNCTION) && EXPECTED((fbc->common.fn_flags & ZEND_ACC_USER_ARG_INFO == 0))) { + if (UNEXPECTED(fbc->type != ZEND_USER_FUNCTION) && EXPECTED((fbc->common.fn_flags & ZEND_ACC_USER_ARG_INFO) == 0)) { for (uint32_t i = 0; i < num_args; i++) { zend_internal_arg_info *arg_info = &fbc->internal_function.arg_info[i]; size_t len = strlen(arg_info->name); diff --git a/ext/inferred_proxy_headers.c b/tracer/inferred_proxy_headers.c similarity index 98% rename from ext/inferred_proxy_headers.c rename to tracer/inferred_proxy_headers.c index 412ea1229f8..6d079b71805 100644 --- a/ext/inferred_proxy_headers.c +++ b/tracer/inferred_proxy_headers.c @@ -1,6 +1,6 @@ #include "inferred_proxy_headers.h" -ZEND_EXTERN_MODULE_GLOBALS(ddtrace); +ZEND_EXTERN_MODULE_GLOBALS(datadog); static HashTable proxy_info_map; diff --git a/ext/inferred_proxy_headers.h b/tracer/inferred_proxy_headers.h similarity index 100% rename from ext/inferred_proxy_headers.h rename to tracer/inferred_proxy_headers.h diff --git a/ext/integrations/exec_integration.c b/tracer/integrations/exec_integration.c similarity index 95% rename from ext/integrations/exec_integration.c rename to tracer/integrations/exec_integration.c index 61ac9fccb82..8de53fa675c 100644 --- a/ext/integrations/exec_integration.c +++ b/tracer/integrations/exec_integration.c @@ -9,10 +9,10 @@ #include #include -#include "../compatibility.h" +#include #include "../ddtrace.h" #include "../span.h" -#include "../sidecar.h" +#include #include "exec_integration_arginfo.h" #if PHP_VERSION_ID < 80000 @@ -20,7 +20,7 @@ typedef struct php_process_handle php_process_handle; #endif /* proc_open / proc_close handling */ -typedef struct _dd_proc_span { +typedef struct dd_proc_span { zend_object *span; php_process_id_t child; #ifdef _WIN32 @@ -271,13 +271,13 @@ PHP_FUNCTION(DDTrace_Integrations_Exec_proc_inject_session_ids) { zend_array *env = Z_ARR_P(env_zv); zval zv; - ZVAL_STRINGL(&zv, (char *)ddtrace_formatted_session_id, sizeof(ddtrace_formatted_session_id)); + ZVAL_STRINGL(&zv, (char *)datadog_formatted_session_id, sizeof(datadog_formatted_session_id)); zend_hash_str_update(env, "_DD_PARENT_PHP_SESSION_ID", sizeof("_DD_PARENT_PHP_SESSION_ID") - 1, &zv); - if (ddtrace_is_empty_session_id(ddtrace_formatted_root_session_id)) { - ZVAL_STRINGL(&zv, (char *)ddtrace_formatted_session_id, sizeof(ddtrace_formatted_session_id)); + if (datadog_is_empty_session_id(datadog_formatted_root_session_id)) { + ZVAL_STRINGL(&zv, (char *)datadog_formatted_session_id, sizeof(datadog_formatted_session_id)); } else { - ZVAL_STRINGL(&zv, (char *)ddtrace_formatted_root_session_id, sizeof(ddtrace_formatted_root_session_id)); + ZVAL_STRINGL(&zv, (char *)datadog_formatted_root_session_id, sizeof(datadog_formatted_root_session_id)); } zend_hash_str_update(env, "_DD_ROOT_PHP_SESSION_ID", sizeof("_DD_ROOT_PHP_SESSION_ID") - 1, &zv); } @@ -297,7 +297,7 @@ void ddtrace_exec_handlers_startup() { orig_php_stream_stdio_ops_close = php_stream_stdio_ops.close; php_stream_stdio_ops.close = dd_php_stdiop_close_wrapper; - zend_register_functions(NULL, ext_functions, NULL, MODULE_PERSISTENT); + zend_register_functions(NULL, ext_functions, NULL, datadog_module_entry.type); cmd_exit_code_zstr = zend_string_init_interned(ZEND_STRL("cmd.exit_code"), 1); error_message_zstr = zend_string_init_interned(ZEND_STRL("error.message"), 1); has_signalled_zstr = zend_string_init_interned(ZEND_STRL("The process was terminated by a signal"), 1); diff --git a/ext/integrations/exec_integration.h b/tracer/integrations/exec_integration.h similarity index 100% rename from ext/integrations/exec_integration.h rename to tracer/integrations/exec_integration.h diff --git a/ext/integrations/exec_integration.stub.php b/tracer/integrations/exec_integration.stub.php similarity index 100% rename from ext/integrations/exec_integration.stub.php rename to tracer/integrations/exec_integration.stub.php diff --git a/ext/integrations/exec_integration_arginfo.h b/tracer/integrations/exec_integration_arginfo.h similarity index 100% rename from ext/integrations/exec_integration_arginfo.h rename to tracer/integrations/exec_integration_arginfo.h diff --git a/ext/integrations/integrations.c b/tracer/integrations/integrations.c similarity index 97% rename from ext/integrations/integrations.c rename to tracer/integrations/integrations.c index 248e2cc7c45..c955e91b67f 100644 --- a/ext/integrations/integrations.c +++ b/tracer/integrations/integrations.c @@ -1,7 +1,8 @@ #include "integrations.h" #include "../configuration.h" -#include "../telemetry.h" +#include "../tracer_telemetry.h" +#include #include #include #include @@ -44,11 +45,11 @@ ddtrace_integration ddtrace_integrations[] = {DD_INTEGRATIONS}; size_t ddtrace_integrations_len = sizeof ddtrace_integrations / sizeof ddtrace_integrations[0]; // Map of lowercase strings to the ddtrace_integration equivalent -static HashTable _dd_string_to_integration_name_map; +static HashTable dd_string_to_integration_name_map; -static void _dd_add_integration_to_map(char* name, size_t name_len, ddtrace_integration* integration); +static void dd_add_integration_to_map(char* name, size_t name_len, ddtrace_integration* integration); -void ddtrace_integrations_mshutdown(void) { zend_hash_destroy(&_dd_string_to_integration_name_map); } +void ddtrace_integrations_mshutdown(void) { zend_hash_destroy(&dd_string_to_integration_name_map); } typedef struct { ddtrace_integration_name name; @@ -83,7 +84,7 @@ static void dd_invoke_integration_loader_and_unhook_posthook(zend_ulong invocati dd_integration_aux *aux = auxiliary; volatile bool unload_hooks = true; - if (aux->name == -1u || ddtrace_config_integration_enabled(aux->name)) { + if (aux->name == -1u || ddtrace_integrations[aux->name].is_enabled()) { if (aux->name != -1u) { ddtrace_telemetry_notify_integration(ddtrace_integrations[aux->name].name_lcase, ddtrace_integrations[aux->name].name_len); } else { @@ -226,13 +227,13 @@ static void dd_set_up_deferred_loading_by_method(ddtrace_integration_name name, } void ddtrace_integrations_minit(void) { - zend_hash_init(&_dd_string_to_integration_name_map, ddtrace_integrations_len, NULL, NULL, 1); + zend_hash_init(&dd_string_to_integration_name_map, ddtrace_integrations_len, NULL, NULL, 1); for (size_t i = 0; i < ddtrace_integrations_len; ++i) { memset(ddtrace_integrations[i].aux, 0, sizeof(ddtrace_integrations[i].aux)); char *name = ddtrace_integrations[i].name_lcase; size_t name_len = ddtrace_integrations[i].name_len; - _dd_add_integration_to_map(name, name_len, &ddtrace_integrations[i]); + dd_add_integration_to_map(name, name_len, &ddtrace_integrations[i]); } dd_load_test_integrations(); @@ -494,12 +495,12 @@ void ddtrace_integrations_minit(void) { "DDTrace\\Integrations\\ZendFramework\\ZendFrameworkIntegration"); } -ddtrace_integration* ddtrace_get_integration_from_string(ddtrace_string integration) { - return zend_hash_str_find_ptr(&_dd_string_to_integration_name_map, integration.ptr, integration.len); +ddtrace_integration* ddtrace_get_integration_from_string(zend_string *integration) { + return zend_hash_find_ptr(&dd_string_to_integration_name_map, integration); } -static void _dd_add_integration_to_map(char* name, size_t name_len, ddtrace_integration* integration) { - zend_hash_str_add_ptr(&_dd_string_to_integration_name_map, name, name_len, integration); +static void dd_add_integration_to_map(char* name, size_t name_len, ddtrace_integration* integration) { + zend_hash_str_add_ptr(&dd_string_to_integration_name_map, name, name_len, integration); ZEND_ASSERT(strlen(integration->name_ucase) == name_len); ZEND_ASSERT(DDTRACE_LONGEST_INTEGRATION_NAME_LEN >= name_len); } diff --git a/ext/integrations/integrations.h b/tracer/integrations/integrations.h similarity index 98% rename from ext/integrations/integrations.h rename to tracer/integrations/integrations.h index 4cd30d5c823..835cce9ab9b 100644 --- a/ext/integrations/integrations.h +++ b/tracer/integrations/integrations.h @@ -3,8 +3,6 @@ #include #include -#include "../ddtrace_string.h" - #define DD_TRACE_INTEGRATION_NOT_LOADED 0 #define DD_TRACE_INTEGRATION_LOADED 1 #define DD_TRACE_INTEGRATION_NOT_AVAILABLE 2 @@ -80,6 +78,6 @@ extern size_t ddtrace_integrations_len; void ddtrace_integrations_minit(void); void ddtrace_integrations_mshutdown(void); -ddtrace_integration *ddtrace_get_integration_from_string(ddtrace_string integration); +ddtrace_integration *ddtrace_get_integration_from_string(zend_string *integration); #endif // DD_INTEGRATIONS_INTEGRATIONS_H diff --git a/ext/ip_extraction.c b/tracer/ip_extraction.c similarity index 99% rename from ext/ip_extraction.c rename to tracer/ip_extraction.c index 5318eddbac5..97d21fd4250 100644 --- a/ext/ip_extraction.c +++ b/tracer/ip_extraction.c @@ -8,7 +8,9 @@ #include #include -#include "compatibility.h" +#include +#include +#include "ip_extraction.h" #include "configuration.h" #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) @@ -130,7 +132,7 @@ bool ddtrace_parse_client_ip_header_config(zai_str value, zval *decoded_value, b return true; } -DDTRACE_PUBLIC zend_string *ddtrace_ip_extraction_find(zval *server) { +DATADOG_PUBLIC zend_string *ddtrace_ip_extraction_find(zval *server) { if (!server || Z_TYPE_P(server) != IS_ARRAY) { return NULL; } diff --git a/ext/ip_extraction.h b/tracer/ip_extraction.h similarity index 77% rename from ext/ip_extraction.h rename to tracer/ip_extraction.h index 149c3be3c91..5223086e622 100644 --- a/ext/ip_extraction.h +++ b/tracer/ip_extraction.h @@ -3,11 +3,11 @@ #include #include -#include +#include void dd_ip_extraction_startup(void); bool ddtrace_parse_client_ip_header_config(zai_str value, zval *decoded_value, bool persistent); -DDTRACE_PUBLIC zend_string *ddtrace_ip_extraction_find(zval *server); +DATADOG_PUBLIC zend_string *ddtrace_ip_extraction_find(zval *server); void ddtrace_extract_ip_from_headers(zval *server, zend_array *meta); #endif diff --git a/ext/limiter/limiter.c b/tracer/limiter/limiter.c similarity index 91% rename from ext/limiter/limiter.c rename to tracer/limiter/limiter.c index 5f21b8da566..0267e1a2e54 100644 --- a/ext/limiter/limiter.c +++ b/tracer/limiter/limiter.c @@ -5,10 +5,11 @@ #endif #include "limiter.h" -#include "../zend_hrtime.h" +#include +#include #include -#include "../sidecar.h" +#include // clang-format Off @@ -27,7 +28,7 @@ static ddtrace_limiter* dd_limiter; void ddtrace_limiter_create() { - if (zai_config_memoized_entries[DDTRACE_CONFIG_DD_TRACE_SAMPLE_RATE].name_index == ZAI_CONFIG_ORIGIN_DEFAULT) { + if (zai_config_memoized_entries[DATADOG_CONFIG_DD_TRACE_SAMPLE_RATE].name_index == ZAI_CONFIG_ORIGIN_DEFAULT) { return; } @@ -39,11 +40,11 @@ void ddtrace_limiter_create() { // We share the limiter among forks (ie, forks need to write this memory), this requires that we map the memory as shared ddog_ShmHandle *shm; - if (!ddtrace_ffi_try("Failed allocating shared memory", ddog_alloc_anon_shm_handle(limit, &shm))) { + if (!datadog_ffi_try("Failed allocating shared memory", ddog_alloc_anon_shm_handle(limit, &shm))) { return; } size_t _size; - if (!ddtrace_ffi_try("Failed mapping shared memory", ddog_map_shm(shm, &dd_limiter_mapped_shm, (void **)&dd_limiter, &_size))) { + if (!datadog_ffi_try("Failed mapping shared memory", ddog_map_shm(shm, &dd_limiter_mapped_shm, (void **)&dd_limiter, &_size))) { ddog_drop_anon_shm_handle(shm); return; } diff --git a/ext/limiter/limiter.h b/tracer/limiter/limiter.h similarity index 100% rename from ext/limiter/limiter.h rename to tracer/limiter/limiter.h diff --git a/ext/live_debugger.c b/tracer/live_debugger.c similarity index 95% rename from ext/live_debugger.c rename to tracer/live_debugger.c index f1b80ee3938..81a5109e4a1 100644 --- a/ext/live_debugger.c +++ b/tracer/live_debugger.c @@ -5,18 +5,19 @@ #include "zai_string/string.h" #include "span.h" #include "hook/uhook.h" -#include "sidecar.h" +#include #include "hook/hook.h" #include "serializer.h" #include "configuration.h" -#include "compat_string.h" +#include #include "zend_interfaces.h" -#include "zend_hrtime.h" +#include #include "components-rs/common.h" +#include #include "zend_generators.h" -#include "process_tags.h" +#include -ZEND_EXTERN_MODULE_GLOBALS(ddtrace); +ZEND_EXTERN_MODULE_GLOBALS(datadog); struct eval_ctx { zend_execute_data *frame; @@ -154,7 +155,7 @@ static void dd_probe_resolved(void *data, bool found) { def->probe.status_msg = DDOG_CHARSLICE_C("Method does not exist on the given class"); def->probe.status_exception = DDOG_CHARSLICE_C("METHOD_NOT_FOUND"); } - ddog_send_debugger_diagnostics(DDTRACE_G(remote_config_state), &DDTRACE_G(sidecar), ddtrace_sidecar_instance_id, DDTRACE_G(sidecar_queue_id), &def->probe, ddtrace_nanoseconds_realtime() / 1000000); + ddog_send_debugger_diagnostics(DATADOG_G(remote_config_state), &DATADOG_G(sidecar), datadog_sidecar_instance_id, DATADOG_G(sidecar_queue_id), &def->probe, ddtrace_nanoseconds_realtime() / 1000000); } static int64_t dd_init_live_debugger_probe(const ddog_Probe *probe, dd_probe_def *def, zai_hook_begin begin, zai_hook_end end, void (*def_dtor)(void *), size_t dynamic) { @@ -167,7 +168,7 @@ static int64_t dd_init_live_debugger_probe(const ddog_Probe *probe, dd_probe_def const ddog_ProbeTarget *target = &probe->target; if (target->type_name.len) { - if (!ddog_type_can_be_instrumented(DDTRACE_G(remote_config_state), target->type_name)) { + if (!ddog_type_can_be_instrumented(DATADOG_G(remote_config_state), target->type_name)) { def->probe.status = DDOG_PROBE_STATUS_BLOCKED; goto error; } @@ -205,24 +206,24 @@ static int64_t dd_init_live_debugger_probe(const ddog_Probe *probe, dd_probe_def def->probe.status_msg = DDOG_CHARSLICE_C("Method does not exist on the given class"); def->probe.status_exception = DDOG_CHARSLICE_C("METHOD_NOT_FOUND"); error: - ddog_send_debugger_diagnostics(DDTRACE_G(remote_config_state), &DDTRACE_G(sidecar), ddtrace_sidecar_instance_id, DDTRACE_G(sidecar_queue_id), &def->probe, ddtrace_nanoseconds_realtime() / 1000000); + ddog_send_debugger_diagnostics(DATADOG_G(remote_config_state), &DATADOG_G(sidecar), datadog_sidecar_instance_id, DATADOG_G(sidecar_queue_id), &def->probe, ddtrace_nanoseconds_realtime() / 1000000); def_dtor(def); return -1; } if (def->probe.status != DDOG_PROBE_STATUS_INSTALLED) { def->probe.status = DDOG_PROBE_STATUS_RECEIVED; - ddog_send_debugger_diagnostics(DDTRACE_G(remote_config_state), &DDTRACE_G(sidecar), ddtrace_sidecar_instance_id, DDTRACE_G(sidecar_queue_id), &def->probe, ddtrace_nanoseconds_realtime() / 1000000); + ddog_send_debugger_diagnostics(DATADOG_G(remote_config_state), &DATADOG_G(sidecar), datadog_sidecar_instance_id, DATADOG_G(sidecar_queue_id), &def->probe, ddtrace_nanoseconds_realtime() / 1000000); } - zend_hash_index_add_new_ptr(&DDTRACE_G(active_rc_hooks), id, def); + zend_hash_index_add_new_ptr(&DDTRACE_G(active_live_debugger_hooks), id, def); return id; } static void dd_probe_mark_active(dd_probe_def *def) { if (def->probe.status != DDOG_PROBE_STATUS_EMITTING) { def->probe.status = DDOG_PROBE_STATUS_EMITTING; - ddog_send_debugger_diagnostics(DDTRACE_G(remote_config_state), &DDTRACE_G(sidecar), ddtrace_sidecar_instance_id, DDTRACE_G(sidecar_queue_id), &def->probe, ddtrace_nanoseconds_realtime() / 1000000); + ddog_send_debugger_diagnostics(DATADOG_G(remote_config_state), &DATADOG_G(sidecar), datadog_sidecar_instance_id, DATADOG_G(sidecar_queue_id), &def->probe, ddtrace_nanoseconds_realtime() / 1000000); } } @@ -381,7 +382,7 @@ static bool dd_log_probe_eval_condition(dd_log_probe_def *def, zend_execute_data ddog_ConditionEvaluationResult condition = dd_eval_condition(def->parent.probe.probe.log.when, retval); switch (condition.tag) { case DDOG_CONDITION_EVALUATION_RESULT_SUCCESS: - return ddog_shm_limiter_inc(def->limiter, def->parent.probe.probe.log.sampling_snapshots_per_second) && ddog_global_log_probe_limiter_inc(DDTRACE_G(remote_config_state)); + return ddog_shm_limiter_inc(def->limiter, def->parent.probe.probe.log.sampling_snapshots_per_second) && ddog_global_log_probe_limiter_inc(DATADOG_G(remote_config_state)); case DDOG_CONDITION_EVALUATION_RESULT_ERROR: dd_submit_probe_eval_error_snapshot(&def->parent.probe, condition.error); break; @@ -402,7 +403,7 @@ static void dd_log_probe_ensure_payload(dd_log_probe_dyn *dyn, dd_log_probe_def dd_zend_string_to_CharSlice(dyn->service), DDOG_CHARSLICE_C("php"), ddtrace_nanoseconds_realtime() / 1000000, - dd_zend_string_to_CharSlice(ddtrace_process_tags_get_serialized())); + dd_zend_string_to_CharSlice(datadog_process_tags_get_serialized())); } } @@ -449,7 +450,10 @@ static void dd_log_probe_capture_snapshot(ddog_DebuggerCapture *capture, dd_log_ static void dd_probe_capture_stack(ddog_DebuggerPayload *payload, zend_execute_data *execute_data) { int remaining_depth = 128; - zend_execute_data *call = execute_data, *last_call = NULL; + zend_execute_data *call = execute_data; +#if PHP_VERSION_ID >= 80400 + zend_execute_data *last_call = NULL; +#endif while (call && --remaining_depth > 0) { if (UNEXPECTED(!call->func)) { /* This is the fake frame inserted for nested generators. Normally, @@ -547,7 +551,9 @@ static void dd_probe_capture_stack(ddog_DebuggerPayload *payload, zend_execute_d ddog_snapshot_push_stack_frame(payload, filename, function_name, type_name, lineno); next_frame: ; +#if PHP_VERSION_ID >= 80400 last_call = call; +#endif call = prev; } } @@ -791,16 +797,16 @@ static void dd_metric_probe_end(zend_ulong invocation, zend_execute_data *execut switch (def->probe.probe.metric.kind) { case DDOG_METRIC_KIND_COUNT: - ddtrace_sidecar_dogstatsd_count(metric_name, (zend_long)metric_value, NULL); + datadog_sidecar_dogstatsd_count(metric_name, (zend_long)metric_value, NULL); break; case DDOG_METRIC_KIND_GAUGE: - ddtrace_sidecar_dogstatsd_gauge(metric_name, metric_value, NULL); + datadog_sidecar_dogstatsd_gauge(metric_name, metric_value, NULL); break; case DDOG_METRIC_KIND_HISTOGRAM: - ddtrace_sidecar_dogstatsd_histogram(metric_name, metric_value, NULL); + datadog_sidecar_dogstatsd_histogram(metric_name, metric_value, NULL); break; case DDOG_METRIC_KIND_DISTRIBUTION: - ddtrace_sidecar_dogstatsd_distribution(metric_name, metric_value, NULL); + datadog_sidecar_dogstatsd_distribution(metric_name, metric_value, NULL); break; } @@ -844,7 +850,7 @@ static int64_t dd_set_probe(const ddog_Probe probe, const ddog_MaybeShmLimiter * static void dd_remove_live_debugger_probe(int64_t id) { dd_probe_def *def; - if ((def = zend_hash_index_find_ptr(&DDTRACE_G(active_rc_hooks), (zend_ulong)id))) { + if ((def = zend_hash_index_find_ptr(&DDTRACE_G(active_live_debugger_hooks), (zend_ulong)id))) { zend_string *scope = def->scope ? zend_string_copy(def->scope) : NULL; zend_string *func = def->function ? zend_string_copy(def->function) : NULL; def->removed = true; @@ -1234,7 +1240,7 @@ static uintptr_t dd_eval_length(void *ctx, const void *zvp) { case IS_DOUBLE: case IS_LONG: ; - zend_string *str = ddtrace_convert_to_str(zv); + zend_string *str = datadog_convert_to_str(zv); uint64_t len = ZSTR_LEN(str); zend_string_release(str); return len; @@ -1560,7 +1566,7 @@ static ddog_CharSlice dd_eval_get_string(void *ctx, const void *zvp) { static ddog_CharSlice dd_eval_stringify(void *ctx, const void *zvp) { UNUSED(ctx); const zval *zv = zvp; - zend_string *str = ddtrace_convert_to_str(zv); + zend_string *str = datadog_convert_to_str(zv); return dd_persist_str_eval_arena(ctx, str); } @@ -1665,28 +1671,46 @@ void ddtrace_live_debugger_minit(void) { } ZEND_HASH_FOREACH_END(); } +void ddtrace_live_debugger_rinit(void) { + zend_hash_init(&DDTRACE_G(active_live_debugger_hooks), 8, NULL, NULL, 0); +} + +void ddtrace_live_debugger_rshutdown(void) { + zend_hash_destroy(&DDTRACE_G(active_live_debugger_hooks)); +} + bool ddtrace_alter_dynamic_instrumentation_config(zval *old_value, zval *new_value, zend_string *new_str) { UNUSED(old_value, new_str); bool enabled = Z_TYPE_P(new_value) == IS_TRUE; // When RC writes, bypass the check for ddog_remote_config_alter_dynamic_config - if (DDTRACE_G(remote_config_state) && !DDTRACE_G(remote_config_writing) && !ddog_remote_config_alter_dynamic_config(DDTRACE_G(remote_config_state), DDOG_CHARSLICE_C("datadog.dynamic_instrumentation.enabled"), zend_string_copy(new_str))) { + if (DATADOG_G(remote_config_state) && !DATADOG_G(remote_config_writing) && !ddog_remote_config_alter_dynamic_config(DATADOG_G(remote_config_state), DDOG_CHARSLICE_C("datadog.dynamic_instrumentation.enabled"), zend_string_copy(new_str))) { return false; } // Apply/unapply probe hooks based on the new DI enabled state. - if (DDTRACE_G(remote_config_state)) { - ddog_set_dynamic_instrumentation_enabled(DDTRACE_G(remote_config_state), enabled); + if (DATADOG_G(remote_config_state)) { + ddog_set_dynamic_instrumentation_enabled(DATADOG_G(remote_config_state), enabled); } - if (DDTRACE_G(request_initialized) && DDTRACE_G(sidecar)) { - ddog_sidecar_set_request_config(&DDTRACE_G(sidecar), ddtrace_sidecar_instance_id, &DDTRACE_G(sidecar_queue_id), enabled ? DDOG_DYNAMIC_INSTRUMENTATION_CONFIG_STATE_ENABLED : DDOG_DYNAMIC_INSTRUMENTATION_CONFIG_STATE_DISABLED); + if (DATADOG_G(request_initialized) && DATADOG_G(sidecar)) { + ddog_sidecar_set_request_config(&DATADOG_G(sidecar), datadog_sidecar_instance_id, &DATADOG_G(sidecar_queue_id), enabled ? DDOG_DYNAMIC_INSTRUMENTATION_CONFIG_STATE_ENABLED : DDOG_DYNAMIC_INSTRUMENTATION_CONFIG_STATE_DISABLED); } return true; } ddog_DynamicInstrumentationConfigState ddtrace_dynamic_instrumentation_state(void) { - if (ddtrace_runtime_config_is_modified(DDTRACE_CONFIG_DD_DYNAMIC_INSTRUMENTATION_ENABLED)) { + if (zai_config_is_modified(DATADOG_CONFIG_DD_DYNAMIC_INSTRUMENTATION_ENABLED)) { return get_DD_DYNAMIC_INSTRUMENTATION_ENABLED() ? DDOG_DYNAMIC_INSTRUMENTATION_CONFIG_STATE_ENABLED : DDOG_DYNAMIC_INSTRUMENTATION_CONFIG_STATE_DISABLED; } return DDOG_DYNAMIC_INSTRUMENTATION_CONFIG_STATE_NOT_SET; } + +void ddtrace_sidecar_send_debugger_data(ddog_Vec_DebuggerPayload payloads) { + LOGEV(DEBUG, UNUSED(log); ddog_log_debugger_data(&payloads);); + ddog_sidecar_send_debugger_data(&DATADOG_G(sidecar), datadog_sidecar_instance_id, DATADOG_G(sidecar_queue_id), payloads); +} + +void ddtrace_sidecar_send_debugger_datum(ddog_DebuggerPayload *payload) { + LOGEV(DEBUG, UNUSED(log); ddog_log_debugger_datum(payload);); + ddog_sidecar_send_debugger_datum(&DATADOG_G(sidecar), datadog_sidecar_instance_id, DATADOG_G(sidecar_queue_id), payload); +} diff --git a/ext/live_debugger.h b/tracer/live_debugger.h similarity index 76% rename from ext/live_debugger.h rename to tracer/live_debugger.h index 7f553341749..a57777b4640 100644 --- a/ext/live_debugger.h +++ b/tracer/live_debugger.h @@ -7,8 +7,9 @@ extern ddog_LiveDebuggerSetup ddtrace_live_debugger_setup; void ddtrace_live_debugger_minit(void); +void ddtrace_live_debugger_rinit(void); +void ddtrace_live_debugger_rshutdown(void); bool ddtrace_alter_dynamic_instrumentation_config(zval *old_value, zval *new_value, zend_string *new_str); -ddog_DynamicInstrumentationConfigState ddtrace_dynamic_instrumentation_state(void); static inline void ddtrace_snapshot_redacted_name(ddog_CaptureValue *capture_value, ddog_CharSlice name) { if (ddog_snapshot_redacted_name(name)) { @@ -22,4 +23,7 @@ struct dd_refcounted_linked { }; void dd_free_capture_ephemerals(struct dd_refcounted_linked *ephemerals); +void ddtrace_sidecar_send_debugger_data(ddog_Vec_DebuggerPayload payloads); +void ddtrace_sidecar_send_debugger_datum(ddog_DebuggerPayload *payload); + #endif // DD_LIVE_DEBUGGER_H diff --git a/ext/memory_limit.c b/tracer/memory_limit.c similarity index 97% rename from ext/memory_limit.c rename to tracer/memory_limit.c index 80ffd352f4b..79733ee7855 100644 --- a/ext/memory_limit.c +++ b/tracer/memory_limit.c @@ -7,7 +7,7 @@ #include "ddtrace.h" #include "serializer.h" -ZEND_EXTERN_MODULE_GLOBALS(ddtrace); +ZEND_EXTERN_MODULE_GLOBALS(datadog); int64_t ddtrace_get_memory_limit(void) { zend_string *raw_memory_limit = get_DD_TRACE_MEMORY_LIMIT(); diff --git a/ext/memory_limit.h b/tracer/memory_limit.h similarity index 100% rename from ext/memory_limit.h rename to tracer/memory_limit.h diff --git a/ext/priority_sampling/priority_sampling.c b/tracer/priority_sampling/priority_sampling.c similarity index 96% rename from ext/priority_sampling/priority_sampling.c rename to tracer/priority_sampling/priority_sampling.c index a50d9de1d42..74c1a4d752d 100644 --- a/ext/priority_sampling/priority_sampling.c +++ b/tracer/priority_sampling/priority_sampling.c @@ -1,8 +1,7 @@ -#include "../compat_string.h" +#include #include "priority_sampling.h" #include -#include #include #include @@ -10,21 +9,21 @@ #include "../configuration.h" #include "../limiter/limiter.h" -#include "ddshared.h" -#include "ddtrace.h" -#include "span.h" +#include "../rule_matching.h" +#include "../ddtrace.h" +#include "../span.h" #include "components/log/log.h" -#include "agent_info.h" +#include /* Sampling constants */ static const uint64_t KNUTH_FACTOR = 1111111111111111111ULL; static const uint64_t MAX_TRACE_ID = ~0ULL; // 2^64-1 - This represents the maximum value of a Trace ID -ZEND_EXTERN_MODULE_GLOBALS(ddtrace); +ZEND_EXTERN_MODULE_GLOBALS(datadog); void ddtrace_try_read_agent_rate(void) { ddog_CharSlice data; - if (DDTRACE_G(agent_config_reader) && ddog_agent_remote_config_read(DDTRACE_G(agent_config_reader), &data)) { + if (DATADOG_G(agent_config_reader) && ddog_agent_remote_config_read(DATADOG_G(agent_config_reader), &data)) { zval json; if ((int)data.len > 0 && zai_json_decode_assoc_safe(&json, data.ptr, (int)data.len, 3, true) == SUCCESS) { if (Z_TYPE(json) == IS_ARRAY) { @@ -268,7 +267,7 @@ static void dd_decide_on_sampling(ddtrace_root_span_data *span) { if (is_trace_root || zval_get_long(&span->property_propagated_sampling_priority) == DDTRACE_PRIORITY_SAMPLING_UNKNOWN) { // when we sample, we need to fetch the env first - ddtrace_apply_agent_info(); + datadog_apply_agent_info(); double default_sample_rate = get_DD_TRACE_SAMPLE_RATE(); sample_rate = default_sample_rate >= 0 ? default_sample_rate : 1; @@ -323,7 +322,7 @@ static void dd_decide_on_sampling(ddtrace_root_span_data *span) { if (zval_get_long(&span->property_sampling_priority) == DDTRACE_PRIORITY_SAMPLING_UNKNOWN) { zval priority_zv; ZVAL_LONG(&priority_zv, PRIORITY_SAMPLING_AUTO_REJECT); - ddtrace_assign_variable(&span->property_sampling_priority, &priority_zv); + datadog_assign_variable(&span->property_sampling_priority, &priority_zv); } zend_hash_str_del(ddtrace_property_array(&span->property_meta), ZEND_STRL("_dd.p.ksr")); return; @@ -380,8 +379,7 @@ static void dd_decide_on_sampling(ddtrace_root_span_data *span) { zval priority_zv; ZVAL_LONG(&priority_zv, priority); - ddtrace_assign_variable(&span->property_sampling_priority, &priority_zv); - + datadog_assign_variable(&span->property_sampling_priority, &priority_zv); dd_update_decision_maker_tag(span, mechanism); } @@ -429,7 +427,7 @@ void ddtrace_set_priority_sampling_on_root(zend_long priority, enum dd_sampling_ void ddtrace_set_priority_sampling_on_span(ddtrace_root_span_data *root_span, zend_long priority, enum dd_sampling_mechanism mechanism) { zval zv; ZVAL_LONG(&zv, priority); - ddtrace_assign_variable(&root_span->property_sampling_priority, &zv); + datadog_assign_variable(&root_span->property_sampling_priority, &zv); if (priority != DDTRACE_PRIORITY_SAMPLING_UNKNOWN) { dd_update_decision_maker_tag(root_span, mechanism); @@ -438,13 +436,13 @@ void ddtrace_set_priority_sampling_on_span(ddtrace_root_span_data *root_span, ze } } -DDTRACE_PUBLIC void ddtrace_set_priority_sampling_on_span_zobj(zend_object *root_span, zend_long priority, enum dd_sampling_mechanism mechanism) { +DATADOG_PUBLIC void ddtrace_set_priority_sampling_on_span_zobj(zend_object *root_span, zend_long priority, enum dd_sampling_mechanism mechanism) { assert(root_span->ce == ddtrace_ce_root_span_data); ddtrace_set_priority_sampling_on_span(ROOTSPANDATA(root_span), priority, mechanism); } -DDTRACE_PUBLIC zend_long ddtrace_get_priority_sampling_on_span_zobj(zend_object *root_span) { +DATADOG_PUBLIC zend_long ddtrace_get_priority_sampling_on_span_zobj(zend_object *root_span) { assert(root_span->ce == ddtrace_ce_root_span_data); return zval_get_long(&ROOTSPANDATA(root_span)->property_sampling_priority); diff --git a/ext/priority_sampling/priority_sampling.h b/tracer/priority_sampling/priority_sampling.h similarity index 89% rename from ext/priority_sampling/priority_sampling.h rename to tracer/priority_sampling/priority_sampling.h index a69e6e647ee..747a5f97273 100644 --- a/ext/priority_sampling/priority_sampling.h +++ b/tracer/priority_sampling/priority_sampling.h @@ -2,7 +2,7 @@ #define DDTRACE_PRIORITY_SAMPLING_H #include "../ddtrace.h" -#include "../ddtrace_export.h" +#include #define DDTRACE_PRIORITY_SAMPLING_UNKNOWN (1 << 30) #define DDTRACE_PRIORITY_SAMPLING_UNSET ((1 << 30) + 1) @@ -25,8 +25,8 @@ enum dd_sampling_mechanism { void ddtrace_set_priority_sampling_on_root(zend_long priority, enum dd_sampling_mechanism mechanism); void ddtrace_set_priority_sampling_on_span(ddtrace_root_span_data *root_span, zend_long priority, enum dd_sampling_mechanism mechanism); -DDTRACE_PUBLIC void ddtrace_set_priority_sampling_on_span_zobj(zend_object *root_span, zend_long priority, enum dd_sampling_mechanism mechanism); -DDTRACE_PUBLIC zend_long ddtrace_get_priority_sampling_on_span_zobj(zend_object *root_span); +DATADOG_PUBLIC void ddtrace_set_priority_sampling_on_span_zobj(zend_object *root_span, zend_long priority, enum dd_sampling_mechanism mechanism); +DATADOG_PUBLIC zend_long ddtrace_get_priority_sampling_on_span_zobj(zend_object *root_span); zend_long ddtrace_fetch_priority_sampling_from_span(ddtrace_root_span_data *root_span); zend_long ddtrace_fetch_priority_sampling_from_root(void); void ddtrace_decide_on_closed_span_sampling(ddtrace_span_data *span); diff --git a/ext/profiling.c b/tracer/profiling.c similarity index 90% rename from ext/profiling.c rename to tracer/profiling.c index 3d79c2ca846..ccd675648ab 100644 --- a/ext/profiling.c +++ b/tracer/profiling.c @@ -4,9 +4,9 @@ #include "ddtrace.h" #include "span.h" -ZEND_EXTERN_MODULE_GLOBALS(ddtrace); +ZEND_EXTERN_MODULE_GLOBALS(datadog); -DDTRACE_PUBLIC struct ddtrace_profiling_context ddtrace_get_profiling_context(void) { +DATADOG_PUBLIC struct ddtrace_profiling_context ddtrace_get_profiling_context(void) { struct ddtrace_profiling_context context = {0, 0}; // NOTE: `active_stack->active` may legitimately be NULL during span close (e.g. when closing the last span on a // stack, `ddtrace_close_top_span_without_stack_swap()` updates it before running additional logic that may still diff --git a/ext/profiling.h b/tracer/profiling.h similarity index 86% rename from ext/profiling.h rename to tracer/profiling.h index df59a1b6ac8..5da0caf40e5 100644 --- a/ext/profiling.h +++ b/tracer/profiling.h @@ -6,7 +6,7 @@ #include #include -#include "ddtrace_export.h" +#include struct ddtrace_profiling_context { uint64_t local_root_span_id, span_id; @@ -20,7 +20,7 @@ BEGIN_EXTERN_C() * This needs to be safe to call even if tracing is disabled, but only needs * to support being called from a PHP thread. */ -DDTRACE_PUBLIC struct ddtrace_profiling_context ddtrace_get_profiling_context(void); +DATADOG_PUBLIC struct ddtrace_profiling_context ddtrace_get_profiling_context(void); END_EXTERN_C() diff --git a/ext/random.c b/tracer/random.c similarity index 91% rename from ext/random.c rename to tracer/random.c index cd15c22b1b8..7e06d2662ca 100644 --- a/ext/random.c +++ b/tracer/random.c @@ -12,9 +12,10 @@ #include "configuration.h" #include "ddtrace.h" -#include +#include "span.h" +#include "vendor/mt19937/mt19937-64.h" -ZEND_EXTERN_MODULE_GLOBALS(ddtrace); +ZEND_EXTERN_MODULE_GLOBALS(datadog); static void ddtrace_seed_prng_with_optional_seed(zend_long seedconfig) { unsigned long long seed; @@ -53,12 +54,12 @@ uint64_t ddtrace_parse_userland_span_id(zval *zid) { return (uid && errno == 0) ? uid : 0U; } -ddtrace_trace_id ddtrace_parse_userland_trace_id(zend_string *tid) { - ddtrace_trace_id num = {0}; +datadog_trace_id ddtrace_parse_userland_trace_id(zend_string *tid) { + datadog_trace_id num = {0}; const char *id = ZSTR_VAL(tid); for (size_t i = 0; i < ZSTR_LEN(tid); i++) { if (id[i] < '0' || id[i] > '9') { - return (ddtrace_trace_id){ 0 }; + return (datadog_trace_id){ 0 }; } uint8_t digit = id[i] - '0'; // num * 10 + digit @@ -71,8 +72,8 @@ ddtrace_trace_id ddtrace_parse_userland_trace_id(zend_string *tid) { return num; } -ddtrace_trace_id ddtrace_parse_hex_trace_id(char *trace_id, ssize_t trace_id_len) { - return (ddtrace_trace_id){ +datadog_trace_id ddtrace_parse_hex_trace_id(char *trace_id, ssize_t trace_id_len) { + return (datadog_trace_id){ .high = trace_id_len > 16 ? ddtrace_parse_hex_span_id_str(trace_id, MIN(16, trace_id_len - 16)) : 0, .low = ddtrace_parse_hex_span_id_str(trace_id + MAX(0, trace_id_len - 16), MIN(16, trace_id_len)), }; @@ -121,12 +122,12 @@ uint64_t ddtrace_peek_span_id(void) { return pspan ? SPANDATA(pspan)->span_id : DDTRACE_G(distributed_parent_trace_id); } -ddtrace_trace_id ddtrace_peek_trace_id(void) { +datadog_trace_id ddtrace_peek_trace_id(void) { ddtrace_span_properties *pspan = DDTRACE_G(active_stack) ? DDTRACE_G(active_stack)->active : NULL; return pspan ? SPANDATA(pspan)->root->trace_id : DDTRACE_G(distributed_trace_id); } -int ddtrace_conv10_trace_id(ddtrace_trace_id id, uint8_t reverse[DD_TRACE_MAX_ID_LEN]) { +int ddtrace_conv10_trace_id(datadog_trace_id id, uint8_t reverse[DD_TRACE_MAX_ID_LEN]) { reverse[0] = 0; int i = 0; while (id.high) { diff --git a/ext/random.h b/tracer/random.h similarity index 70% rename from ext/random.h rename to tracer/random.h index d14c971ded9..1f5a2d747a1 100644 --- a/ext/random.h +++ b/tracer/random.h @@ -5,7 +5,7 @@ #include #include -#include "compatibility.h" +#include #include "ddtrace.h" #define DD_TRACE_MAX_ID_LEN 40 // uint64_t -> 2**128 = 20 chars max ID @@ -14,12 +14,12 @@ void ddtrace_seed_prng(void); bool ddtrace_reseed_seed_change(zval *old_value, zval *new_value, zend_string *new_str); uint64_t ddtrace_generate_span_id(void); uint64_t ddtrace_peek_span_id(void); -ddtrace_trace_id ddtrace_peek_trace_id(void); +datadog_trace_id ddtrace_peek_trace_id(void); uint64_t ddtrace_parse_userland_span_id(zval *zid); -ddtrace_trace_id ddtrace_parse_userland_trace_id(zend_string *tid); -ddtrace_trace_id ddtrace_parse_hex_trace_id(char *trace_id, ssize_t trace_id_len); +datadog_trace_id ddtrace_parse_userland_trace_id(zend_string *tid); +datadog_trace_id ddtrace_parse_hex_trace_id(char *trace_id, ssize_t trace_id_len); uint64_t ddtrace_parse_hex_span_id_str(const char *id, size_t len); uint64_t ddtrace_parse_hex_span_id(zval *zid); -int ddtrace_conv10_trace_id(ddtrace_trace_id id, uint8_t reverse[DD_TRACE_MAX_ID_LEN]); +int ddtrace_conv10_trace_id(datadog_trace_id id, uint8_t reverse[DD_TRACE_MAX_ID_LEN]); #endif // DD_RANDOM_H diff --git a/ext/ddshared.c b/tracer/rule_matching.c similarity index 94% rename from ext/ddshared.c rename to tracer/rule_matching.c index 2f6e0ee42c3..07df3ebf4d8 100644 --- a/ext/ddshared.c +++ b/tracer/rule_matching.c @@ -2,16 +2,12 @@ #include #include -#include "ddshared.h" +#include "rule_matching.h" #include "configuration.h" #include "ddtrace.h" #include "uri_normalization.h" -ZEND_EXTERN_MODULE_GLOBALS(ddtrace); - -void ddshared_minit(void) { - ddtrace_set_container_cgroup_path((ddog_CharSlice){ .ptr = DDTRACE_G(cgroup_file), .len = strlen(DDTRACE_G(cgroup_file)) }); -} +ZEND_EXTERN_MODULE_GLOBALS(datadog); bool dd_glob_rule_is_wildcards_only(zval *pattern) { if (Z_TYPE_P(pattern) != IS_STRING || Z_STRLEN_P(pattern) == 0) { diff --git a/ext/ddshared.h b/tracer/rule_matching.h similarity index 89% rename from ext/ddshared.h rename to tracer/rule_matching.h index 84faada9059..8229ec583b1 100644 --- a/ext/ddshared.h +++ b/tracer/rule_matching.h @@ -3,7 +3,6 @@ #include -void ddshared_minit(void); bool dd_rule_matches(zval *pattern, zval *prop, int rulesFormat); bool dd_glob_rule_matches(zval *pattern, zend_string* value); diff --git a/ext/serializer.c b/tracer/serializer.c similarity index 97% rename from ext/serializer.c rename to tracer/serializer.c index bae4bbb12d5..fa132fd0880 100644 --- a/ext/serializer.c +++ b/tracer/serializer.c @@ -17,44 +17,43 @@ #include "zend_variables.h" #include #include -#include -// comment to prevent clang from reordering these headers #include #include #include -#include "process_tags.h" +#include #ifndef _WIN32 #include #else #include #include #endif -#include +#include "vendor/mpack/mpack.h" #include #include #include -#include "compat_string.h" +#include #include "ddtrace.h" #include "engine_api.h" #include "engine_hooks.h" -#include "git.h" +#include "git_metadata.h" #include "ip_extraction.h" #include #include "priority_sampling/priority_sampling.h" #include "span.h" #include "uri_normalization.h" #include "user_request.h" -#include "ddshared.h" -#include "zend_hrtime.h" +#include "rule_matching.h" +#include #include "trace_source.h" #include "exception_serialize.h" -#include "sidecar.h" +#include #include "span_stats.h" #include "trace_filter.h" +#include "configuration.h" -ZEND_EXTERN_MODULE_GLOBALS(ddtrace); +ZEND_EXTERN_MODULE_GLOBALS(datadog); extern void (*profiling_notify_trace_finished)(uint64_t local_root_span_id, zai_str span_type, @@ -593,14 +592,14 @@ static bool dd_set_mapped_peer_service(ddog_SpanBytes *span, zend_string *peer_s void ddtrace_update_root_id_properties(ddtrace_root_span_data *span) { zval zv; - ZVAL_STR(&zv, ddtrace_trace_id_as_hex_string(span->trace_id)); - ddtrace_assign_variable(&span->property_trace_id, &zv); + ZVAL_STR(&zv, datadog_trace_id_as_hex_string(span->trace_id)); + datadog_assign_variable(&span->property_trace_id, &zv); if (span->parent_id) { ZVAL_STR(&zv, ddtrace_span_id_as_string(span->parent_id)); } else { ZVAL_UNDEF(&zv); } - ddtrace_assign_variable(&span->property_parent_id, &zv); + datadog_assign_variable(&span->property_parent_id, &zv); } struct superglob_equiv { @@ -742,7 +741,7 @@ void ddtrace_inherit_span_properties(ddtrace_span_data *span, ddtrace_span_data zval *version; if ((version = zend_hash_str_find(parent_meta, ZEND_STRL("version")))) { zval old = *version; - ddtrace_convert_to_string(version, version); + datadog_convert_to_string(version, version); zval_ptr_dtor(&old); } else { version = &parent->property_version; @@ -754,7 +753,7 @@ void ddtrace_inherit_span_properties(ddtrace_span_data *span, ddtrace_span_data zval *env; if ((env = zend_hash_str_find(parent_meta, ZEND_STRL("env")))) { zval old = *env; - ddtrace_convert_to_string(env, env); + datadog_convert_to_string(env, env); zval_ptr_dtor(&old); } else { env = &parent->property_env; @@ -778,7 +777,7 @@ zend_string *ddtrace_default_service_name(void) { zend_string *ddtrace_active_service_name(void) { ddtrace_span_data *span = ddtrace_active_span(); if (span) { - return ddtrace_convert_to_str(&span->property_service); + return datadog_convert_to_str(&span->property_service); } zend_string *ini_service = get_DD_SERVICE(); if (ZSTR_LEN(ini_service)) { @@ -802,7 +801,7 @@ void ddtrace_set_root_span_properties(ddtrace_root_span_data *span) { * temporary avoids the warning without a performance penalty. */ zend_string *encoded_id = zend_string_alloc(36, false); - ddtrace_format_runtime_id((uint8_t(*)[36])&ZSTR_VAL(encoded_id)); + datadog_format_runtime_id((uint8_t(*)[36])&ZSTR_VAL(encoded_id)); ZSTR_VAL(encoded_id)[36] = '\0'; zval zv; @@ -907,9 +906,9 @@ void ddtrace_set_root_span_properties(ddtrace_root_span_data *span) { ddtrace_set_priority_sampling_on_span(span, DDTRACE_G(default_priority_sampling), DD_MECHANISM_MANUAL); } - if (DDTRACE_G(asm_event_emitted)) { - span->asm_event_emitted = DDTRACE_G(asm_event_emitted); - DDTRACE_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) + if (DATADOG_G(asm_event_emitted)) { + span->asm_event_emitted = DATADOG_G(asm_event_emitted); + 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]; @@ -929,7 +928,7 @@ void ddtrace_set_root_span_properties(ddtrace_root_span_data *span) { zend_hash_str_add_new(metrics, ZEND_STRL("process_id"), &pid); } -static void _dd_serialize_json(zend_array *arr, smart_str *buf, int options) { +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); @@ -987,7 +986,7 @@ static void dd_serialize_array_recursively(ddog_SpanBytes *target, zend_string * ddog_add_span_metrics_zstr(target, str, zval_get_double(value)); } else { zval val_as_string; - ddtrace_convert_to_string(&val_as_string, value); + 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); } @@ -1342,7 +1341,7 @@ ddog_SpanBytes *ddtrace_serialize_span_to_rust_span(ddtrace_span_data *span, ddo zval *http_status_code = zend_hash_str_find(metrics, ZEND_STRL("http.status_code")); if (http_status_code) { zval status_code_as_string; - ddtrace_convert_to_string(&status_code_as_string, http_status_code); + 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")); } @@ -1352,7 +1351,7 @@ ddog_SpanBytes *ddtrace_serialize_span_to_rust_span(ddtrace_span_data *span, ddo zval *http_response_status_code = zend_hash_str_find(metrics, ZEND_STRL("http.response.status_code")); if (http_response_status_code) { zval status_code_as_string; - ddtrace_convert_to_string(&status_code_as_string, http_response_status_code); + 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")); } @@ -1362,9 +1361,9 @@ ddog_SpanBytes *ddtrace_serialize_span_to_rust_span(ddtrace_span_data *span, ddo // Trace-level filter: when stats computation is enabled, drop the span from the // entire pipeline (trace sending + stats) if its trace is filtered. - if (DDTRACE_G(sidecar) && get_DD_TRACE_STATS_COMPUTATION_ENABLED()) { - if (DDTRACE_G(agent_info_reader)) { - ddog_apply_agent_info_concentrator_config(DDTRACE_G(agent_info_reader)); + if (DATADOG_G(sidecar) && get_DD_TRACE_STATS_COMPUTATION_ENABLED()) { + if (DATADOG_G(agent_info_reader)) { + ddog_apply_agent_info_concentrator_config(DATADOG_G(agent_info_reader)); } if (!ddtrace_trace_passes_filter(span)) { ddtrace_free_span_precomputed(&pre); @@ -1377,7 +1376,7 @@ ddog_SpanBytes *ddtrace_serialize_span_to_rust_span(ddtrace_span_data *span, ddo if (ddtrace_span_is_entrypoint_root(span) || is_inferred_span) { int status = SG(sapi_headers).http_response_code; - if (ddtrace_active_sapi == DATADOG_PHP_SAPI_FRANKENPHP && !status) { + if (datadog_active_sapi == DATADOG_PHP_SAPI_FRANKENPHP && !status) { status = pre.has_exception ? 500 : 200; } dd_set_http_error(meta, status, pre.ignore_error); @@ -1534,7 +1533,7 @@ ddog_SpanBytes *ddtrace_serialize_span_to_rust_span(ddtrace_span_data *span, ddo ZEND_HASH_FOREACH_END(); - if (!span_sampling_applied && DDTRACE_G(sidecar) && get_DD_TRACE_STATS_COMPUTATION_ENABLED() && ddog_agent_has_stats_computation()) { + if (!span_sampling_applied && DATADOG_G(sidecar) && get_DD_TRACE_STATS_COMPUTATION_ENABLED() && ddog_agent_has_stats_computation()) { if (inferred_span) { // Inferred span won't be serialized, so feed it to the concentrator here. ddtrace_span_precomputed inferred_pre; @@ -1575,7 +1574,7 @@ ddog_SpanBytes *ddtrace_serialize_span_to_rust_span(ddtrace_span_data *span, ddo ddog_set_span_duration(rust_span, span->duration); if (is_first_span) { - zend_string *process_tags = ddtrace_process_tags_get_serialized(); + zend_string *process_tags = datadog_process_tags_get_serialized(); if (ZSTR_LEN(process_tags)) { ddog_add_str_span_meta_zstr(rust_span, "_dd.tags.process", process_tags); } @@ -1669,7 +1668,7 @@ ddog_SpanBytes *ddtrace_serialize_span_to_rust_span(ddtrace_span_data *span, ddo zend_object *current_exception = EG(exception); EG(exception) = NULL; smart_str buf = {0}; - _dd_serialize_json(span_links, &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; @@ -1680,7 +1679,7 @@ ddog_SpanBytes *ddtrace_serialize_span_to_rust_span(ddtrace_span_data *span, ddo zend_object *current_exception = EG(exception); EG(exception) = NULL; smart_str buf = {0}; - _dd_serialize_json(span_events, &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; @@ -1688,15 +1687,15 @@ ddog_SpanBytes *ddtrace_serialize_span_to_rust_span(ddtrace_span_data *span, ddo zval *git_metadata = &span->root->property_git_metadata; if (git_metadata && Z_TYPE_P(git_metadata) == IS_OBJECT) { - ddtrace_git_metadata *metadata = (ddtrace_git_metadata *)Z_OBJ_P(git_metadata); + 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 = ddtrace_convert_to_str(&metadata->property_commit); + 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); zend_string_release(commit_sha); } if (Z_TYPE(metadata->property_repository) == IS_STRING) { - zend_string *repository_url = ddtrace_convert_to_str(&metadata->property_repository); + 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); zend_string_release(repository_url); } @@ -1765,9 +1764,9 @@ ddog_SpanBytes *ddtrace_serialize_span_to_rust_span(ddtrace_span_data *span, ddo // Add _dd.base_service if service name differs from mapped root service name. zval prop_service_as_string; - ddtrace_convert_to_string(&prop_service_as_string, &span->property_service); + datadog_convert_to_string(&prop_service_as_string, &span->property_service); zval prop_root_service_as_string; - ddtrace_convert_to_string(&prop_root_service_as_string, &span->root->property_service); + datadog_convert_to_string(&prop_root_service_as_string, &span->root->property_service); zval *new_root_name = zend_hash_find(get_DD_SERVICE_MAPPING(), Z_STR(prop_root_service_as_string)); if (new_root_name) { zend_string_release(Z_STR(prop_root_service_as_string)); @@ -1779,7 +1778,7 @@ ddog_SpanBytes *ddtrace_serialize_span_to_rust_span(ddtrace_span_data *span, ddo zend_string_release(Z_STR(prop_root_service_as_string)); zend_string_release(Z_STR(prop_service_as_string)); - if (DDTRACE_G(sidecar) && get_DD_TRACE_STATS_COMPUTATION_ENABLED() && ddog_agent_has_stats_computation()) { + if (DATADOG_G(sidecar) && get_DD_TRACE_STATS_COMPUTATION_ENABLED() && ddog_agent_has_stats_computation()) { ddtrace_feed_span_to_concentrator(span, &pre); } @@ -1804,7 +1803,7 @@ ddog_SpanBytes *ddtrace_serialize_span_to_rust_span(ddtrace_span_data *span, ddo } } - if (DDTRACE_G(sidecar) && get_DD_TRACE_STATS_COMPUTATION_ENABLED() && !is_inferred_span) { + if (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; diff --git a/ext/serializer.h b/tracer/serializer.h similarity index 100% rename from ext/serializer.h rename to tracer/serializer.h diff --git a/ext/span.c b/tracer/span.c similarity index 97% rename from ext/span.c rename to tracer/span.c index 80b43cebba5..43636e9bc45 100644 --- a/ext/span.c +++ b/tracer/span.c @@ -4,21 +4,21 @@ #include "components-rs/sidecar.h" #include "priority_sampling/priority_sampling.h" #include -#include "zend_hrtime.h" +#include #include "auto_flush.h" -#include "compat_string.h" #include "configuration.h" +#include "tracer_telemetry.h" #include "ddtrace.h" #include #include "random.h" #include "serializer.h" -#include "telemetry.h" -#include "ext/standard/php_string.h" +#include +#include #include #include "user_request.h" #include "zend_types.h" -#include "sidecar.h" +#include #include "sandbox/sandbox.h" #include "hook/uhook.h" #include "trace_source.h" @@ -29,7 +29,7 @@ #define USE_REALTIME_CLOCK 0 #define USE_MONOTONIC_CLOCK 1 -ZEND_EXTERN_MODULE_GLOBALS(ddtrace); +ZEND_EXTERN_MODULE_GLOBALS(datadog); static void dd_reset_span_counters(void) { DDTRACE_G(open_spans_count) = 0; @@ -206,7 +206,7 @@ ddtrace_inferred_span_data *ddtrace_open_inferred_span(ddtrace_inferred_proxy_re if (result->domain) { ZVAL_STR_COPY(&zv, result->domain); - ddtrace_assign_variable(&span->property_service, &zv); + datadog_assign_variable(&span->property_service, &zv); } else { ZVAL_COPY(&span->property_service, &root->property_service); // Fall back to root service name } @@ -285,7 +285,7 @@ ddtrace_span_data *ddtrace_open_span(enum ddtrace_span_dataype type) { root->trace_id = DDTRACE_G(distributed_trace_id); root->parent_id = DDTRACE_G(distributed_parent_trace_id); } else { - root->trace_id = (ddtrace_trace_id) { + root->trace_id = (datadog_trace_id) { .low = span->span_id, .time = get_DD_TRACE_128_BIT_TRACEID_GENERATION_ENABLED() ? span->start / ZEND_NANO_IN_SEC : 0, }; @@ -313,7 +313,7 @@ ddtrace_span_data *ddtrace_open_span(enum ddtrace_span_dataype type) { LOG(SPAN_TRACE, "Starting new root span: trace_id=%s, span_id=%" PRIu64 ", parent_id=%" PRIu64 ", SpanStack=%d, parent_SpanStack=%d", Z_STRVAL(root->property_trace_id), span->span_id, root->parent_id, root->stack->std.handle, root->stack->parent_stack->std.handle); if (ddtrace_span_is_entrypoint_root(span)) { - ddtrace_sidecar_submit_root_span_data(); + datadog_sidecar_submit_root_span_data(); } } else { LOG(SPAN_TRACE, "Starting new span: trace_id=%s, span_id=%" PRIu64 ", parent_id=%" PRIu64 ", SpanStack=%d", Z_STRVAL(span->root->property_trace_id), span->span_id, SPANDATA(span->parent)->span_id, span->stack->std.handle); @@ -659,7 +659,7 @@ void ddtrace_push_root_span(void) { ddtrace_observe_opened_span(span); } -DDTRACE_PUBLIC zend_object *ddtrace_get_root_span() +DATADOG_PUBLIC zend_object *ddtrace_get_root_span() { if (!DDTRACE_G(active_stack)) { return NULL; @@ -729,7 +729,7 @@ void ddtrace_close_stack_userland_spans_until(ddtrace_span_data *until) { LOG(ERROR, "Found internal span data while closing userland spans"); } - zend_string *name = ddtrace_convert_to_str(&span->property_name); + zend_string *name = datadog_convert_to_str(&span->property_name); LOG(WARN, "Found unfinished span while automatically closing spans with name '%s'", ZSTR_VAL(name)); zend_string_release(name); @@ -794,7 +794,7 @@ static void dd_mark_closed_spans_flushable(ddtrace_span_stack *stack) { 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))) { zval priority; ZVAL_LONG(&priority, PRIORITY_SAMPLING_AUTO_REJECT); - ddtrace_assign_variable(&root_span->property_sampling_priority, &priority); + datadog_assign_variable(&root_span->property_sampling_priority, &priority); root_span->explicit_sampling_priority = true; } } @@ -890,7 +890,7 @@ void ddtrace_close_top_span_without_stack_swap(ddtrace_span_data *span) { // Enable resource renaming if: // - DD_TRACE_RESOURCE_RENAMING_ENABLED is explicitly set to true, OR // - DD_APPSEC_ENABLED is true and DD_TRACE_RESOURCE_RENAMING_ENABLED is not explicitly set - bool resource_renaming_at_default = zai_config_memoized_entries[DDTRACE_CONFIG_DD_TRACE_RESOURCE_RENAMING_ENABLED].name_index == ZAI_CONFIG_ORIGIN_DEFAULT; + bool resource_renaming_at_default = zai_config_memoized_entries[DATADOG_CONFIG_DD_TRACE_RESOURCE_RENAMING_ENABLED].name_index == ZAI_CONFIG_ORIGIN_DEFAULT; bool enable_resource_renaming = resource_renaming_at_default ? get_DD_APPSEC_ENABLED() : get_DD_TRACE_RESOURCE_RENAMING_ENABLED(); if (enable_resource_renaming) { ddtrace_maybe_add_guessed_endpoint_tag(ROOTSPANDATA(&span->std)); @@ -1153,7 +1153,7 @@ void ddtrace_serialize_closed_spans_with_cycle(ddog_TracesBytes *traces, bool fa zend_string *ddtrace_span_id_as_string(uint64_t id) { return zend_strpprintf(0, "%" PRIu64, id); } -zend_string *ddtrace_trace_id_as_string(ddtrace_trace_id id) { +zend_string *datadog_trace_id_as_string(datadog_trace_id id) { uint8_t reverse[DD_TRACE_MAX_ID_LEN]; int len = ddtrace_conv10_trace_id(id, reverse); zend_string *str = zend_string_alloc(len, 0); @@ -1169,8 +1169,14 @@ zend_string *ddtrace_span_id_as_hex_string(uint64_t id) { return str; } -zend_string *ddtrace_trace_id_as_hex_string(ddtrace_trace_id id) { +zend_string *datadog_trace_id_as_hex_string(datadog_trace_id id) { zend_string *str = zend_string_alloc(32, 0); snprintf(ZSTR_VAL(str), 33, "%016" PRIx64 "%016" PRIx64, id.high, id.low); return str; } + +void ddtrace_populate_root_span_data(ddtrace_span_data *span, zend_string **service, zend_string **env, zend_string **version) { + *service = datadog_convert_to_str(&span->property_service); + *env = datadog_convert_to_str(&span->property_env); + *version = datadog_convert_to_str(&span->property_version); +} \ No newline at end of file diff --git a/ext/span.h b/tracer/span.h similarity index 96% rename from ext/span.h rename to tracer/span.h index 64be73a1330..53b33dc2f5f 100644 --- a/ext/span.h +++ b/tracer/span.h @@ -6,9 +6,9 @@ #include #include -#include "compatibility.h" +#include #include "ddtrace.h" -#include "ddtrace_export.h" +#include #include "priority_sampling/priority_sampling.h" #include "inferred_proxy_headers.h" @@ -119,7 +119,7 @@ static inline ddtrace_inferred_span_data *INFERRED_SPANDATA(zend_object *obj) { } struct ddtrace_root_span_data { - ddtrace_trace_id trace_id; + datadog_trace_id trace_id; uint64_t parent_id; ddtrace_rule_result sampling_rule; bool explicit_sampling_priority; @@ -211,7 +211,7 @@ struct ddtrace_exception_span_event { zval property_exception; }; -struct ddtrace_git_metadata { +struct datadog_git_metadata { union { zend_object std; struct { @@ -246,7 +246,7 @@ ddtrace_span_data *ddtrace_alloc_execute_data_span(zend_ulong invocation, zend_e void ddtrace_clear_execute_data_span(zend_ulong invocation, bool keep); // Note that this function is used externally by the appsec extension. -DDTRACE_PUBLIC zend_object *ddtrace_get_root_span(void); +DATADOG_PUBLIC zend_object *ddtrace_get_root_span(void); uint64_t ddtrace_nanoseconds_realtime(void); void dd_trace_stop_span_time(ddtrace_span_data *span); @@ -262,9 +262,9 @@ 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); zend_string *ddtrace_span_id_as_string(uint64_t id); -zend_string *ddtrace_trace_id_as_string(ddtrace_trace_id id); +zend_string *datadog_trace_id_as_string(datadog_trace_id id); zend_string *ddtrace_span_id_as_hex_string(uint64_t id); -zend_string *ddtrace_trace_id_as_hex_string(ddtrace_trace_id id); +zend_string *datadog_trace_id_as_hex_string(datadog_trace_id id); bool ddtrace_span_alter_root_span_config(zval *old_value, zval *new_value, zend_string *new_str); diff --git a/ext/span_stats.c b/tracer/span_stats.c similarity index 95% rename from ext/span_stats.c rename to tracer/span_stats.c index e3290aff41a..cfef8dc83bf 100644 --- a/ext/span_stats.c +++ b/tracer/span_stats.c @@ -11,13 +11,14 @@ #include #include -#include "compat_string.h" +#include +#include #include "configuration.h" #include "ddtrace.h" -#include "sidecar.h" +#include #include "span.h" -ZEND_EXTERN_MODULE_GLOBALS(ddtrace); +ZEND_EXTERN_MODULE_GLOBALS(datadog); // gRPC status-code meta keys in the same order as PHP_GRPC_KEY_COUNT / grpc_meta[] in stats.rs. static const char *const GRPC_META_KEYS[] = { @@ -45,12 +46,12 @@ void ddtrace_precompute_span(ddtrace_span_data *span, ddtrace_span_precomputed * pre->service_from_meta = (service_name_meta != NULL); pre->service = NULL; if (service_name_meta) { - pre->service = ddtrace_convert_to_str(service_name_meta); + pre->service = datadog_convert_to_str(service_name_meta); } else { zval *prop_service = &span->property_service; ZVAL_DEREF(prop_service); if (Z_TYPE_P(prop_service) > IS_NULL) { - pre->service = ddtrace_convert_to_str(prop_service); + pre->service = datadog_convert_to_str(prop_service); } } if (pre->service) { @@ -71,7 +72,7 @@ void ddtrace_precompute_span(ddtrace_span_data *span, ddtrace_span_precomputed * zval *prop_name = &span->property_name; ZVAL_DEREF(prop_name); if (Z_TYPE_P(prop_name) > IS_NULL) { - pre->name = ddtrace_convert_to_str(prop_name); + pre->name = datadog_convert_to_str(prop_name); } pre->name_from_meta = false; } @@ -81,13 +82,13 @@ void ddtrace_precompute_span(ddtrace_span_data *span, ddtrace_span_precomputed * pre->resource_from_meta = (resource_name != NULL); pre->resource = NULL; if (resource_name) { - pre->resource = ddtrace_convert_to_str(resource_name); + pre->resource = datadog_convert_to_str(resource_name); } else { zval *prop_resource = &span->property_resource; ZVAL_DEREF(prop_resource); if (Z_TYPE_P(prop_resource) > IS_FALSE && (Z_TYPE_P(prop_resource) != IS_STRING || Z_STRLEN_P(prop_resource) > 0)) { - pre->resource = ddtrace_convert_to_str(prop_resource); + pre->resource = datadog_convert_to_str(prop_resource); } } if (!pre->resource && pre->name) { @@ -101,7 +102,7 @@ void ddtrace_precompute_span(ddtrace_span_data *span, ddtrace_span_precomputed * zval *prop_type = span_type ? span_type : &span->property_type; ZVAL_DEREF(prop_type); if (Z_TYPE_P(prop_type) > IS_NULL) { - pre->type = ddtrace_convert_to_str(prop_type); + pre->type = datadog_convert_to_str(prop_type); } // Env: prefer deprecated meta["env"] (with a warning), else span property. @@ -110,7 +111,7 @@ void ddtrace_precompute_span(ddtrace_span_data *span, ddtrace_span_precomputed * 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 = ddtrace_convert_to_str(meta_env); + zend_string *str = datadog_convert_to_str(meta_env); if (ZSTR_LEN(str) > 0) { pre->env = str; } else { @@ -121,7 +122,7 @@ void ddtrace_precompute_span(ddtrace_span_data *span, ddtrace_span_precomputed * zval *prop_env = &span->property_env; ZVAL_DEREF(prop_env); if (Z_TYPE_P(prop_env) > IS_NULL) { - zend_string *str = ddtrace_convert_to_str(prop_env); + zend_string *str = datadog_convert_to_str(prop_env); if (ZSTR_LEN(str) > 0) { pre->env = str; } else { @@ -136,7 +137,7 @@ void ddtrace_precompute_span(ddtrace_span_data *span, ddtrace_span_precomputed * 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 = ddtrace_convert_to_str(meta_version); + zend_string *str = datadog_convert_to_str(meta_version); if (ZSTR_LEN(str) > 0) { pre->version = str; } else { @@ -147,7 +148,7 @@ void ddtrace_precompute_span(ddtrace_span_data *span, ddtrace_span_precomputed * zval *prop_version = &span->property_version; ZVAL_DEREF(prop_version); if (Z_TYPE_P(prop_version) > IS_NULL) { - zend_string *str = ddtrace_convert_to_str(prop_version); + zend_string *str = datadog_convert_to_str(prop_version); if (ZSTR_LEN(str) > 0) { pre->version = str; } else { @@ -397,7 +398,7 @@ void ddtrace_feed_span_to_concentrator(ddtrace_span_data *span, const ddtrace_sp ddtrace_concentrator_cb_data data = { .span = span, .pre = pre, .needs_ipc = false }; ddog_span_concentrator_with(env_slice, version_slice, service_slice, ddtrace_span_concentrator_feed_cb, &data); - if (data.needs_ipc && DDTRACE_G(sidecar)) { - ddog_sidecar_add_php_span_to_concentrator(&DDTRACE_G(sidecar), env_slice, version_slice, &data.ipc_stats); + if (data.needs_ipc && DATADOG_G(sidecar)) { + ddog_sidecar_add_php_span_to_concentrator(&DATADOG_G(sidecar), env_slice, version_slice, &data.ipc_stats); } } diff --git a/ext/span_stats.h b/tracer/span_stats.h similarity index 100% rename from ext/span_stats.h rename to tracer/span_stats.h diff --git a/ext/standalone_limiter.c b/tracer/standalone_limiter.c similarity index 87% rename from ext/standalone_limiter.c rename to tracer/standalone_limiter.c index db8b02a58e0..c83030145b0 100644 --- a/ext/standalone_limiter.c +++ b/tracer/standalone_limiter.c @@ -9,8 +9,9 @@ #include #include "ddtrace.h" -#include "sidecar.h" -#include "zend_hrtime.h" +#include +#include +#include typedef struct { /* limit from configuration DD_TRACE_RATE_LIMIT */ @@ -29,8 +30,8 @@ void ddtrace_standalone_limiter_create() { ddog_ShmHandle *shm; size_t _size; - if (ddtrace_ffi_try("Failed allocating shared memory", ddog_alloc_anon_shm_handle(limit, &shm))) { - if (!ddtrace_ffi_try("Failed mapping shared memory", ddog_map_shm(shm, &dd_limiter_mapped_shm, (void **)&dd_limiter, &_size))) { + if (datadog_ffi_try("Failed allocating shared memory", ddog_alloc_anon_shm_handle(limit, &shm))) { + if (!datadog_ffi_try("Failed mapping shared memory", ddog_map_shm(shm, &dd_limiter_mapped_shm, (void **)&dd_limiter, &_size))) { dd_limiter = &dd_local_limiter; ddog_drop_anon_shm_handle(shm); } diff --git a/ext/standalone_limiter.h b/tracer/standalone_limiter.h similarity index 100% rename from ext/standalone_limiter.h rename to tracer/standalone_limiter.h diff --git a/ext/trace_filter.c b/tracer/trace_filter.c similarity index 97% rename from ext/trace_filter.c rename to tracer/trace_filter.c index c2659a8cc8d..51425af0a58 100644 --- a/ext/trace_filter.c +++ b/tracer/trace_filter.c @@ -9,14 +9,15 @@ #include #include "ddtrace.h" -#include "sidecar.h" +#include +#include #include "span.h" #ifndef _WIN32 #include #endif -ZEND_EXTERN_MODULE_GLOBALS(ddtrace); +ZEND_EXTERN_MODULE_GLOBALS(datadog); // Lookup callback for ddog_check_stats_trace_filter. // Returns null when the key is not found anywhere on the span. diff --git a/ext/trace_filter.h b/tracer/trace_filter.h similarity index 100% rename from ext/trace_filter.h rename to tracer/trace_filter.h diff --git a/ext/trace_source.c b/tracer/trace_source.c similarity index 89% rename from ext/trace_source.c rename to tracer/trace_source.c index 4e70987a855..4873ae766ff 100644 --- a/ext/trace_source.c +++ b/tracer/trace_source.c @@ -2,10 +2,11 @@ #include "configuration.h" #include "ddtrace.h" +#include "span.h" #include "priority_sampling/priority_sampling.h" #include "tracer_tag_propagation/tracer_tag_propagation.h" -ZEND_EXTERN_MODULE_GLOBALS(ddtrace); +ZEND_EXTERN_MODULE_GLOBALS(datadog); #define TRACE_SOURCE_APM (1 << 0) #define TRACE_SOURCE_ASM (1 << 1) @@ -13,10 +14,10 @@ ZEND_EXTERN_MODULE_GLOBALS(ddtrace); #define TRACE_SOURCE_DJM (1 << 3) #define TRACE_SOURCE_DBM (1 << 4) -static zend_string *_dd_tag_p_ts; +static zend_string *dd_tag_p_ts; void ddtrace_trace_source_minit() { - _dd_tag_p_ts = zend_string_init_interned(ZEND_STRL(DD_P_TS_KEY), 1 /* permanent */); + dd_tag_p_ts = zend_string_init_interned(ZEND_STRL(DD_P_TS_KEY), 1 /* permanent */); } zend_string *ddtrace_trace_source_get_encoded(uint32_t source) { @@ -31,7 +32,7 @@ static void ddtrace_trace_source_add_propagated_tag(zend_string *encoded) { } zval ts_encoded_zv; ZVAL_STR(&ts_encoded_zv, encoded); - ddtrace_add_propagated_tag(_dd_tag_p_ts, &ts_encoded_zv); + ddtrace_add_propagated_tag(dd_tag_p_ts, &ts_encoded_zv); zend_string_release(encoded); } diff --git a/ext/trace_source.h b/tracer/trace_source.h similarity index 100% rename from ext/trace_source.h rename to tracer/trace_source.h diff --git a/tracer/tracer_api.h b/tracer/tracer_api.h new file mode 100644 index 00000000000..acbf9d36c7c --- /dev/null +++ b/tracer/tracer_api.h @@ -0,0 +1,41 @@ +#include +#include + +// Primary lifecycle +int ddtrace_startup(zend_extension *extension); +void ddtrace_shutdown(zend_extension *extension); +void ddtrace_activate_once(void); +void ddtrace_activate_early(void); +void ddtrace_activate_late(void); +void ddtrace_ginit(zend_datadog_globals *ddtrace_globals); +void ddtrace_gshutdown(zend_datadog_globals *datadog_globals); +void ddtrace_pre_config_minit(void); +void ddtrace_minit_early(int module_number); +void ddtrace_minit_late(void); +void ddtrace_mshutdown(void); +void ddtrace_first_rinit(void); +void ddtrace_rinit(void); +void ddtrace_rshutdown(bool fast_shutdown); +void ddtrace_post_deactivate(void); + +// fork handling +void ddtrace_internal_handle_fork(void); +void ddtrace_internal_handle_prefork(void); +void ddtrace_internal_handle_postfork(void); + +// Other lifecycle stuff +void ddtrace_telemetry_first_init(void); +void ddtrace_telemetry_register_services(ddog_SidecarTransport **sidecar); +void ddtrace_telemetry_finalize(void); + +// Other +void ddtrace_populate_root_span_data(ddtrace_span_data *span, zend_string **service, zend_string **env, zend_string **version); +extern ddog_LiveDebuggerSetup ddtrace_live_debugger_setup; + +#ifdef DDTRACE +ddog_DynamicInstrumentationConfigState ddtrace_dynamic_instrumentation_state(void); +#else +static inline ddog_DynamicInstrumentationConfigState ddtrace_dynamic_instrumentation_state(void) { + return DDOG_DYNAMIC_INSTRUMENTATION_CONFIG_STATE_DISABLED; +} +#endif diff --git a/tracer/tracer_otel_config.c b/tracer/tracer_otel_config.c new file mode 100644 index 00000000000..1544790f775 --- /dev/null +++ b/tracer/tracer_otel_config.c @@ -0,0 +1,73 @@ +#include "tracer_otel_config.h" +#include +#include +#include "ddtrace.h" +#include +#include +#include +#include "configuration.h" + +ZEND_EXTERN_MODULE_GLOBALS(datadog); + +bool ddtrace_conf_otel_propagators(zai_env_buffer *buf, bool pre_rinit) { + ZAI_ENV_BUFFER_INIT(local, ZAI_ENV_MAX_BUFSIZ); + if (!datadog_get_otel_value((zai_str)ZAI_STRL("OTEL_PROPAGATORS"), &local, pre_rinit)) { + return false; + } + memcpy(buf->ptr, local.ptr, strlen(local.ptr) + 1); + char *off = (char *)zend_memnstr(buf->ptr, ZEND_STRL("b3"), buf->ptr + strlen(buf->ptr)); + if (off && (!off[strlen("b3")] || off[strlen("b3")] == ',') && strlen(buf->ptr) < buf->len - 100) { + memmove(off + strlen("b3 single header"), off + strlen("b3"), buf->ptr + strlen(buf->ptr) - (off + strlen("b3")) + 1); + memcpy(off, "b3 single header", strlen("b3 single header")); + } + return true; +} + +bool ddtrace_conf_otel_sample_rate(zai_env_buffer *buf, bool pre_rinit) { + if (!datadog_get_otel_value((zai_str)ZAI_STRL("OTEL_TRACES_SAMPLER"), buf, pre_rinit)) { + return false; + } + + if (strcmp(buf->ptr, "always_on") == 0 || strcmp(buf->ptr, "parentbased_always_on") == 0) { + buf->ptr = "1"; buf->len = 1; + return true; + } + if (strcmp(buf->ptr, "always_off") == 0 || strcmp(buf->ptr, "parentbased_always_off") == 0) { + buf->ptr = "0"; buf->len = 1; + return true; + } + if (strcmp(buf->ptr, "traceidratio") == 0 || strcmp(buf->ptr, "parentbased_traceidratio") == 0) { + if (datadog_get_otel_value((zai_str)ZAI_STRL("OTEL_TRACES_SAMPLER_ARG"), buf, pre_rinit)) { + return true; + } + LOG_ONCE(WARN, "OTEL_TRACES_SAMPLER is %s, but is missing OTEL_TRACES_SAMPLER_ARG", buf->ptr); + } else { + LOG_ONCE(WARN, "OTEL_TRACES_SAMPLER has invalid value: %s", buf->ptr); + } + datadog_report_otel_cfg_telemetry_invalid("otel_traces_sampler", "dd_trace_sample_rate", pre_rinit); + return false; +} + +bool ddtrace_conf_otel_traces_exporter(zai_env_buffer *buf, bool pre_rinit) { + if (datadog_get_otel_value((zai_str)ZAI_STRL("OTEL_TRACES_EXPORTER"), buf, pre_rinit)) { + if (strcmp(buf->ptr, "none") == 0) { + buf->ptr = "0"; buf->len = 1; + return true; + } + LOG_ONCE(WARN, "OTEL_TRACES_EXPORTER has invalid value: %s", buf->ptr); + datadog_report_otel_cfg_telemetry_invalid("otel_traces_exporter", "dd_trace_enabled", pre_rinit); + } + return false; +} + +bool ddtrace_conf_otel_metrics_exporter(zai_env_buffer *buf, bool pre_rinit) { + if (datadog_get_otel_value((zai_str)ZAI_STRL("OTEL_METRICS_EXPORTER"), buf, pre_rinit)) { + if (strcmp(buf->ptr, "none") == 0) { + buf->ptr = "0"; buf->len = 1; + return true; + } + LOG_ONCE(WARN, "OTEL_METRICS_EXPORTER has invalid value: %s", buf->ptr); + datadog_report_otel_cfg_telemetry_invalid("otel_metrics_exporter", "dd_integration_metrics_enabled", pre_rinit); + } + return false; +} diff --git a/tracer/tracer_otel_config.h b/tracer/tracer_otel_config.h new file mode 100644 index 00000000000..e7d92576ae5 --- /dev/null +++ b/tracer/tracer_otel_config.h @@ -0,0 +1,20 @@ +#ifndef DD_OTEL_CONFIG_H +#define DD_OTEL_CONFIG_H + +#include + +void datadog_report_otel_cfg_telemetry_invalid(const char *otel_cfg, const char *dd_cfg, bool pre_rinit); +bool datadog_get_otel_value(zai_str str, zai_env_buffer *buf, bool pre_rinit); + + +bool ddtrace_conf_otel_resource_attributes_env(zai_env_buffer *buf, bool pre_rinit); +bool ddtrace_conf_otel_resource_attributes_version(zai_env_buffer *buf, bool pre_rinit); +bool ddtrace_conf_otel_service_name(zai_env_buffer *buf, bool pre_rinit); +bool ddtrace_conf_otel_log_level(zai_env_buffer *buf, bool pre_rinit); +bool ddtrace_conf_otel_propagators(zai_env_buffer *buf, bool pre_rinit); +bool ddtrace_conf_otel_sample_rate(zai_env_buffer *buf, bool pre_rinit); +bool ddtrace_conf_otel_traces_exporter(zai_env_buffer *buf, bool pre_rinit); +bool ddtrace_conf_otel_metrics_exporter(zai_env_buffer *buf, bool pre_rinit); +bool ddtrace_conf_otel_resource_attributes_tags(zai_env_buffer *buf, bool pre_rinit); + +#endif // DD_OTEL_CONFIG_H diff --git a/tracer/tracer_startup_logging.c b/tracer/tracer_startup_logging.c new file mode 100644 index 00000000000..b64530d9ff6 --- /dev/null +++ b/tracer/tracer_startup_logging.c @@ -0,0 +1,99 @@ +#include "tracer_startup_logging.h" +#include + +#include +#include +#include +#include + +#include + +#include "configuration.h" +#include "integrations/integrations.h" +#include + +#include + +void ddtrace_populate_startup_config(HashTable *ht) { + // Cross-language tracer values + + dd_add_assoc_bool(ht, ZEND_STRL("analytics_enabled"), get_DD_TRACE_ANALYTICS_ENABLED()); + dd_add_assoc_double(ht, ZEND_STRL("sample_rate"), get_DD_TRACE_SAMPLE_RATE()); + dd_add_assoc_array(ht, ZEND_STRL("sampling_rules"), dd_array_copy(get_DD_TRACE_SAMPLING_RULES())); + // TODO Add integration-specific config: integration__analytics_enabled, + // integration__sample_rate, integrations_loaded + dd_add_assoc_array(ht, ZEND_STRL("tags"), dd_array_copy(get_DD_TAGS())); + dd_add_assoc_array(ht, ZEND_STRL("service_mapping"), dd_array_copy(get_DD_SERVICE_MAPPING())); + // "log_injection_enabled" N/A for PHP + // "runtime_metrics_enabled" N/A for PHP + // "configuration_file" N/A for PHP + // "vm" N/A for PHP + // "partial_flushing_enabled" N/A for PHP + dd_add_assoc_bool(ht, ZEND_STRL("distributed_tracing_enabled"), get_DD_DISTRIBUTED_TRACING()); + // "logs_correlation_enabled" N/A for PHP + // "profiling_enabled" N/A for PHP + dd_add_assoc_zstring(ht, ZEND_STRL("dd_version"), zend_string_copy(get_DD_VERSION())); + // "health_metrics_enabled" N/A for PHP + dd_add_assoc_zstring(ht, ZEND_STRL("architecture"), php_get_uname('m')); + dd_add_assoc_bool(ht, ZEND_STRL("instrumentation_telemetry_enabled"), get_global_DD_INSTRUMENTATION_TELEMETRY_ENABLED()); + + // PHP-specific values + dd_add_assoc_string(ht, ZEND_STRL("sapi"), sapi_module.name); + dd_add_assoc_zstring(ht, ZEND_STRL("datadog.trace.sources_path"), + zend_string_copy(get_DD_TRACE_SOURCES_PATH())); + dd_add_assoc_bool(ht, ZEND_STRL("open_basedir_configured"), dd_ini_is_set(ZEND_STRL("open_basedir"))); + dd_add_assoc_zstring(ht, ZEND_STRL("uri_fragment_regex"), + dd_implode_keys(get_DD_TRACE_RESOURCE_URI_FRAGMENT_REGEX())); + dd_add_assoc_zstring(ht, ZEND_STRL("uri_mapping_incoming"), + dd_implode_keys(get_DD_TRACE_RESOURCE_URI_MAPPING_INCOMING())); + dd_add_assoc_zstring(ht, ZEND_STRL("uri_mapping_outgoing"), + dd_implode_keys(get_DD_TRACE_RESOURCE_URI_MAPPING_OUTGOING())); + dd_add_assoc_bool(ht, ZEND_STRL("auto_flush_enabled"), get_DD_TRACE_AUTO_FLUSH_ENABLED()); + dd_add_assoc_bool(ht, ZEND_STRL("generate_root_span"), get_DD_TRACE_GENERATE_ROOT_SPAN()); + dd_add_assoc_bool(ht, ZEND_STRL("http_client_split_by_domain"), get_DD_TRACE_HTTP_CLIENT_SPLIT_BY_DOMAIN()); + dd_add_assoc_bool(ht, ZEND_STRL("measure_compile_time"), get_DD_TRACE_MEASURE_COMPILE_TIME()); + dd_add_assoc_bool(ht, ZEND_STRL("report_hostname_on_root_span"), get_DD_TRACE_REPORT_HOSTNAME()); + dd_add_assoc_zstring(ht, ZEND_STRL("traced_internal_functions"), + dd_implode_keys(get_DD_TRACE_TRACED_INTERNAL_FUNCTIONS())); + dd_add_assoc_bool(ht, ZEND_STRL("enabled_from_env"), get_DD_TRACE_ENABLED()); + dd_add_assoc_string(ht, ZEND_STRL("opcache.file_cache"), dd_get_ini(ZEND_STRL("opcache.file_cache"))); + dd_add_assoc_bool(ht, ZEND_STRL("sidecar_trace_sender"), get_global_DD_TRACE_SIDECAR_TRACE_SENDER()); + dd_add_assoc_bool(ht, ZEND_STRL("dynamic_instrumentation_enabled"), get_global_DD_DYNAMIC_INSTRUMENTATION_ENABLED()); + dd_add_assoc_bool(ht, ZEND_STRL("exception_replay_enabled"), get_global_DD_EXCEPTION_REPLAY_ENABLED()); +} + +static bool dd_file_exists(const char *file) { + if (!strlen(file)) { + return false; + } + return (VCWD_ACCESS(file, R_OK) == 0); +} + +static bool dd_open_basedir_allowed(const char *file) { return (php_check_open_basedir_ex(file, 0) != -1); } + +void ddtrace_startup_diagnostics(HashTable *ht, bool quick) { + //dd_add_assoc_string(ht, ZEND_STRL("service_mapping_error"), ""); // TODO Parse at C level + + const char *sources = ZSTR_VAL(get_DD_TRACE_SOURCES_PATH()); + bool sources_exist = dd_file_exists(sources); + if (!sources_exist) { + dd_add_assoc_bool(ht, ZEND_STRL("datadog.trace.sources_path_reachable"), sources_exist); + } else { + bool sources_allowed = dd_open_basedir_allowed(sources); + if (!sources_allowed) { + dd_add_assoc_bool(ht, ZEND_STRL("open_basedir_sources_allowed"), sources_allowed); + } + } + + //dd_add_assoc_string(ht, ZEND_STRL("uri_fragment_regex_error"), ""); // TODO Parse at C level + //dd_add_assoc_string(ht, ZEND_STRL("uri_mapping_incoming_error"), ""); // TODO Parse at C level + //dd_add_assoc_string(ht, ZEND_STRL("uri_mapping_outgoing_error"), ""); // TODO Parse at C level +} + + +// Only show startup logs on the first request +void ddtrace_startup_logging_extra(void (*log)(const char *format, ...)) { + if (get_DD_OPENAI_LOGS_ENABLED()) { + log("Note that DD_OPENAI_LOGS_ENABLED=1 may be changed or removed in any release."); + } +} diff --git a/tracer/tracer_startup_logging.h b/tracer/tracer_startup_logging.h new file mode 100644 index 00000000000..aa2c432ab7e --- /dev/null +++ b/tracer/tracer_startup_logging.h @@ -0,0 +1,12 @@ +#ifndef DD_TRACE_STARTUP_LOGGING_H +#define DD_TRACE_STARTUP_LOGGING_H + +#include +#include +#include + +void ddtrace_startup_logging_extra(void (*log)(const char *format, ...)); +void ddtrace_populate_startup_config(HashTable *ht); +void ddtrace_startup_diagnostics(HashTable *ht, bool quick); + +#endif // DD_TRACE_STARTUP_LOGGING_H diff --git a/ext/tracer_tag_propagation/tracer_tag_propagation.c b/tracer/tracer_tag_propagation/tracer_tag_propagation.c similarity index 94% rename from ext/tracer_tag_propagation/tracer_tag_propagation.c rename to tracer/tracer_tag_propagation/tracer_tag_propagation.c index de1482cc0ab..5998d6a64d4 100644 --- a/ext/tracer_tag_propagation/tracer_tag_propagation.c +++ b/tracer/tracer_tag_propagation/tracer_tag_propagation.c @@ -2,14 +2,14 @@ #include -#include "../compat_string.h" +#include #include "../configuration.h" #include "../ddtrace.h" -#include "../trace_source.h" -#include "../priority_sampling/priority_sampling.h" +#include "../random.h" +#include "../span.h" #include -ZEND_EXTERN_MODULE_GLOBALS(ddtrace); +ZEND_EXTERN_MODULE_GLOBALS(datadog); void ddtrace_clean_tracer_tags(zend_array *root_meta, zend_array *propagated_tags) { zend_string *tagname; @@ -72,7 +72,7 @@ void ddtrace_add_tracer_tags_from_array(zend_array *array, zend_array *root_meta ZEND_HASH_FOREACH_STR_KEY_VAL(array, tagname, tag) { if (tagname) { zval tagstr; - ddtrace_convert_to_string(&tagstr, tag); + datadog_convert_to_string(&tagstr, tag); zend_hash_update(root_meta, tagname, &tagstr); zend_hash_add_empty_element(propagated_tags, tagname); } @@ -144,7 +144,7 @@ zend_string *ddtrace_format_propagated_tags(zend_array *propagated, zend_array * smart_str taglist = {0}; - ddtrace_trace_id trace_id = ddtrace_peek_trace_id(); + datadog_trace_id trace_id = ddtrace_peek_trace_id(); if (trace_id.high) { smart_str_append_printf(&taglist, "_dd.p.tid=%016" PRIx64, trace_id.high); } @@ -153,7 +153,7 @@ zend_string *ddtrace_format_propagated_tags(zend_array *propagated, zend_array * ZEND_HASH_FOREACH_STR_KEY(propagated, tagname) { zval *tag = zend_hash_find(tags, tagname), error_zv = {0}; if (tag) { - zend_string *str = ddtrace_convert_to_str(tag); + zend_string *str = datadog_convert_to_str(tag); for (char *cur = ZSTR_VAL(tagname), *end = cur + ZSTR_LEN(tagname); cur < end; ++cur) { if (*cur < 0x20 || *cur > 0x7E || *cur == '=' || *cur == ',') { @@ -212,9 +212,9 @@ void ddtrace_add_propagated_tag(zend_string *key, zval *value) { zend_array *root_meta = ddtrace_get_root_meta(); zval tagstr; - ddtrace_convert_to_string(&tagstr, value); + datadog_convert_to_string(&tagstr, value); zend_hash_update(root_meta, key, &tagstr); zend_hash_add_empty_element(propagated, key); } -DDTRACE_PUBLIC void ddtrace_add_propagated_tag_on_span_zobj(zend_string *key, zval *value) { ddtrace_add_propagated_tag(key, value); } +DATADOG_PUBLIC void ddtrace_add_propagated_tag_on_span_zobj(zend_string *key, zval *value) { ddtrace_add_propagated_tag(key, value); } diff --git a/ext/tracer_tag_propagation/tracer_tag_propagation.h b/tracer/tracer_tag_propagation/tracer_tag_propagation.h similarity index 89% rename from ext/tracer_tag_propagation/tracer_tag_propagation.h rename to tracer/tracer_tag_propagation/tracer_tag_propagation.h index 7af7c58e0c3..a296fbcd297 100644 --- a/ext/tracer_tag_propagation/tracer_tag_propagation.h +++ b/tracer/tracer_tag_propagation/tracer_tag_propagation.h @@ -3,12 +3,12 @@ #include -#include "../ddtrace_export.h" +#include 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); -DDTRACE_PUBLIC void ddtrace_add_propagated_tag_on_span_zobj(zend_string *key, zval *value); +DATADOG_PUBLIC void ddtrace_add_propagated_tag_on_span_zobj(zend_string *key, zval *value); void ddtrace_add_propagated_tag(zend_string *key, zval *value); zval *ddtrace_propagated_tags_get_tag(const char *tag); diff --git a/tracer/tracer_telemetry.c b/tracer/tracer_telemetry.c new file mode 100644 index 00000000000..cee13d908bc --- /dev/null +++ b/tracer/tracer_telemetry.c @@ -0,0 +1,279 @@ +#include "tracer_telemetry.h" +#include "integrations/integrations.h" +#include "ddtrace.h" +#include +#include +#include +#include +#include "autoload_php_files.h" +#include "configuration.h" +#include +#include "span.h" + +#ifndef _WIN32 +#include +#else +#include +#endif + +ZEND_EXTERN_MODULE_GLOBALS(datadog); + +zend_long dd_composer_hook_id; +ddog_QueueId dd_bgs_queued_id; + +const char *ddtrace_telemetry_redact_file(const char *file) { +#ifdef _WIN32 +#define SEPARATOR_CHAR "\\" +#else +#define SEPARATOR_CHAR "/" +#endif + const char *redacted_substring = strstr(file, SEPARATOR_CHAR "DDTrace"); + if (redacted_substring != NULL) { + return redacted_substring; + } else { + // Should not happen but will serve as a gate keepers + const char *php_file_name = strrchr(file, SEPARATOR_CHAR[0]); + if (php_file_name) { + return php_file_name; + } + return ""; + } +} + +void ddtrace_integration_error_telemetryf(ddog_Log source, const char *format, ...) { + va_list va, va2; + va_start(va, format); + char buf[0x100]; + ddog_SidecarActionsBuffer *buffer = datadog_telemetry_buffer(); + va_copy(va2, va); + int len = vsnprintf(buf, sizeof(buf), format, va2); + va_end(va2); + if (len > (int)sizeof(buf)) { + char *msg = malloc(len + 1); + len = vsnprintf(msg, len + 1, format, va); + ddog_sidecar_telemetry_add_integration_log_buffer(source, buffer, (ddog_CharSlice){ .ptr = msg, .len = (uintptr_t)len }); + free(msg); + } else { + ddog_sidecar_telemetry_add_integration_log_buffer(source, buffer, (ddog_CharSlice){ .ptr = buf, .len = (uintptr_t)len }); + } + va_end(va); +} + +static bool dd_check_for_composer_autoloader(zend_ulong invocation, zend_execute_data *execute_data, void *auxiliary, void *dynamic) { + UNUSED(invocation, auxiliary, dynamic); + + ddog_CharSlice composer_path = dd_zend_string_to_CharSlice(execute_data->func->op_array.filename); + if (!DATADOG_G(sidecar) // if sidecar connection was broken, let's skip immediately + || ddtrace_detect_composer_installed_json(&DATADOG_G(sidecar), datadog_sidecar_instance_id, &DATADOG_G(sidecar_queue_id), composer_path)) { + zai_hook_remove((zai_str)ZAI_STR_EMPTY, (zai_str)ZAI_STR_EMPTY, dd_composer_hook_id); + } + return true; +} + +void ddtrace_telemetry_first_init(void) { + dd_composer_hook_id = zai_hook_install((zai_str)ZAI_STR_EMPTY, (zai_str)ZAI_STR_EMPTY, dd_check_for_composer_autoloader, NULL, ZAI_HOOK_AUX_UNUSED, 0); +} + +void ddtrace_telemetry_finalize(void) { + ddog_SidecarActionsBuffer *buffer = datadog_telemetry_buffer(); + // Send information about explicitly disabled integrations + for (size_t i = 0; i < ddtrace_integrations_len; ++i) { + ddtrace_integration *integration = &ddtrace_integrations[i]; + if (!integration->is_enabled()) { + ddog_CharSlice integration_name = (ddog_CharSlice) {.len = integration->name_len, .ptr = integration->name_lcase}; + ddog_sidecar_telemetry_addIntegration_buffer(buffer, integration_name, DDOG_CHARSLICE_C(""), false); + } + } + + // Telemetry metrics + ddog_CharSlice metric_name = DDOG_CHARSLICE_C("spans_created"); + ddog_sidecar_telemetry_register_metric(&DATADOG_G(sidecar), metric_name, DDOG_METRIC_TYPE_COUNT, DDOG_METRIC_NAMESPACE_TRACERS); + zend_string *integration_name; + zval *metric_value; + ZEND_HASH_FOREACH_STR_KEY_VAL(&DDTRACE_G(telemetry_spans_created_per_integration), integration_name, metric_value) { + zai_string tags = zai_string_concat3((zai_str)ZAI_STRL("integration_name:"), (zai_str)ZAI_STR_FROM_ZSTR(integration_name), (zai_str)ZAI_STRING_EMPTY); + ddog_sidecar_telemetry_add_span_metric_point_buffer(buffer, metric_name, Z_DVAL_P(metric_value), dd_zai_string_to_CharSlice(tags)); + zai_string_destroy(&tags); + } ZEND_HASH_FOREACH_END(); + + ddog_sidecar_telemetry_register_metric(&DATADOG_G(sidecar), DDOG_CHARSLICE_C("context_header_style.extracted"), DDOG_METRIC_TYPE_COUNT, DDOG_METRIC_NAMESPACE_TRACERS); + ddog_sidecar_telemetry_add_span_metric_point_buffer(buffer, DDOG_CHARSLICE_C("context_header_style.extracted"), DDTRACE_G(baggage_extract_count), DDOG_CHARSLICE_C("header_style:baggage")); + ddog_sidecar_telemetry_register_metric(&DATADOG_G(sidecar), DDOG_CHARSLICE_C("context_header_style.injected"), DDOG_METRIC_TYPE_COUNT, DDOG_METRIC_NAMESPACE_TRACERS); + ddog_sidecar_telemetry_add_span_metric_point_buffer(buffer, DDOG_CHARSLICE_C("context_header_style.injected"), DDTRACE_G(baggage_inject_count), DDOG_CHARSLICE_C("header_style:baggage")); + ddog_sidecar_telemetry_register_metric(&DATADOG_G(sidecar), DDOG_CHARSLICE_C("context_header.truncated"), DDOG_METRIC_TYPE_COUNT, DDOG_METRIC_NAMESPACE_TRACERS); + ddog_sidecar_telemetry_add_span_metric_point_buffer(buffer, DDOG_CHARSLICE_C("context_header.truncated"), DDTRACE_G(baggage_max_item_count), DDOG_CHARSLICE_C("truncation_reason:baggage_byte_item_exceeded")); + ddog_sidecar_telemetry_add_span_metric_point_buffer(buffer, DDOG_CHARSLICE_C("context_header.truncated"), DDTRACE_G(baggage_max_byte_count), DDOG_CHARSLICE_C("truncation_reason:baggage_byte_count_exceeded")); + ddog_sidecar_telemetry_add_span_metric_point_buffer(buffer, DDOG_CHARSLICE_C("context_header.truncated"), DDTRACE_G(baggage_extract_max_item_count), DDOG_CHARSLICE_C("truncation_reason:baggage_extract_item_exceeded")); + ddog_sidecar_telemetry_add_span_metric_point_buffer(buffer, DDOG_CHARSLICE_C("context_header.truncated"), DDTRACE_G(baggage_extract_max_byte_count), DDOG_CHARSLICE_C("truncation_reason:baggage_extract_byte_exceeded")); + ddog_sidecar_telemetry_register_metric(&DATADOG_G(sidecar), DDOG_CHARSLICE_C("context_header_style.malformed"), DDOG_METRIC_TYPE_COUNT, DDOG_METRIC_NAMESPACE_TRACERS); + ddog_sidecar_telemetry_add_span_metric_point_buffer(buffer, DDOG_CHARSLICE_C("context_header_style.malformed"), DDTRACE_G(baggage_malformed_count), DDOG_CHARSLICE_C("header_style:baggage")); + + // Flush any accumulated BGS (background sender) metrics if enough time has passed. + ddtrace_telemetry_flush_bgs_metrics_if_due(DATADOG_GLOBALS_PTR()); +} + +void ddtrace_telemetry_rinit(void) { + zend_hash_init(&DDTRACE_G(telemetry_spans_created_per_integration), 8, unused, NULL, 0); + DDTRACE_G(baggage_extract_count) = 0; + DDTRACE_G(baggage_inject_count) = 0; + DDTRACE_G(baggage_malformed_count) = 0; + DDTRACE_G(baggage_max_item_count) = 0; + DDTRACE_G(baggage_max_byte_count) = 0; + DDTRACE_G(baggage_extract_max_item_count) = 0; + DDTRACE_G(baggage_extract_max_byte_count) = 0; +} + +void ddtrace_telemetry_rshutdown(void) { + zend_hash_destroy(&DDTRACE_G(telemetry_spans_created_per_integration)); +} + +void ddtrace_telemetry_register_services(ddog_SidecarTransport **sidecar) { + if (!dd_bgs_queued_id) { + dd_bgs_queued_id = ddog_sidecar_queueId_generate(); + } + + ddog_sidecar_telemetry_register_metric(sidecar, DDOG_CHARSLICE_C("trace_api.requests"), DDOG_METRIC_TYPE_COUNT, DDOG_METRIC_NAMESPACE_TRACERS); + ddog_sidecar_telemetry_register_metric(sidecar, DDOG_CHARSLICE_C("trace_api.responses"), DDOG_METRIC_TYPE_COUNT, DDOG_METRIC_NAMESPACE_TRACERS); + ddog_sidecar_telemetry_register_metric(sidecar, DDOG_CHARSLICE_C("trace_api.errors"), DDOG_METRIC_TYPE_COUNT, DDOG_METRIC_NAMESPACE_TRACERS); + + // FIXME: it seems we must call "enqueue_actions" (even with an empty list of actions) for things to work properly + ddog_SidecarActionsBuffer *buffer = ddog_sidecar_telemetry_buffer_alloc(); + datadog_ffi_try("Failed flushing background sender telemetry buffer", + ddog_sidecar_telemetry_buffer_flush(sidecar, datadog_sidecar_instance_id, &dd_bgs_queued_id, buffer)); +} + +void ddtrace_telemetry_notify_integration(const char *name, size_t name_len) { + ddtrace_telemetry_notify_integration_version(name, name_len, "", 0); +} + +void ddtrace_telemetry_notify_integration_version(const char *name, size_t name_len, const char *version, size_t version_len) { + if (DATADOG_G(sidecar) && get_global_DD_INSTRUMENTATION_TELEMETRY_ENABLED()) { + ddog_CharSlice integration = (ddog_CharSlice) {.len = name_len, .ptr = name}; + ddog_CharSlice ver = (ddog_CharSlice) {.len = version_len, .ptr = version}; + ddog_sidecar_telemetry_addIntegration_buffer(datadog_telemetry_buffer(), integration, ver, true); + } +} + +void ddtrace_telemetry_inc_spans_created(ddtrace_span_data *span) { + zval *component = NULL; + if (Z_TYPE(span->property_meta) == IS_ARRAY) { + component = zend_hash_str_find(Z_ARRVAL(span->property_meta), ZEND_STRL("component")); + } + + zend_string *integration = NULL; + 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); + } else if (span->flags & DDTRACE_SPAN_FLAG_OPENTRACING) { + integration = zend_string_init(ZEND_STRL("opentracing"), 0); + } else { + // Fallback value when the span has not been created by an integration, nor OpenTelemetry/OpenTracing (i.e. \DDTrace\span_start()) + integration = zend_string_init(ZEND_STRL("datadog"), 0); + } + + zval *current = zend_hash_find(&DDTRACE_G(telemetry_spans_created_per_integration), integration); + if (current) { + ++Z_DVAL_P(current); + } else { + zval counter; + ZVAL_DOUBLE(&counter, 1.0); + zend_hash_add(&DDTRACE_G(telemetry_spans_created_per_integration), integration, &counter); + } + + zend_string_release(integration); +} + +// Process-global atomic accumulators for background-sender metrics. +// Written by the BGS thread (coms.c) without any lock; drained by a PHP request +// thread in ddtrace_telemetry_flush_bgs_metrics_if_due(). +static _Atomic(int) bgs_metric_requests = 0; +static _Atomic(int) bgs_metric_responses_1xx = 0; +static _Atomic(int) bgs_metric_responses_2xx = 0; +static _Atomic(int) bgs_metric_responses_3xx = 0; +static _Atomic(int) bgs_metric_responses_4xx = 0; +static _Atomic(int) bgs_metric_responses_5xx = 0; +static _Atomic(int) bgs_metric_errors_timeout = 0; +static _Atomic(int) bgs_metric_errors_network = 0; +static _Atomic(int) bgs_metric_errors_status_code = 0; +// Timestamp (nanoseconds) of the last flush; used to rate-limit to one flush per interval. +static _Atomic(uint64_t) bgs_metrics_last_flush_ns = 0; + +void ddtrace_telemetry_send_trace_api_metrics(trace_api_metrics metrics) { + // Pure atomic accumulation — never touches the sidecar. + if (!metrics.requests) { + return; + } + atomic_fetch_add(&bgs_metric_requests, metrics.requests); + atomic_fetch_add(&bgs_metric_responses_1xx, metrics.responses_1xx); + atomic_fetch_add(&bgs_metric_responses_2xx, metrics.responses_2xx); + atomic_fetch_add(&bgs_metric_responses_3xx, metrics.responses_3xx); + atomic_fetch_add(&bgs_metric_responses_4xx, metrics.responses_4xx); + atomic_fetch_add(&bgs_metric_responses_5xx, metrics.responses_5xx); + atomic_fetch_add(&bgs_metric_errors_timeout, metrics.errors_timeout); + atomic_fetch_add(&bgs_metric_errors_network, metrics.errors_network); + atomic_fetch_add(&bgs_metric_errors_status_code, metrics.errors_status_code); +} + +void ddtrace_telemetry_flush_bgs_metrics_if_due(zend_datadog_globals *datadog_globals) { + if (!datadog_globals->sidecar || !get_global_DD_INSTRUMENTATION_TELEMETRY_ENABLED()) { + return; + } + + // Rate-limit: flush at most once per agent flush interval. + uint64_t now_ns = ddtrace_nanoseconds_realtime(); + uint64_t last = atomic_load(&bgs_metrics_last_flush_ns); + uint64_t interval_ns = (uint64_t)get_global_DD_TRACE_AGENT_FLUSH_INTERVAL() * 1000000ULL; + if (now_ns - last < interval_ns) { + return; + } + // CAS ensures only one thread flushes per interval. + if (!atomic_compare_exchange_strong(&bgs_metrics_last_flush_ns, &last, now_ns)) { + return; + } + + int requests = atomic_exchange(&bgs_metric_requests, 0); + if (!requests) { + return; + } + + ddog_SidecarActionsBuffer *buffer = ddog_sidecar_telemetry_buffer_alloc(); + ddog_sidecar_telemetry_add_span_metric_point_buffer(buffer, DDOG_CHARSLICE_C("trace_api.requests"), requests, DDOG_CHARSLICE_C("")); + + int v; + if ((v = atomic_exchange(&bgs_metric_responses_1xx, 0))) { + ddog_sidecar_telemetry_add_span_metric_point_buffer(buffer, DDOG_CHARSLICE_C("trace_api.responses"), v, DDOG_CHARSLICE_C("status_code:1xx")); + } + if ((v = atomic_exchange(&bgs_metric_responses_2xx, 0))) { + ddog_sidecar_telemetry_add_span_metric_point_buffer(buffer, DDOG_CHARSLICE_C("trace_api.responses"), v, DDOG_CHARSLICE_C("status_code:2xx")); + } + if ((v = atomic_exchange(&bgs_metric_responses_3xx, 0))) { + ddog_sidecar_telemetry_add_span_metric_point_buffer(buffer, DDOG_CHARSLICE_C("trace_api.responses"), v, DDOG_CHARSLICE_C("status_code:3xx")); + } + if ((v = atomic_exchange(&bgs_metric_responses_4xx, 0))) { + ddog_sidecar_telemetry_add_span_metric_point_buffer(buffer, DDOG_CHARSLICE_C("trace_api.responses"), v, DDOG_CHARSLICE_C("status_code:4xx")); + } + if ((v = atomic_exchange(&bgs_metric_responses_5xx, 0))) { + ddog_sidecar_telemetry_add_span_metric_point_buffer(buffer, DDOG_CHARSLICE_C("trace_api.responses"), v, DDOG_CHARSLICE_C("status_code:5xx")); + } + if ((v = atomic_exchange(&bgs_metric_errors_timeout, 0))) { + ddog_sidecar_telemetry_add_span_metric_point_buffer(buffer, DDOG_CHARSLICE_C("trace_api.errors"), v, DDOG_CHARSLICE_C("type:timeout")); + } + if ((v = atomic_exchange(&bgs_metric_errors_network, 0))) { + ddog_sidecar_telemetry_add_span_metric_point_buffer(buffer, DDOG_CHARSLICE_C("trace_api.errors"), v, DDOG_CHARSLICE_C("type:network")); + } + if ((v = atomic_exchange(&bgs_metric_errors_status_code, 0))) { + ddog_sidecar_telemetry_add_span_metric_point_buffer(buffer, DDOG_CHARSLICE_C("trace_api.errors"), v, DDOG_CHARSLICE_C("type:status_code")); + } + + datadog_ffi_try("Failed flushing background sender metrics", + ddog_sidecar_telemetry_buffer_flush(&datadog_globals->sidecar, datadog_sidecar_instance_id, &dd_bgs_queued_id, buffer)); +} + +void ddtrace_telemetry_flush_bgs_metrics_final(zend_datadog_globals *datadog_globals) { + // Bypass the time gate so any remaining metrics are sent before the transport + // is dropped in GSHUTDOWN. Setting last_flush_ns to 0 makes the time check in + // _if_due always pass; the CAS inside still prevents a concurrent double-flush. + atomic_store(&bgs_metrics_last_flush_ns, 0); + ddtrace_telemetry_flush_bgs_metrics_if_due(datadog_globals); +} diff --git a/tracer/tracer_telemetry.h b/tracer/tracer_telemetry.h new file mode 100644 index 00000000000..3ad266ad1fe --- /dev/null +++ b/tracer/tracer_telemetry.h @@ -0,0 +1,25 @@ +#ifndef DD_TRACER_TELEMETRY_H +#define DD_TRACER_TELEMETRY_H + +#include +#include "ddtrace.h" + +void ddtrace_telemetry_first_init(void); +void ddtrace_telemetry_rinit(void); +void ddtrace_telemetry_rshutdown(void); +void ddtrace_integration_error_telemetryf(ddog_Log source, const char *format, ...); +void ddtrace_telemetry_notify_integration(const char *name, size_t name_len); +void ddtrace_telemetry_notify_integration_version(const char *name, size_t name_len, const char *version, size_t version_len); + +void ddtrace_telemetry_inc_spans_created(ddtrace_span_data *span); +// Called by the background sender thread (coms.c) to accumulate metrics atomically. +// Never touches the sidecar; the request thread flushes via ddtrace_telemetry_flush_bgs_metrics_if_due(). +void ddtrace_telemetry_send_trace_api_metrics(trace_api_metrics metrics); +// Called from datadog_telemetry_finalize() to flush accumulated BGS metrics through +// the current thread's sidecar connection, at most once per flush interval. +void ddtrace_telemetry_flush_bgs_metrics_if_due(zend_datadog_globals *datadog_globals); +// Force-flush accumulated BGS metrics regardless of the time gate. Call immediately +// before dropping the per-thread transport in GSHUTDOWN so no data is lost. +void ddtrace_telemetry_flush_bgs_metrics_final(zend_datadog_globals *datadog_globals); + +#endif // DD_TRACER_TELEMETRY_H diff --git a/ext/uri_normalization.h b/tracer/uri_normalization.h similarity index 100% rename from ext/uri_normalization.h rename to tracer/uri_normalization.h diff --git a/ext/user_request.c b/tracer/user_request.c similarity index 99% rename from ext/user_request.c rename to tracer/user_request.c index 2daff708a33..5305518f027 100644 --- a/ext/user_request.c +++ b/tracer/user_request.c @@ -11,7 +11,7 @@ static struct { size_t size; } reg_listeners; -DDTRACE_PUBLIC bool ddtrace_user_req_add_listeners(ddtrace_user_req_listeners *listeners) +DATADOG_PUBLIC bool ddtrace_user_req_add_listeners(ddtrace_user_req_listeners *listeners) { if (strcmp(sapi_module.name, "cli") != 0 && strcmp(sapi_module.name, "frankenphp") != 0) { return false; diff --git a/ext/user_request.h b/tracer/user_request.h similarity index 91% rename from ext/user_request.h rename to tracer/user_request.h index f36a4664148..ba6302973be 100644 --- a/ext/user_request.h +++ b/tracer/user_request.h @@ -1,7 +1,7 @@ #pragma once #include "ddtrace.h" -#include "ddtrace_export.h" +#include typedef struct _ddtrace_user_req_listeners ddtrace_user_req_listeners; struct _ddtrace_user_req_listeners { @@ -17,7 +17,7 @@ struct _ddtrace_user_req_listeners { }; // exported -DDTRACE_PUBLIC bool ddtrace_user_req_add_listeners(ddtrace_user_req_listeners *listeners); +DATADOG_PUBLIC bool ddtrace_user_req_add_listeners(ddtrace_user_req_listeners *listeners); void ddtrace_user_req_notify_finish(ddtrace_span_data *span); diff --git a/ext/vendor/mpack/AUTHORS.md b/tracer/vendor/mpack/AUTHORS.md similarity index 100% rename from ext/vendor/mpack/AUTHORS.md rename to tracer/vendor/mpack/AUTHORS.md diff --git a/ext/vendor/mpack/CHANGELOG.md b/tracer/vendor/mpack/CHANGELOG.md similarity index 100% rename from ext/vendor/mpack/CHANGELOG.md rename to tracer/vendor/mpack/CHANGELOG.md diff --git a/ext/vendor/mpack/LICENSE b/tracer/vendor/mpack/LICENSE similarity index 100% rename from ext/vendor/mpack/LICENSE rename to tracer/vendor/mpack/LICENSE diff --git a/ext/vendor/mpack/README.md b/tracer/vendor/mpack/README.md similarity index 100% rename from ext/vendor/mpack/README.md rename to tracer/vendor/mpack/README.md diff --git a/ext/vendor/mpack/mpack.c b/tracer/vendor/mpack/mpack.c similarity index 100% rename from ext/vendor/mpack/mpack.c rename to tracer/vendor/mpack/mpack.c diff --git a/ext/vendor/mpack/mpack.h b/tracer/vendor/mpack/mpack.h similarity index 100% rename from ext/vendor/mpack/mpack.h rename to tracer/vendor/mpack/mpack.h diff --git a/ext/vendor/mt19937/mt19937-64.c b/tracer/vendor/mt19937/mt19937-64.c similarity index 100% rename from ext/vendor/mt19937/mt19937-64.c rename to tracer/vendor/mt19937/mt19937-64.c diff --git a/ext/vendor/mt19937/mt19937-64.h b/tracer/vendor/mt19937/mt19937-64.h similarity index 100% rename from ext/vendor/mt19937/mt19937-64.h rename to tracer/vendor/mt19937/mt19937-64.h diff --git a/ext/weak_resources.c b/tracer/weak_resources.c similarity index 97% rename from ext/weak_resources.c rename to tracer/weak_resources.c index d7a40fec557..fd91eebd6bd 100644 --- a/ext/weak_resources.c +++ b/tracer/weak_resources.c @@ -1,7 +1,7 @@ #include "ddtrace.h" #include "weak_resources.h" -ZEND_EXTERN_MODULE_GLOBALS(ddtrace); +ZEND_EXTERN_MODULE_GLOBALS(datadog); void dd_resource_destroy(zval *zv) { zend_resource *rsrc = Z_RES_P(zv); diff --git a/ext/weak_resources.h b/tracer/weak_resources.h similarity index 100% rename from ext/weak_resources.h rename to tracer/weak_resources.h diff --git a/ext/weakrefs.c b/tracer/weakrefs.c similarity index 99% rename from ext/weakrefs.c rename to tracer/weakrefs.c index 459527c9c87..81a91fce08d 100644 --- a/ext/weakrefs.c +++ b/tracer/weakrefs.c @@ -1,6 +1,5 @@ #include "ddtrace.h" - -#include "compatibility.h" +#include // copied from zend_weakrefs.c, given that there is no public API on old PHP 8.0 versions diff --git a/zend_abstract_interface/components_rs.cmake b/zend_abstract_interface/components_rs.cmake index bfa75b3e9e8..2e71681595e 100644 --- a/zend_abstract_interface/components_rs.cmake +++ b/zend_abstract_interface/components_rs.cmake @@ -21,17 +21,17 @@ add_custom_target(libdatadog_stamp if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux") set(EXPORTS_FILE "${CMAKE_BINARY_DIR}/ddtrace_exports.version") add_custom_target(ddtrace_exports - COMMAND bash -c "{ echo -e '{\\nglobal:'; sed 's/$/;/' '${CMAKE_SOURCE_DIR}'/../ddtrace.sym; echo -e 'local:\\n*;\\n};'; } > '${EXPORTS_FILE}'" + COMMAND bash -c "{ echo -e '{\\nglobal:'; sed 's/$/;/' '${CMAKE_SOURCE_DIR}'/../datadog.sym; echo -e 'local:\\n*;\\n};'; } > '${EXPORTS_FILE}'" BYPRODUCT ${EXPORTS_FILE} - DEPENDS ${CMAKE_SOURCE_DIR}/../ddtrace.sym + DEPENDS ${CMAKE_SOURCE_DIR}/../datadog.sym VERBATIM ) elseif(APPLE) -set(EXPORTS_FILE "${CMAKE_BINARY_DIR}/ddtrace_exports.sym") +set(EXPORTS_FILE "${CMAKE_BINARY_DIR}/datadog_exports.sym") add_custom_target(ddtrace_exports - COMMAND bash -c "sed 's/^/_/' '${CMAKE_SOURCE_DIR}'/../ddtrace.sym > '${EXPORTS_FILE}'" + COMMAND bash -c "sed 's/^/_/' '${CMAKE_SOURCE_DIR}'/../datadog.sym > '${EXPORTS_FILE}'" BYPRODUCT ${EXPORTS_FILE} - DEPENDS ${CMAKE_SOURCE_DIR}/../ddtrace.sym + DEPENDS ${CMAKE_SOURCE_DIR}/../datadog.sym VERBATIM ) endif() diff --git a/zend_abstract_interface/config/config_ini.c b/zend_abstract_interface/config/config_ini.c index 531a10a164b..edfc1ac6090 100644 --- a/zend_abstract_interface/config/config_ini.c +++ b/zend_abstract_interface/config/config_ini.c @@ -514,3 +514,34 @@ bool zai_config_is_modified(zai_config_id entry_id) { return ini->modified; } + +void zai_config_change_default_ini(zai_config_id entry_id, zai_str str) { + zai_config_memoized_entry *memoized = &zai_config_memoized_entries[entry_id]; + zend_ini_entry *entry = memoized->ini_entries[0]; + zend_string_release(entry->value); + entry->value = zend_string_init(str.ptr, str.len, 1); + if (entry->modified) { + entry->modified = false; + zend_string_release(entry->orig_value); + } +#if ZTS + zend_ini_entry *runtime_entry = zend_hash_find_ptr(EG(ini_directives), entry->name); + if (runtime_entry != entry) { + zend_string_release(runtime_entry->value); + runtime_entry->value = zend_string_copy(entry->value); + if (runtime_entry->modified) { + runtime_entry->modified = false; + zend_string_release(runtime_entry->orig_value); + } + } +#endif + memoized->default_encoded_value = str; + memoized->name_index = ZAI_CONFIG_ORIGIN_DEFAULT; + + zval decoded; + ZVAL_UNDEF(&decoded); + if (zai_config_decode_value(str, memoized->type, memoized->parser, &decoded, 1)) { + zai_json_dtor_pzval(&memoized->decoded_value); + ZVAL_COPY_VALUE(&memoized->decoded_value, &decoded); + } +} diff --git a/zend_abstract_interface/config/config_ini.h b/zend_abstract_interface/config/config_ini.h index ce880792e1b..d6224efa003 100644 --- a/zend_abstract_interface/config/config_ini.h +++ b/zend_abstract_interface/config/config_ini.h @@ -40,3 +40,4 @@ typedef bool (*zai_env_config_fallback)(zai_env_buffer *buf, bool pre_rinit); bool zai_config_system_ini_change(zval *old_value, zval *new_value, zend_string *new_str); bool zai_config_is_modified(zai_config_id entry_id); +void zai_config_change_default_ini(zai_config_id entry_id, zai_str str); diff --git a/zend_abstract_interface/env/env.c b/zend_abstract_interface/env/env.c index 875b5754d46..f83ba311511 100644 --- a/zend_abstract_interface/env/env.c +++ b/zend_abstract_interface/env/env.c @@ -15,7 +15,7 @@ zai_env_result zai_sapi_getenv(zai_str name, zai_env_buffer *buf) { ZAI_ASSERT(buf && "zai_sapi_getenv: buf must be non-NULL"); - ZAI_ASSERT((PG(modules_activated) | PG(during_request_startup)) && "zai_sapi_getenv: must be called during or after RINIT"); + ZAI_ASSERT((PG(modules_activated) || PG(during_request_startup)) && "zai_sapi_getenv: must be called during or after RINIT"); // Optimize for the happy-path where the caller has valid inputs. On every // request, every config is likely to check for a sapi-provided env var, diff --git a/zend_abstract_interface/json/json.h b/zend_abstract_interface/json/json.h index 7d73b021c75..b563ebb5c34 100644 --- a/zend_abstract_interface/json/json.h +++ b/zend_abstract_interface/json/json.h @@ -6,8 +6,10 @@ #include "php.h" #include "zend_smart_str.h" +#ifndef PHP_JSON_PRETTY_PRINT #define PHP_JSON_OBJECT_AS_ARRAY (1 << 0) #define PHP_JSON_PRETTY_PRINT (1 << 7) +#endif /* The JSON extension is a required module and ZAI JSON must work under the * following environments: