Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 45 additions & 1 deletion ext/autoload_php_files.c
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,43 @@ static void dd_load_files(const char *files_file) {

#define dd_load_files(file) EXPECTED(get_global_DD_AUTOLOAD_NO_COMPILE() == false) ? dd_load_file("bridge/_generated_" file) : dd_load_files("bridge/_files_" file)

// Remove mixed return types for PHP 7.4 support. OpenTelemetry v2 now requires ": mixed" and drops PHP 7.4, but we fixup the AST here so that OpenTelemetry v1 still works with PHP 7.4.
#if PHP_VERSION_ID >= 70400 && PHP_VERSION_ID < 80000
void dd_walk_ast_top_stmt(zend_ast *ast) {
if (ast->kind == ZEND_AST_STMT_LIST) {
zend_ast_list *list = zend_ast_get_list(ast);
uint32_t i;
for (i = 0; i < list->children; ++i) {
dd_walk_ast_top_stmt(list->child[i]);
}
} else if (ast->kind == ZEND_AST_FUNC_DECL || ast->kind == ZEND_AST_METHOD) {
zend_ast_decl *decl = (zend_ast_decl *) ast;
zend_ast *return_type_ast = decl->child[3];
if (return_type_ast && return_type_ast->kind != ZEND_AST_TYPE) {
if (zend_string_equals_literal(zend_ast_get_str(return_type_ast), "mixed")) {
decl->child[3] = NULL;
zend_ast_destroy(return_type_ast);
}
}
} else if (ast->kind == ZEND_AST_CLASS) {
zend_ast_decl *decl = (zend_ast_decl *) ast;
zend_ast *stmt_ast = decl->child[2];

dd_walk_ast_top_stmt(stmt_ast);
} else if (ast->kind == ZEND_AST_NAMESPACE && ast->child[1]) {
dd_walk_ast_top_stmt(ast->child[1]);
}
}

zend_ast_process_t dd_prev_ast_process = NULL;
void dd_remove_mixed_return(zend_ast *ast) {
dd_walk_ast_top_stmt(ast);
if (dd_prev_ast_process) {
dd_prev_ast_process(ast);
}
}
#endif

// We have, at this place, the luxury of knowing that we'll always be called before composers autoloader.
// Note that this code will also be called during opcache.preload, allowing us to not consider that scenario separately.
// The first time the autoloader gets invoked for ddtrace\\, we load the API
Expand Down Expand Up @@ -211,9 +248,16 @@ static zend_class_entry *dd_perform_autoload(zend_string *class_name, zend_strin
}
}

