Skip to content

Commit

Permalink
Implement OTel config remapping
Browse files Browse the repository at this point in the history
Signed-off-by: Bob Weinand <bob.weinand@datadoghq.com>
  • Loading branch information
bwoebi committed Jun 6, 2024
1 parent c582c9f commit 969e9ae
Show file tree
Hide file tree
Showing 13 changed files with 365 additions and 51 deletions.
3 changes: 2 additions & 1 deletion config.m4
Original file line number Diff line number Diff line change
Expand Up @@ -157,8 +157,9 @@ if test "$PHP_DDTRACE" != "no"; then
ext/integrations/integrations.c \
ext/ip_extraction.c \
ext/logging.c \
ext/memory_limit.c \
ext/limiter/limiter.c \
ext/memory_limit.c \
ext/otel_config.c \
ext/priority_sampling/priority_sampling.c \
ext/profiling.c \
ext/random.c \
Expand Down
2 changes: 1 addition & 1 deletion config.w32
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ if (PHP_DDTRACE != 'no') {

var version = PHP_VERSION * 100 + PHP_MINOR_VERSION;

var DDTRACE_EXT_SOURCES = "arrays.c auto_flush.c autoload_php_files.c compat_string.c configuration.c distributed_tracing_headers.c ddshared.c dogstatsd.c engine_api.c engine_hooks.c excluded_modules.c handlers_api.c handlers_curl" + (version < 800 ? "_php7" : "") + ".c handlers_exception.c handlers_internal.c handlers_pcntl.c ip_extraction.c logging.c memory_limit.c profiling.c random.c serializer.c sidecar.c span.c startup_logging.c telemetry.c user_request.c";
var DDTRACE_EXT_SOURCES = "arrays.c auto_flush.c autoload_php_files.c compat_string.c configuration.c distributed_tracing_headers.c ddshared.c dogstatsd.c engine_api.c engine_hooks.c excluded_modules.c handlers_api.c handlers_curl" + (version < 800 ? "_php7" : "") + ".c handlers_exception.c handlers_internal.c handlers_pcntl.c ip_extraction.c logging.c memory_limit.c otel_config.c profiling.c random.c serializer.c sidecar.c span.c startup_logging.c telemetry.c user_request.c";
if (version >= 800 && version < 802) {
DDTRACE_EXT_SOURCES += " weakrefs.c";
}
Expand Down
29 changes: 20 additions & 9 deletions ext/configuration.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include "ddtrace_string.h"
#include "integrations/integrations.h"
#include "span.h"
#include "otel_config.h"

// note: only call this if ddtrace_config_trace_enabled() returns true
bool ddtrace_config_integration_enabled(ddtrace_integration_name integration_name);
Expand Down Expand Up @@ -92,21 +93,25 @@ enum ddtrace_sampling_rules_format {
CONFIG(STRING, DD_API_KEY, "", .ini_change = zai_config_system_ini_change) \
CONFIG(BOOL, DD_DISTRIBUTED_TRACING, "true") \
CONFIG(STRING, DD_DOGSTATSD_PORT, "8125") \
CONFIG(STRING, DD_ENV, "", .ini_change = ddtrace_alter_dd_env) \
CONFIG(STRING, DD_ENV, "", .ini_change = ddtrace_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 = ddtrace_alter_dd_service, \
.env_config_fallback = ddtrace_conf_otel_service_name) \
CONFIG(MAP, DD_SERVICE_MAPPING, "") \
CONFIG(MAP, DD_TAGS, "") \
CONFIG(MAP, DD_TAGS, "", \
.env_config_fallback = ddtrace_conf_otel_resource_attributes_tags) \
CONFIG(INT, DD_TRACE_AGENT_PORT, "0", .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") \
CONFIG(BOOL, DD_TRACE_CLI_ENABLED, "false") \
CONFIG(BOOL, DD_TRACE_MEASURE_COMPILE_TIME, "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_ENABLED, "true", .ini_change = ddtrace_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_TRACE_HEALTH_METRICS_ENABLED, "false", .ini_change = zai_config_system_ini_change) \
CONFIG(DOUBLE, DD_TRACE_HEALTH_METRICS_HEARTBEAT_SAMPLE_RATE, "0.001") \
Expand All @@ -126,7 +131,8 @@ enum ddtrace_sampling_rules_format {
CONFIG(SET, DD_TRACE_HTTP_URL_QUERY_PARAM_ALLOWED, "*") \
CONFIG(SET, DD_TRACE_HTTP_POST_DATA_PARAM_ALLOWED, "") \
CONFIG(INT, DD_TRACE_RATE_LIMIT, "0", .ini_change = zai_config_system_ini_change) \
CONFIG(DOUBLE, DD_TRACE_SAMPLE_RATE, "-1") \
CONFIG(DOUBLE, DD_TRACE_SAMPLE_RATE, "-1", \
.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, "[]") \
Expand All @@ -139,7 +145,8 @@ enum ddtrace_sampling_rules_format {
CONFIG(BOOL, DD_TRACE_PROPAGATE_SERVICE, "false") \
CONFIG(SET_LOWERCASE, DD_TRACE_PROPAGATION_STYLE_EXTRACT, "datadog,tracecontext,B3,B3 single header") \
CONFIG(SET_LOWERCASE, DD_TRACE_PROPAGATION_STYLE_INJECT, "datadog,tracecontext") \
CONFIG(SET_LOWERCASE, DD_TRACE_PROPAGATION_STYLE, "datadog,tracecontext") \
CONFIG(SET_LOWERCASE, DD_TRACE_PROPAGATION_STYLE, "datadog,tracecontext", \
.env_config_fallback = ddtrace_conf_otel_propagators) \
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) \
Expand Down Expand Up @@ -168,23 +175,27 @@ enum ddtrace_sampling_rules_format {
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 = ddtrace_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_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_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(BOOL, DD_TRACE_PROPAGATE_USER_ID_DEFAULT, "false") \
CONFIG(CUSTOM(INT), DD_DBM_PROPAGATION_MODE, "disabled", .parser = dd_parse_dbm_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_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) \
CONFIG(STRING, DD_TRACE_LOG_LEVEL, "error", .ini_change = ddtrace_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) \
DD_INTEGRATIONS

Expand Down
199 changes: 199 additions & 0 deletions ext/otel_config.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
#include "otel_config.h"
#include <env/env.h>
#include "ddtrace.h"
#include <components/log/log.h>
#include "sidecar.h"
#include "configuration.h"

ZEND_EXTERN_MODULE_GLOBALS(ddtrace);

static void report_otel_cfg_telemetry_invalid(const char *otel_cfg, const char *dd_cfg) {
if (ddtrace_sidecar && get_DD_INSTRUMENTATION_TELEMETRY_ENABLED()) {
UNUSED(otel_cfg, dd_cfg);
ddog_SidecarActionsBuffer *buffer = ddog_sidecar_telemetry_buffer_alloc();
ddog_sidecar_telemetry_register_metric_buffer(buffer, DDOG_CHARSLICE_C("tracers.otel.env.invalid"), DDOG_METRIC_NAMESPACE_TRACERS);
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("tracers.otel.env.invalid"), 1, tags);
free((char *)tags.ptr);
ddog_sidecar_telemetry_buffer_flush(&ddtrace_sidecar, ddtrace_sidecar_instance_id, &DDTRACE_G(telemetry_queue_id), buffer);
}
}

static bool get_otel_value(zai_str str, zai_env_buffer buf, bool pre_rinit) {
if (zai_getenv_ex(str, buf, pre_rinit) == ZAI_ENV_SUCCESS) {
return true;
}

zval *cfg = cfg_get_entry(str.ptr, str.len);
if (cfg) {
if (Z_TYPE_P(cfg) == IS_ARRAY) {
zval *val;
char *off = buf.ptr;
ZEND_HASH_FOREACH_VAL(Z_ARR_P(cfg), val) {
if (Z_TYPE_P(val) == IS_STRING) {
if (off - buf.ptr + Z_STRLEN_P(val) + 2 >= ZAI_ENV_MAX_BUFSIZ) {
return false;
}
if (off != buf.ptr) {
*off++ = ',';
}
memcpy(off, Z_STRVAL_P(val), Z_STRLEN_P(val));
off += Z_STRLEN_P(val);
}
} ZEND_HASH_FOREACH_END();
*off = 0;
} else if (Z_STRLEN_P(cfg) == 0 || Z_STRLEN_P(cfg) + 1 >= ZAI_ENV_MAX_BUFSIZ) {
return false;
} else {
memcpy(buf.ptr, Z_STRVAL_P(cfg), Z_STRLEN_P(cfg) + 1);
}
return true;
}

return false;
}

static bool ddtrace_conf_otel_resource_attributes_special(const char *tag, int len, zai_env_buffer buf, bool pre_rinit) {
if (!get_otel_value((zai_str)ZAI_STRL("OTEL_RESOURCE_ATTRIBUTES"), buf, pre_rinit)) {
return false;
}

for (char *cur = buf.ptr, *key_start = cur; *cur; ++cur) {
if (*cur == '=') {
char *key_end = cur++;
while (*cur && *cur != ',') {
++cur;
}
if (key_end - key_start == len && memcmp(key_start, tag, len) == 0 && key_end[1]) {
size_t vallen = cur - (key_end + 1);
memcpy(buf.ptr, key_end + 1, vallen);
buf.ptr[vallen] = 0;
return true;
}
key_start = cur-- + 1;
}
}

return false;
}

bool ddtrace_conf_otel_resource_attributes_env(zai_env_buffer buf, bool pre_rinit) {
return ddtrace_conf_otel_resource_attributes_special(ZEND_STRL("deployment.environment"), buf, pre_rinit);
}

bool ddtrace_conf_otel_resource_attributes_version(zai_env_buffer buf, bool pre_rinit) {
return ddtrace_conf_otel_resource_attributes_special(ZEND_STRL("service.version"), buf, pre_rinit);
}

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)
|| 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) {
if (!get_otel_value((zai_str)ZAI_STRL("OTEL_PROPAGATORS"), buf, pre_rinit)) {
return false;
}
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) {
memcpy(buf.ptr, ZEND_STRS("q1"));
return true;
}
if (strcmp(buf.ptr, "always_off") == 0 || strcmp(buf.ptr, "parentbased_always_off") == 0) {
memcpy(buf.ptr, ZEND_STRS("0"));
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", "trace.sample_rate");
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) {
memcpy(buf.ptr, ZEND_STRS("0"));
return true;
}
LOG_ONCE(WARN, "OTEL_TRACES_EXPORTER has invalid value: %s", buf.ptr);
report_otel_cfg_telemetry_invalid("OTEL_TRACES_EXPORTER", "trace.enabled");
}
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) {
memcpy(buf.ptr, ZEND_STRS("0"));
return true;
}
LOG_ONCE(WARN, "OTEL_METRICS_EXPORTER has invalid value: %s", buf.ptr);
report_otel_cfg_telemetry_invalid("OTEL_METRICS_EXPORTER", "integration_metrics_enabled");
}
return false;
}

