Skip to content
Open
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
2 changes: 1 addition & 1 deletion ext/autoload_php_files.c
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ 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;
dd_load_files("opentelemetry");
if ((ce = zend_hash_find_ptr(EG(class_table), lc_name))) {
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
19 changes: 19 additions & 0 deletions ext/ddtrace.c
Original file line number Diff line number Diff line change
Expand Up @@ -2851,6 +2851,25 @@ PHP_FUNCTION(dd_trace_internal_fn) {
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 (params_count == 2 && FUNCTION_NAME_MATCHES("track_otel_config")) {
zval *config_name = ZVAL_VARARG_PARAM(params, 0);
zval *config_value = ZVAL_VARARG_PARAM(params, 1);
if (Z_TYPE_P(config_name) == IS_STRING) {
// 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);
RETVAL_TRUE;
}
} else if (params_count == 3 && FUNCTION_NAME_MATCHES("track_telemetry_metrics")) {
zval *metric_name = ZVAL_VARARG_PARAM(params, 0);
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));
RETVAL_TRUE;
}
} else if (FUNCTION_NAME_MATCHES("dump_sidecar")) {
if (!ddtrace_sidecar) {
RETURN_FALSE;
Expand Down
2 changes: 2 additions & 0 deletions ext/ddtrace.h
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,8 @@ ZEND_BEGIN_MODULE_GLOBALS(ddtrace)

HashTable resource_weak_storage;
dtor_func_t resource_dtor_func;

HashTable otel_config_telemetry;
ZEND_END_MODULE_GLOBALS(ddtrace)
// clang-format on

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_COPY(&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
14 changes: 14 additions & 0 deletions ext/telemetry.c
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ void ddtrace_telemetry_first_init(void) {

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;
Expand All @@ -98,6 +99,7 @@ void ddtrace_telemetry_rinit(void) {

void ddtrace_telemetry_rshutdown(void) {
zend_hash_destroy(&DDTRACE_G(telemetry_spans_created_per_integration));
zend_hash_destroy(&DDTRACE_G(otel_config_telemetry));
}

// Register in the sidecar services not bound to the request lifetime
Expand Down Expand Up @@ -195,6 +197,18 @@ void ddtrace_telemetry_finalize() {
if (injection_enabled) {
ddog_sidecar_telemetry_enqueueConfig_buffer(buffer, DDOG_CHARSLICE_C("ssi_injection_enabled"), (ddog_CharSlice) {.ptr = injection_enabled, .len = strlen(injection_enabled)}, DDOG_CONFIGURATION_ORIGIN_ENV_VAR, DDOG_CHARSLICE_C(""));
}

// 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) {
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));
// OTel configurations are from environment variables
ddog_sidecar_telemetry_enqueueConfig_buffer(buffer, name, value, DDOG_CONFIGURATION_ORIGIN_ENV_VAR, DDOG_CHARSLICE_C(""));
}
} ZEND_HASH_FOREACH_END();
}

// Send information about explicitly disabled integrations
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;
}
});
}
);
Loading
Loading