if (get_DD_TRACE_OTEL_ENABLED() && zend_string_starts_with_literal(lc_name, "opentelemetry\\") && !DDTRACE_G(otel_is_loaded)) {
if ((get_DD_TRACE_OTEL_ENABLED() || get_DD_METRICS_OTEL_ENABLED()) && zend_string_starts_with_literal(lc_name, "opentelemetry\\") && !DDTRACE_G(otel_is_loaded)) {
DDTRACE_G(otel_is_loaded) = 1;
#if PHP_VERSION_ID >= 70400 && PHP_VERSION_ID < 80000
dd_prev_ast_process = zend_ast_process;
zend_ast_process = dd_remove_mixed_return;
dd_load_files("opentelemetry");
zend_ast_process = dd_prev_ast_process;
#else
dd_load_files("opentelemetry");
#endif
if ((ce = zend_hash_find_ptr(EG(class_table), lc_name))) {
return ce;
}
Expand Down
2 changes: 2 additions & 0 deletions ext/configuration.h
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ enum ddtrace_sampling_rules_format {
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 */ \
Expand Down Expand Up @@ -227,6 +228,7 @@ enum ddtrace_sampling_rules_format {
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_TRACE_OTEL_ENABLED, "false") \
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, \
Expand Down
23 changes: 15 additions & 8 deletions ext/serializer.c
Original file line number Diff line number Diff line change
Expand Up @@ -816,18 +816,25 @@ void ddtrace_set_root_span_properties(ddtrace_root_span_data *span) {
}

if (get_DD_TRACE_REPORT_HOSTNAME()) {
if (ZSTR_LEN(get_DD_HOSTNAME())) {
zval hostname_zv;
ZVAL_STR(&hostname_zv, get_DD_HOSTNAME());
zend_hash_str_add_new(meta, ZEND_STRL("_dd.hostname"), &hostname_zv);
} else {

#ifndef HOST_NAME_MAX
#define HOST_NAME_MAX 255
#endif

zend_string *hostname = zend_string_alloc(HOST_NAME_MAX, 0);
if (gethostname(ZSTR_VAL(hostname), HOST_NAME_MAX + 1)) {
zend_string_release(hostname);
} else {
hostname = zend_string_truncate(hostname, strlen(ZSTR_VAL(hostname)), 0);
zval hostname_zv;
ZVAL_STR(&hostname_zv, hostname);
zend_hash_str_add_new(meta, ZEND_STRL("_dd.hostname"), &hostname_zv);
zend_string *hostname = zend_string_alloc(HOST_NAME_MAX, 0);
if (gethostname(ZSTR_VAL(hostname), HOST_NAME_MAX + 1)) {
zend_string_release(hostname);
} else {
hostname = zend_string_truncate(hostname, strlen(ZSTR_VAL(hostname)), 0);
zval hostname_zv;
ZVAL_STR(&hostname_zv, hostname);
zend_hash_str_add_new(meta, ZEND_STRL("_dd.hostname"), &hostname_zv);
}
}
}

Expand Down
125 changes: 125 additions & 0 deletions src/DDTrace/OpenTelemetry/CompositeResolver.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
<?php
// This file does not actually replace the CompositeResolver, but it's guaranteed to be autoloaded before the actual CompositeResolver.
// We just hook the CompositeResolver to track it.

use OpenTelemetry\Contrib\Otlp\OtlpUtil;
use OpenTelemetry\API\Signals;

\DDTrace\install_hook(
'OpenTelemetry\SDK\Common\Configuration\Resolver\CompositeResolver::__construct',
null,
function (\DDTrace\HookData $hook) {

$this->addResolver(new class () implements \OpenTelemetry\SDK\Common\Configuration\Resolver\ResolverInterface {
public function retrieveValue(string $name): mixed
{
// Only configure metrics-related settings if DD_METRICS_OTEL_ENABLED is true
if (($name === 'OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE' ||
$name === 'OTEL_EXPORTER_OTLP_METRICS_ENDPOINT') &&
!\dd_trace_env_config('DD_METRICS_OTEL_ENABLED')) {
return null;
}

if ($name === 'OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE') {
return "delta";
}
if ($name === 'OTEL_EXPORTER_OTLP_ENDPOINT' || $name === 'OTEL_EXPORTER_OTLP_METRICS_ENDPOINT') {
// Determine protocol
$protocol = null;

if ($name === 'OTEL_EXPORTER_OTLP_METRICS_ENDPOINT' && \OpenTelemetry\SDK\Common\Configuration\Configuration::has('OTEL_EXPORTER_OTLP_METRICS_PROTOCOL')) {
// Get metrics-specific protocol
$protocol = \OpenTelemetry\SDK\Common\Configuration\Configuration::getEnum('OTEL_EXPORTER_OTLP_METRICS_PROTOCOL');
}

if ($protocol === null) {
// Get general OTLP protocol
$protocol = \OpenTelemetry\SDK\Common\Configuration\Configuration::getEnum('OTEL_EXPORTER_OTLP_PROTOCOL');
}

if ($protocol === null) {
// Use language default
$protocol = 'http/protobuf';
}

// Determine endpoint

// Check for general OTLP endpoint (only when requesting metrics endpoint)
if ($name === 'OTEL_EXPORTER_OTLP_METRICS_ENDPOINT' && \OpenTelemetry\SDK\Common\Configuration\Configuration::has('OTEL_EXPORTER_OTLP_ENDPOINT')) {
$generalEndpoint = rtrim(\OpenTelemetry\SDK\Common\Configuration\Configuration::getString('OTEL_EXPORTER_OTLP_ENDPOINT'), '/');
// May need to add subpath for metrics endpoint with HTTP protocol
if ($protocol !== 'grpc') {
return "$generalEndpoint/v1/metrics";
}
return $generalEndpoint.OtlpUtil::method(Signals::METRICS);
}

// Get agent host from DD_AGENT_HOST or DD_TRACE_AGENT_URL
$host = null;
$scheme = 'http';
$port = null;

// First check DD_TRACE_AGENT_URL for unix sockets or full URLs
$agentUrl = \dd_trace_env_config('DD_TRACE_AGENT_URL');
if ($agentUrl !== '') {
$component = \parse_url($agentUrl);
if ($component !== false) {
$scheme = $component['scheme'] ?? 'http';

// Handle unix scheme - return as-is
if ($scheme === 'unix') {
// Unix sockets: pass through the full URL
// The SDK must be configured with a URL in the format unix:///path/to/socket.sock
return $agentUrl;
}

$host = $component['host'] ?? null;
}
}

// Fall back to DD_AGENT_HOST if no URL was set
if ($host === null) {
$ddAgentHost = \dd_trace_env_config('DD_AGENT_HOST');
if ($ddAgentHost !== '') {
$host = $ddAgentHost;
}
}

// Build endpoint: {scheme}://{host}:{port}
if ($host === '') {
$host = 'localhost';
}

// Determine port based on protocol if not already set
$port = ($protocol === 'grpc') ? '4317' : '4318';
$endpoint = $scheme . '://' . $host . ':' . $port;

if ($name === 'OTEL_EXPORTER_OTLP_METRICS_ENDPOINT') {
// Add subpath for metrics endpoint with HTTP protocol
if ($protocol !== 'grpc') {
return $endpoint.'/v1/metrics';
}
else {
return $endpoint.OtlpUtil::method(Signals::METRICS);
}
}
return $endpoint;
}

// Explicitly return null to match the original implicit behavior.
return null;
}

public function hasVariable(string $variableName): bool {
// Only provide default values if DD_METRICS_OTEL_ENABLED is true
// AND the variable is not already set in the environment
if ($variableName === 'OTEL_EXPORTER_OTLP_METRICS_ENDPOINT' ||
$variableName === 'OTEL_EXPORTER_OTLP_ENDPOINT' ||
$variableName === 'OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE') {
return \dd_trace_env_config('DD_METRICS_OTEL_ENABLED');
}
return false;
}
});
}
);
29 changes: 29 additions & 0 deletions src/DDTrace/OpenTelemetry/Detectors/Environment.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php

use OpenTelemetry\SDK\Common\Attribute\AttributesFactory;
use OpenTelemetry\SDK\Resource\ResourceInfo;

\DDTrace\install_hook(
'OpenTelemetry\SDK\Resource\Detectors\Environment::getResource',
null,
function (\DDTrace\HookData $hook) {
$attributes = [];

if (\dd_trace_env_config('DD_ENV')!='') {
$attributes['deployment.environment.name'] = \dd_trace_env_config('DD_ENV');
}

if (\dd_trace_env_config('DD_VERSION') != '') {
$attributes['service.version'] = \dd_trace_env_config('DD_VERSION');
}

foreach (\dd_trace_env_config('DD_TAGS') as $key => $value) {
$attributes[$key] = $value;
}

$builder = (new AttributesFactory)->builder($attributes);
$newResource = ResourceInfo::create($builder->build());
$resource = $hook->returned;
$resource = $resource->merge($newResource);
$hook->overrideReturnValue($resource);
});
21 changes: 21 additions & 0 deletions src/DDTrace/OpenTelemetry/Detectors/Host.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?php

use OpenTelemetry\SDK\Common\Attribute\AttributesFactory;
use OpenTelemetry\SDK\Resource\ResourceInfo;

\DDTrace\install_hook(
'OpenTelemetry\SDK\Resource\Detectors\Host::getResource',
null,
function (\DDTrace\HookData $hook) {
$attributes = [];

if (\dd_trace_env_config('DD_TRACE_REPORT_HOSTNAME')) {
$attributes['host.name'] = \dd_trace_env_config('DD_HOSTNAME');
}

$builder = (new AttributesFactory)->builder($attributes);
$newResource = ResourceInfo::create($builder->build());
$resource = $hook->returned;
$resource = $resource->merge($newResource);
$hook->overrideReturnValue($resource);
});
27 changes: 27 additions & 0 deletions src/DDTrace/OpenTelemetry/Detectors/Service.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php

use OpenTelemetry\SDK\Common\Attribute\AttributesFactory;
use OpenTelemetry\SDK\Resource\ResourceInfo;

\DDTrace\install_hook(
'OpenTelemetry\SDK\Resource\Detectors\Service::getResource',
null,
function (\DDTrace\HookData $hook) {
$attributes = [];

$rootSpan = \DDTrace\root_span();
if ($rootSpan) {
$attributes['service.name'] = $rootSpan->service;
} else {
if (ddtrace_config_app_name() === '') {
return;
}
$attributes['service.name'] = \ddtrace_config_app_name();
}

$builder = (new AttributesFactory)->builder($attributes);
$newResource = ResourceInfo::create($builder->build());
$resource = $hook->returned;
$resource = $resource->merge($newResource);
$hook->overrideReturnValue($resource);
});
2 changes: 1 addition & 1 deletion src/DDTrace/OpenTelemetry/Span.php
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,7 @@ public function getKind(): int
/**
* @inheritDoc
*/
public function getAttribute(string $key)
public function getAttribute(string $key): mixed
{
return $this->span->meta[$key] ?? ($this->span->metrics[$key] ?? null);
}
Expand Down
4 changes: 4 additions & 0 deletions src/bridge/_files_opentelemetry.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,12 @@
return [
__DIR__ . '/../DDTrace/OpenTelemetry/Context.php',
__DIR__ . '/../DDTrace/OpenTelemetry/Convention.php',
__DIR__ . '/../DDTrace/OpenTelemetry/CompositeResolver.php',
__DIR__ . '/../DDTrace/OpenTelemetry/SpanContext.php',
__DIR__ . '/../DDTrace/OpenTelemetry/Span.php',
__DIR__ . '/../DDTrace/OpenTelemetry/SpanBuilder.php',
__DIR__ . '/../DDTrace/OpenTelemetry/CachedInstrumentation.php',
__DIR__ . '/../DDTrace/OpenTelemetry/Detectors/Environment.php',
__DIR__ . '/../DDTrace/OpenTelemetry/Detectors/Host.php',
__DIR__ . '/../DDTrace/OpenTelemetry/Detectors/Service.php',
];
Loading