diff --git a/Makefile b/Makefile index e23e56904b..eaaa7b94c2 100644 --- a/Makefile +++ b/Makefile @@ -1249,13 +1249,13 @@ define run_opentelemetry_tests $(eval TEST_EXTRA_ENV=) endef -test_opentelemetry_beta: tests/Frameworks/Custom/OpenTelemetry/composer.lock-php$(PHP_MAJOR_MINOR) tests/OpenTelemetry/composer-beta.lock-php$(PHP_MAJOR_MINOR) +test_opentelemetry_beta: global_test_run_dependencies tests/Frameworks/Custom/OpenTelemetry/composer.lock-php$(PHP_MAJOR_MINOR) tests/OpenTelemetry/composer-beta$(shell [ $(PHP_MAJOR_MINOR) -le 81 ] && echo "-pre-8.1" || echo '').lock-php$(PHP_MAJOR_MINOR) $(call run_opentelemetry_tests, TESTSUITE_VENDOR_DIR=vendor-beta) -tests/OpenTelemetry/composer-beta.lock-php$(PHP_MAJOR_MINOR): tests/OpenTelemetry/composer-beta.json - $(call run_composer_with_lock,tests/OpenTelemetry,composer-beta.json) +tests/OpenTelemetry/composer-%.lock-php$(PHP_MAJOR_MINOR): tests/OpenTelemetry/composer-%.json + $(call run_composer_with_lock,tests/OpenTelemetry,composer-$(*).json) -test_opentelemetry_1: tests/Frameworks/Custom/OpenTelemetry/composer.lock-php$(PHP_MAJOR_MINOR) tests/OpenTelemetry/composer.lock-php$(PHP_MAJOR_MINOR) +test_opentelemetry_1: global_test_run_dependencies tests/Frameworks/Custom/OpenTelemetry/composer.lock-php$(PHP_MAJOR_MINOR) tests/OpenTelemetry/composer$(shell [ $(PHP_MAJOR_MINOR) -le 81 ] && echo "-pre-8.1" || echo '').lock-php$(PHP_MAJOR_MINOR) $(call run_opentelemetry_tests) test_opentracing_10: global_test_run_dependencies tests/OpenTracer1Unit/composer.lock-php$(PHP_MAJOR_MINOR) tests/Frameworks/Custom/OpenTracing/composer.lock-php$(PHP_MAJOR_MINOR) diff --git a/config.m4 b/config.m4 index 241f81657b..c4b7a1f39c 100644 --- a/config.m4 +++ b/config.m4 @@ -137,6 +137,7 @@ if test "$PHP_DDTRACE" != "no"; then EXTRA_PHP_SOURCES="\ ext/handlers_curl.c \ ext/hook/uhook_attributes.c \ + ext/hook/uhook_otel.c \ " ZAI_RESOLVER_SUFFIX="" diff --git a/config.w32 b/config.w32 index dc151bd508..c4fcb9e606 100644 --- a/config.w32 +++ b/config.w32 @@ -67,7 +67,7 @@ if (PHP_DDTRACE != 'no') { var DDTRACE_HOOK_SOURCES = "uhook.c uhook_legacy.c"; if (version >= 800) { - DDTRACE_HOOK_SOURCES += " uhook_attributes.c"; + DDTRACE_HOOK_SOURCES += " uhook_attributes.c uhook_otel.c"; } var zai_dirname = configure_module_dirname + "/zend_abstract_interface"; diff --git a/ext/ddtrace.c b/ext/ddtrace.c index 798327fff4..d9187dbba6 100644 --- a/ext/ddtrace.c +++ b/ext/ddtrace.c @@ -2512,6 +2512,12 @@ PHP_FUNCTION(dd_trace_internal_fn) { ddog_CharSlice path = dd_zend_string_to_CharSlice(Z_STR_P(ZVAL_VARARG_PARAM(params, 0))); ddtrace_detect_composer_installed_json(&ddtrace_sidecar, ddtrace_sidecar_instance_id, &DDTRACE_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); + zval *version = ZVAL_VARARG_PARAM(params, 1); + if (Z_TYPE_P(name) == IS_STRING && Z_TYPE_P(version) == IS_STRING) { + ddtrace_telemetry_notify_integration_version(Z_STRVAL_P(name), Z_STRLEN_P(name), Z_STRVAL_P(version), Z_STRLEN_P(version)); + } } else if (FUNCTION_NAME_MATCHES("dump_sidecar")) { if (!ddtrace_sidecar) { RETURN_FALSE; @@ -3315,8 +3321,11 @@ PHP_FUNCTION(DDTrace_curl_multi_exec_get_request_spans) { RETURN_NULL(); } -static const zend_module_dep ddtrace_module_deps[] = {ZEND_MOD_REQUIRED("json") ZEND_MOD_REQUIRED("standard") - ZEND_MOD_END}; +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, diff --git a/ext/hook/uhook.c b/ext/hook/uhook.c index e186583ecc..2fafdc5f11 100644 --- a/ext/hook/uhook.c +++ b/ext/hook/uhook.c @@ -1103,6 +1103,7 @@ static void dd_uhook_closure_free_wrapper(zend_object *object) { #if PHP_VERSION_ID >= 80000 void zai_uhook_attributes_minit(void); +void dd_register_opentelemetry_wrapper(void); #endif void zai_uhook_minit(int module_number) { ddtrace_hook_data_ce = register_class_DDTrace_HookData(); @@ -1116,6 +1117,7 @@ void zai_uhook_minit(int module_number) { #if PHP_VERSION_ID >= 80000 zai_uhook_attributes_minit(); + dd_register_opentelemetry_wrapper(); #endif // get hold of a Closure object to access handlers diff --git a/ext/hook/uhook_otel.c b/ext/hook/uhook_otel.c new file mode 100644 index 0000000000..57ce16104e --- /dev/null +++ b/ext/hook/uhook_otel.c @@ -0,0 +1,282 @@ +#include +#include +#include +#include "uhook.h" +#include "../configuration.h" +#include "../span.h" +#include + +#include + +typedef struct { + zend_object *begin; + zend_object *end; +} dd_uhook_def; + +void dd_otel_call(zend_execute_data *execute_data, zval *retval, zend_object *closure, zval *rv) { + zval args[8]; + + int offset = retval ? 2 : 0; + if (EX(func)->op_array.scope) { + if (EX(func)->op_array.fn_flags & ZEND_ACC_STATIC) { + ZVAL_STR(&args[0], zend_get_called_scope(execute_data)->name); + } else { + ZVAL_COPY_VALUE(&args[0], &EX(This)); + } + ZVAL_STR(&args[2 + offset], EX(func)->op_array.scope->name); + } else { + ZVAL_NULL(&args[0]); + ZVAL_NULL(&args[2 + offset]); + } + ZVAL_ARR(&args[1], dd_uhook_collect_args(execute_data)); + ZVAL_STR(&args[3 + offset], EX(func)->op_array.function_name); + if (ZEND_USER_CODE(EX(func)->type)) { + ZVAL_STR(&args[4 + offset], EX(func)->op_array.filename); + ZVAL_LONG(&args[5 + offset], EX(func)->op_array.line_start); + } else { + ZVAL_NULL(&args[4 + offset]); + ZVAL_NULL(&args[5 + offset]); + } + if (!retval) { + ZVAL_EMPTY_ARRAY(&args[6]); + ZVAL_EMPTY_ARRAY(&args[7]); + } else { + ZVAL_COPY_VALUE(&args[2], retval); + if (EG(exception)) { + ZVAL_OBJ(&args[3], EG(exception)); + } else { + ZVAL_NULL(&args[3]); + } + } + + zend_fcall_info fci = empty_fcall_info; + zend_fcall_info_cache fcc = empty_fcall_info_cache; + + zval zv; + ZVAL_OBJ(&zv, closure); + ZVAL_UNDEF(rv); + + zend_fcall_info_init(&zv, 0, &fci, &fcc, NULL, NULL); + fci.retval = rv; + fci.params = args; + fci.param_count = 8; + + zai_sandbox sandbox; + zai_sandbox_open(&sandbox); + if (zend_call_function(&fci, &fcc) == SUCCESS || PG(last_error_message)) { + dd_uhook_report_sandbox_error(execute_data, closure); + } + zai_sandbox_close(&sandbox); + + zval_ptr_dtor(&args[1]); +} + +static bool dd_uhook_begin(zend_ulong invocation, zend_execute_data *execute_data, void *auxiliary, void *dynamic) { + UNUSED(invocation, dynamic); + dd_uhook_def *def = auxiliary; + + LOGEV(HOOK_TRACE, dd_uhook_log_invocation(log, execute_data, "begin", def->begin);); + + zval rv; + dd_otel_call(execute_data, NULL, def->begin, &rv); + + if (Z_TYPE(rv) == IS_ARRAY) { + zend_ulong arg_offset; + zend_string *strkey; + zval *val; + zend_function *fbc = EX(func); + + ZEND_HASH_FOREACH_KEY_VAL(Z_ARR(rv), arg_offset, strkey, val) { + bool found = false; + if (strkey) { + uint32_t num_args = fbc->common.num_args; + // As per zend_handle_named_arg() + if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) + || EXPECTED(fbc->common.fn_flags & ZEND_ACC_USER_ARG_INFO)) { + for (uint32_t i = 0; i < num_args; i++) { + zend_arg_info *arg_info = &fbc->op_array.arg_info[i]; + if (zend_string_equals(strkey, arg_info->name)) { + arg_offset = i; + found = true; + } + } + } else { + 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); + if (zend_string_equals_cstr(strkey, arg_info->name, len)) { + arg_offset = i; + found = true; + } + } + } + } else { + found = arg_offset < fbc->common.num_args; + } + + uint32_t current_num_args = EX_NUM_ARGS(); + zval *arg = EX_VAR_NUM(arg_offset); + if (!found) { + if (!(fbc->common.fn_flags & ZEND_ACC_VARIADIC)) { + continue; // Unknown parameter + } + + if (strkey) { + /* Unknown named parameter that will be collected into a variadic. */ + if (!(EX_CALL_INFO() & ZEND_CALL_HAS_EXTRA_NAMED_PARAMS)) { + ZEND_ADD_CALL_FLAG(execute_data, ZEND_CALL_HAS_EXTRA_NAMED_PARAMS); + EX(extra_named_params) = zend_new_array(0); + } + + Z_TRY_ADDREF_P(val); + zend_hash_update(EX(extra_named_params), strkey, val); + continue; + } else { + + if (arg_offset > current_num_args) { + if (!ZEND_USER_CODE(fbc->type)) { + if ((uint32_t)arg_offset - current_num_args > EG(vm_stack_end) - EX_VAR_NUM(0)) { + continue; // we won't mess with adding new frames + } +#if PHP_VERSION_ID >= 80200 + // temporaries like the last observed frame are already initialized. Move them. + memmove(EX_VAR_NUM(arg_offset), EX_VAR_NUM(EX_NUM_ARGS()), fbc->common.T * sizeof(zval *)); +#endif + for (uint32_t i = fbc->common.num_args; i < (uint32_t)arg_offset; ++i) { + ZVAL_UNDEF(EX_VAR_NUM(i)); + } + } else { + arg = EX_VAR_NUM(fbc->op_array.last_var + fbc->op_array.T - fbc->op_array.num_args + arg_offset); + for (zval *extra_arg = EX_VAR_NUM(fbc->op_array.last_var + fbc->op_array.T); extra_arg < arg; ++extra_arg) { + ZVAL_UNDEF(extra_arg); + } + } + } + } + } + if (arg_offset >= EX_NUM_ARGS()) { + EX_NUM_ARGS() = arg_offset + 1; + uint32_t num_extra_args = EX_NUM_ARGS() - current_num_args; + + if (num_extra_args > 1) { + for (uint32_t i = current_num_args; i < MIN(fbc->common.num_args, arg_offset); ++i) { + ZVAL_UNDEF(EX_VAR_NUM(i)); + } + ZEND_ADD_CALL_FLAG(execute_data, ZEND_CALL_MAY_HAVE_UNDEF); + } + } + zval_ptr_dtor(arg); + ZVAL_COPY(arg, val); + } ZEND_HASH_FOREACH_END(); + } + zval_ptr_dtor(&rv); + + return true; +} + +static void dd_uhook_end(zend_ulong invocation, zend_execute_data *execute_data, zval *retval, void *auxiliary, void *dynamic) { + UNUSED(invocation, dynamic); + dd_uhook_def *def = auxiliary; + + LOGEV(HOOK_TRACE, dd_uhook_log_invocation(log, execute_data, "end", def->end);); + + zval rv; + dd_otel_call(execute_data, retval, def->end, &rv); + + if (!Z_ISUNDEF(rv)) { + const zend_function *func = zend_get_closure_method_def(def->end); + if (func->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE && (ZEND_TYPE_PURE_MASK(func->common.arg_info[-1].type) & IS_VOID) == 0) { + zval_ptr_dtor(retval); + ZVAL_COPY_VALUE(retval, &rv); + } else { + zval_ptr_dtor(&rv); + } + } +} + +static void dd_uhook_dtor(void *data) { + dd_uhook_def *def = data; + if (def->begin) { + OBJ_RELEASE(def->begin); + } + if (def->end) { + OBJ_RELEASE(def->end); + } + efree(def); +} + +PHP_FUNCTION(DDTrace_OpenTelemetry_Instrumentation_hook) { + zend_string *class_name, *function_name; + zval *pre = NULL, *post = NULL; + + ZEND_PARSE_PARAMETERS_START(2, 4) + Z_PARAM_STR_OR_NULL(class_name) + Z_PARAM_STR(function_name) + Z_PARAM_OPTIONAL + Z_PARAM_OBJECT_OF_CLASS_OR_NULL(pre, zend_ce_closure) + Z_PARAM_OBJECT_OF_CLASS_OR_NULL(post, zend_ce_closure) + ZEND_PARSE_PARAMETERS_END(); + + dd_uhook_def *def = emalloc(sizeof(*def)); + def->begin = pre ? Z_OBJ_P(pre) : NULL; + if (def->begin) { + GC_ADDREF(def->begin); + } + def->end = post ? Z_OBJ_P(post) : NULL; + if (def->end) { + GC_ADDREF(def->end); + } + + zai_str class_str = ZAI_STR_EMPTY; + if (class_name) { + class_str = (zai_str)ZAI_STR_FROM_ZSTR(class_name); + } + zai_str func_str = ZAI_STR_FROM_ZSTR(function_name); + + + bool success = zai_hook_install_generator(class_str, func_str, + def->begin ? dd_uhook_begin : NULL, NULL, NULL, def->end ? dd_uhook_end : NULL, + ZAI_HOOK_AUX(def, dd_uhook_dtor), 0) != -1; + + if (!success) { + dd_uhook_dtor(def); + } else { + LOG(HOOK_TRACE, "Installing an otel hook function at %s:%d on %s %s%s%s", + zend_get_executed_filename(), zend_get_executed_lineno(), + class_name ? "method" : "function", + class_name ? ZSTR_VAL(class_name) : "", + class_name ? "::" : "", + ZSTR_VAL(function_name)); + } + RETURN_BOOL(success); +} + +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_OpenTelemetry_Instrumentation_hook, 0, 2, _IS_BOOL, 0) + ZEND_ARG_TYPE_INFO(0, class, IS_STRING, 1) + ZEND_ARG_TYPE_INFO(0, function, IS_STRING, 0) + ZEND_ARG_OBJ_INFO_WITH_DEFAULT_VALUE(0, pre, Closure, 1, "null") + ZEND_ARG_OBJ_INFO_WITH_DEFAULT_VALUE(0, post, Closure, 1, "null") +ZEND_END_ARG_INFO() + +static zend_function_entry dd_otel_functions[] = { + ZEND_NS_FALIAS("OpenTelemetry\\Instrumentation", hook, DDTrace_OpenTelemetry_Instrumentation_hook, arginfo_OpenTelemetry_Instrumentation_hook) + ZEND_FE_END +}; + +zif_handler dd_extension_loaded; +ZEND_FUNCTION(DDTrace_extension_loaded) { + dd_extension_loaded(INTERNAL_FUNCTION_PARAM_PASSTHRU); + if (Z_TYPE_P(return_value) == IS_FALSE && EX_NUM_ARGS() > 0 && Z_TYPE_P(EX_VAR_NUM(0)) == IS_STRING && zend_string_equals_cstr(Z_STR_P(EX_VAR_NUM(0)), ZEND_STRL("opentelemetry"))) { + RETURN_TRUE; + } +} + +void dd_register_opentelemetry_wrapper(void) { + if (!zend_hash_str_find_ptr_lc(CG(function_table), dd_otel_functions->fname, strlen(dd_otel_functions->fname))) { + zend_register_functions(NULL, dd_otel_functions, NULL, MODULE_PERSISTENT); + + zend_internal_function *extension_loaded = zend_hash_str_find_ptr(CG(function_table), ZEND_STRL("extension_loaded")); + dd_extension_loaded = extension_loaded->handler; + extension_loaded->handler = ZEND_FN(DDTrace_extension_loaded); + } +} diff --git a/ext/telemetry.c b/ext/telemetry.c index 75f5be5b09..5e0fec18a0 100644 --- a/ext/telemetry.c +++ b/ext/telemetry.c @@ -185,10 +185,14 @@ void ddtrace_telemetry_finalize(void) { } 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_sidecar && get_global_DD_INSTRUMENTATION_TELEMETRY_ENABLED()) { ddog_CharSlice integration = (ddog_CharSlice) {.len = name_len, .ptr = name}; - ddog_sidecar_telemetry_addIntegration(&ddtrace_sidecar, ddtrace_sidecar_instance_id, &DDTRACE_G(sidecar_queue_id), integration, - DDOG_CHARSLICE_C(""), true); + ddog_CharSlice ver = (ddog_CharSlice) {.len = version_len, .ptr = version}; + ddog_sidecar_telemetry_addIntegration(&ddtrace_sidecar, ddtrace_sidecar_instance_id, &DDTRACE_G(sidecar_queue_id), integration, ver, true); } } diff --git a/ext/telemetry.h b/ext/telemetry.h index 78c97d12dd..6f4111f70b 100644 --- a/ext/telemetry.h +++ b/ext/telemetry.h @@ -26,6 +26,7 @@ void ddtrace_telemetry_rinit(void); void ddtrace_telemetry_rshutdown(void); ddog_TelemetryWorkerHandle *ddtrace_build_telemetry_handle(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); void ddtrace_telemetry_register_services(ddog_SidecarTransport *sidecar); void ddtrace_telemetry_inc_spans_created(ddtrace_span_data *span); diff --git a/src/DDTrace/OpenTelemetry/CachedInstrumentation.php b/src/DDTrace/OpenTelemetry/CachedInstrumentation.php new file mode 100644 index 0000000000..3f767aa4ee --- /dev/null +++ b/src/DDTrace/OpenTelemetry/CachedInstrumentation.php @@ -0,0 +1,58 @@ +name, $this->version); +}); + +\DDTrace\install_hook('OpenTelemetry\API\Instrumentation\CachedInstrumentation::tracer', null, function (\DDTrace\HookData $hook) { + $tracer = $hook->returned; + + $name = $this->name; + if (strpos($name, "io.opentelemetry.contrib.php.") === 0) { + $name = substr($name, strlen("io.opentelemetry.contrib.php.")); + } + $name = "otel.$name"; + + $hook->overrideReturnValue(new class($tracer, $name) implements \OpenTelemetry\API\Trace\TracerInterface { + public $tracer; + public $name; + + public function __construct($tracer, $name) + { + $this->tracer = $tracer; + $this->name = $name; + } + + public function spanBuilder(string $spanName): \OpenTelemetry\API\Trace\SpanBuilderInterface + { + $spanBuilder = $this->tracer->spanBuilder($spanName); + //print new \Exception; + $spanBuilder->setAttribute("component", $this->name); + return $spanBuilder; + } + + public function isEnabled(): bool + { + return $this->tracer->isEnabled(); + } + + public function getInstrumentationScope(): InstrumentationScopeInterface + { + if (!method_exists($this->tracer, 'getInstrumentationScope')) { + throw new \Error("There is no getInstrumentationScope method available for " . get_class($this->tracer)); + } + return $this->tracer->getInstrumentationScope(); + } + + public function updateConfig(Configurator $configurator): void + { + $this->tracer->updateConfig($configurator); + } + }); +}); diff --git a/src/bridge/_files_opentelemetry.php b/src/bridge/_files_opentelemetry.php index 58e0945a18..e5e2a91d70 100644 --- a/src/bridge/_files_opentelemetry.php +++ b/src/bridge/_files_opentelemetry.php @@ -6,4 +6,5 @@ __DIR__ . '/../DDTrace/OpenTelemetry/SpanContext.php', __DIR__ . '/../DDTrace/OpenTelemetry/Span.php', __DIR__ . '/../DDTrace/OpenTelemetry/SpanBuilder.php', + __DIR__ . '/../DDTrace/OpenTelemetry/CachedInstrumentation.php', ]; diff --git a/tests/Frameworks/Custom/OpenTelemetry/composer.json b/tests/Frameworks/Custom/OpenTelemetry/composer.json index c5811adc60..adcb6bd49f 100644 --- a/tests/Frameworks/Custom/OpenTelemetry/composer.json +++ b/tests/Frameworks/Custom/OpenTelemetry/composer.json @@ -1,6 +1,8 @@ { "require": { "php": ">=7.4", - "open-telemetry/sdk": "^1.0" + "open-telemetry/sdk": "^1.0", + "symfony/http-client": "*", + "nyholm/psr7": "*" } } diff --git a/tests/OpenTelemetry/Integration/SpanProvenanceTest.php b/tests/OpenTelemetry/Integration/SpanProvenanceTest.php new file mode 100644 index 0000000000..85c14fa032 --- /dev/null +++ b/tests/OpenTelemetry/Integration/SpanProvenanceTest.php @@ -0,0 +1,31 @@ +isolateTracer(function () { + $context = Configurator::create() + ->withTracerProvider(new TracerProvider) + ->storeInContext(); + Context::storage()->attach($context); + + file_get_contents("/etc/passwd"); + }); + $this->assertEquals($traces[0][0]["resource"], "file_get_contents"); + $this->assertEquals($traces[0][0]["name"], "internal"); + $this->assertEquals($traces[0][0]["meta"]["component"], "otel.io"); + } +} diff --git a/tests/OpenTelemetry/composer-beta-pre-8.1.json b/tests/OpenTelemetry/composer-beta-pre-8.1.json new file mode 100644 index 0000000000..3e3b281af2 --- /dev/null +++ b/tests/OpenTelemetry/composer-beta-pre-8.1.json @@ -0,0 +1,12 @@ +{ + "name": "datadog/dd-trace-tests", + "require": { + "open-telemetry/sdk": "@beta", + "open-telemetry/extension-propagator-b3": "@beta", + "open-telemetry/opentelemetry-logger-monolog": "@beta" + }, + "minimum-stability": "beta", + "config": { + "vendor-dir": "vendor-beta/" + } +} diff --git a/tests/OpenTelemetry/composer-beta.json b/tests/OpenTelemetry/composer-beta.json index 3e3b281af2..1d27dbb177 100644 --- a/tests/OpenTelemetry/composer-beta.json +++ b/tests/OpenTelemetry/composer-beta.json @@ -3,10 +3,14 @@ "require": { "open-telemetry/sdk": "@beta", "open-telemetry/extension-propagator-b3": "@beta", - "open-telemetry/opentelemetry-logger-monolog": "@beta" + "open-telemetry/opentelemetry-logger-monolog": "@beta", + "open-telemetry/opentelemetry-auto-io": "^0.0.12" }, "minimum-stability": "beta", "config": { + "platform": { + "ext-opentelemetry": "1" + }, "vendor-dir": "vendor-beta/" } } diff --git a/tests/OpenTelemetry/composer-pre-8.1.json b/tests/OpenTelemetry/composer-pre-8.1.json new file mode 100644 index 0000000000..f968bafcf6 --- /dev/null +++ b/tests/OpenTelemetry/composer-pre-8.1.json @@ -0,0 +1,9 @@ +{ + "name": "datadog/dd-trace-tests", + "require": { + "open-telemetry/sdk": "1.0.*||1.1.*", + "open-telemetry/extension-propagator-b3": "1.0.*||1.1.*", + "open-telemetry/opentelemetry-logger-monolog": "1.0.*||1.1.*" + }, + "minimum-stability": "stable" +} diff --git a/tests/OpenTelemetry/composer.json b/tests/OpenTelemetry/composer.json index f968bafcf6..02c4a86374 100644 --- a/tests/OpenTelemetry/composer.json +++ b/tests/OpenTelemetry/composer.json @@ -3,7 +3,13 @@ "require": { "open-telemetry/sdk": "1.0.*||1.1.*", "open-telemetry/extension-propagator-b3": "1.0.*||1.1.*", - "open-telemetry/opentelemetry-logger-monolog": "1.0.*||1.1.*" + "open-telemetry/opentelemetry-logger-monolog": "1.0.*||1.1.*", + "open-telemetry/opentelemetry-auto-io": "^0.0.12" }, - "minimum-stability": "stable" + "minimum-stability": "stable", + "config": { + "platform": { + "ext-opentelemetry": "1" + } + } } diff --git a/tests/phpunit.xml b/tests/phpunit.xml index c44f1f70f5..a8d6bc60c4 100644 --- a/tests/phpunit.xml +++ b/tests/phpunit.xml @@ -80,6 +80,7 @@ ./OpenTelemetry/Unit/Propagation ./OpenTelemetry/Integration/API ./OpenTelemetry/Integration/Context + ./OpenTelemetry/Integration/SpanProvenanceTest.php ./OpenTelemetry/Integration/Logs ./OpenTelemetry/Integration/SDK ./OpenTelemetry/Integration/InteroperabilityTest.php diff --git a/zend_abstract_interface/hook/hook.c b/zend_abstract_interface/hook/hook.c index 8f07e4aa7d..91e81fcdf6 100644 --- a/zend_abstract_interface/hook/hook.c +++ b/zend_abstract_interface/hook/hook.c @@ -36,6 +36,7 @@ typedef struct _zai_hooks_entry { void ***run_time_cache; // used only if Closure #endif bool is_generator; + bool is_internal; // However, for non-Closure functions, we may not track the run_time_cache, as it may not yet have been initialized when first resolved #endif // On PHP 7, we only go by resolved; we don't have to care about individual rt_caches @@ -188,6 +189,7 @@ static void zai_hook_entries_destroy(zai_hooks_entry *hooks, zend_ulong install_ } } else if (hooks->run_time_cache) { zend_function func; + func.type = hooks->is_internal ? ZEND_INTERNAL_FUNCTION : ZEND_USER_FUNCTION; func.common.fn_flags = hooks->is_generator ? ZEND_ACC_GENERATOR : 0; func.op_array.opcodes = (void *)(uintptr_t *)(install_address << 5); // does not need to be valid, but sufficient to get install_address #if PHP_VERSION_ID >= 80200 @@ -399,6 +401,7 @@ static void zai_hook_resolve_hooks_entry(zai_hooks_entry *hooks, zend_function * hooks->run_time_cache = ZEND_MAP_PTR(resolved->common.run_time_cache); #endif } + hooks->is_internal = ZEND_USER_CODE(resolved->type); hooks->is_generator = (resolved->common.fn_flags & ZEND_ACC_GENERATOR) != 0; if (hooks->is_generator) { #if ZAI_JIT_BLACKLIST_ACTIVE