Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement OTel config remapping #2691

Merged
merged 4 commits into from
Jun 7, 2024
Merged
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: 2 additions & 0 deletions components-rs/ddtrace.h
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,8 @@ bool ddtrace_detect_composer_installed_json(struct ddog_SidecarTransport **trans

struct ddog_SidecarActionsBuffer *ddog_sidecar_telemetry_buffer_alloc(void);

void ddog_sidecar_telemetry_buffer_drop(struct ddog_SidecarActionsBuffer*);

void ddog_sidecar_telemetry_addIntegration_buffer(struct ddog_SidecarActionsBuffer *buffer,
ddog_CharSlice integration_name,
ddog_CharSlice integration_version,
Expand Down
3 changes: 3 additions & 0 deletions components-rs/telemetry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,9 @@ pub extern "C" fn ddog_sidecar_telemetry_buffer_alloc() -> Box<SidecarActionsBuf
SidecarActionsBuffer::default().into()
}

#[no_mangle]
pub extern "C" fn ddog_sidecar_telemetry_buffer_drop(_: Box<SidecarActionsBuffer>) {}

#[no_mangle]
pub unsafe extern "C" fn ddog_sidecar_telemetry_addIntegration_buffer(
buffer: &mut SidecarActionsBuffer,
Expand Down
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", \
zacharycmontoya marked this conversation as resolved.
Show resolved Hide resolved
.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
3 changes: 3 additions & 0 deletions ext/ddtrace.c
Original file line number Diff line number Diff line change
Expand Up @@ -572,6 +572,9 @@ static PHP_GSHUTDOWN_FUNCTION(ddtrace) {
ddog_agent_remote_config_reader_drop(ddtrace_globals->remote_config_reader);
}
zai_hook_gshutdown();
if (ddtrace_globals->telemetry_buffer) {
ddog_sidecar_telemetry_buffer_drop(ddtrace_globals->telemetry_buffer);
}

#ifdef CXA_THREAD_ATEXIT_WRAPPER
// FrankenPHP calls `ts_free_thread()` in rshutdown
Expand Down
1 change: 1 addition & 0 deletions ext/ddtrace.h
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ ZEND_BEGIN_MODULE_GLOBALS(ddtrace)
zend_string *last_flushed_root_env_name;

HashTable telemetry_spans_created_per_integration;
ddog_SidecarActionsBuffer *telemetry_buffer;

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

ZEND_EXTERN_MODULE_GLOBALS(ddtrace);

static void report_otel_cfg_telemetry_invalid(const char *otel_cfg, const char *dd_cfg, bool pre_rinit) {
if (!pre_rinit && ddtrace_sidecar && get_DD_INSTRUMENTATION_TELEMETRY_ENABLED()) {
ddog_SidecarActionsBuffer *buffer = ddtrace_telemetry_buffer();
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);
}
}

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", 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) {
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", 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) {
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", pre_rinit);
}
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;
}
Loading
Loading