bool ddtrace_conf_otel_resource_attributes_tags(zai_env_buffer buf, bool pre_rinit) {
if (!get_otel_value((zai_str)ZAI_STRL("OTEL_RESOURCE_ATTRIBUTES"), buf, pre_rinit)) {
return false;
}

char *out = buf.ptr;
int tags = 0;
for (char *cur = buf.ptr, *key_start = cur; *cur; ++cur) {
if (*cur == '=') {
char *key = key_start, *key_end = cur++;
while (*cur && *cur != ',') {
++cur;
}
key_start = cur + 1;
if (key_end - key == strlen("deployment.environment") && memcmp(key, ZEND_STRL("deployment.environment")) == 0) {
continue;
}
if (key_end - key == strlen("service.name") && memcmp(key, ZEND_STRL("service.name")) == 0) {
continue;
}
if (key_end - key == strlen("service.version") && memcmp(key, ZEND_STRL("service.version")) == 0) {
continue;
}
memmove(out, key, cur - key);
out[key_end - key] = ':';
out += cur - key;
*out++ = ',';
if (++tags == 10 && *cur) {
LOG_ONCE(WARN, "OTEL_RESOURCE_ATTRIBUTES has more than 10 tags, ignoring all of: %s", cur + 1);
break;
}
--cur;
}
}
if (out != buf.ptr) {
--out;
}
*out = 0;

return true;
}
16 changes: 16 additions & 0 deletions ext/otel_config.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#ifndef DD_OTEL_CONFIG_H
#define DD_OTEL_CONFIG_H

#include <env/env.h>

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
Loading

0 comments on commit 969e9ae

Please sign in to comment.