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

Add a DDTrace\generate_distributed_tracing_headers() function #1905

Merged
merged 1 commit into from
Feb 3, 2023
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: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
"ext-posix": "*",
"g1a/composer-test-scenarios": "~3.0",
"mockery/mockery": "*",
"phpunit/phpunit": "*",
"phpunit/phpunit": "<10",
"squizlabs/php_codesniffer": "^3.3.0",
"symfony/process": "<5"
},
Expand Down
12 changes: 12 additions & 0 deletions ext/ddtrace.c
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
#include "dogstatsd_client.h"
#include "engine_hooks.h"
#include "excluded_modules.h"
#include "handlers_http.h"
#include "handlers_internal.h"
#include "integrations/integrations.h"
#include "ip_extraction.h"
Expand Down Expand Up @@ -2005,6 +2006,16 @@ static PHP_FUNCTION(consume_distributed_tracing_headers) {
RETURN_NULL();
}

/* {{{ proto array generate_distributed_tracing_headers() */
static PHP_FUNCTION(generate_distributed_tracing_headers) {
UNUSED(execute_data);

array_init(return_value);
if (get_DD_TRACE_ENABLED()) {
ddtrace_inject_distributed_headers(Z_ARR_P(return_value), true);
Comment on lines +2014 to +2015
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If a given request had distributed headers passed to it, do we need to pass on those headers in outgoing requests even if the tracer is disabled? My memory isn't clear here, but IIRC there's something like that we should be doing.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the tracer is disabled, we don't even read the distributed headers. So, here, no, we should not do now.

Maybe, if it's something we should do, we need to refactor a couple things, but that should be separate work.

}
}

/* {{{ proto string dd_trace_closed_spans_count() */
static PHP_FUNCTION(dd_trace_closed_spans_count) {
UNUSED(execute_data);
Expand Down Expand Up @@ -2126,6 +2137,7 @@ static const zend_function_entry ddtrace_functions[] = {
DDTRACE_NS_FE(current_context, arginfo_ddtrace_void),
DDTRACE_NS_FE(set_distributed_tracing_context, arginfo_dd_trace_set_distributed_tracing_context),
DDTRACE_NS_FE(consume_distributed_tracing_headers, arginfo_consume_distributed_tracing_headers),
DDTRACE_NS_FE(generate_distributed_tracing_headers, arginfo_ddtrace_void),
DDTRACE_FE(dd_trace_reset, arginfo_ddtrace_void),
DDTRACE_FE(dd_trace_send_traces_via_thread, arginfo_dd_trace_send_traces_via_thread),
DDTRACE_FE(dd_trace_serialize_closed_spans, arginfo_ddtrace_void),
Expand Down
2 changes: 1 addition & 1 deletion ext/handlers_curl.c
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ static void dd_inject_distributed_tracing_headers(zend_object *ch) {
array_init(&headers);
}

ddtrace_inject_distributed_headers(Z_ARR(headers));
ddtrace_inject_distributed_headers(Z_ARR(headers), false);

zend_function *setopt_fn = zend_hash_str_find_ptr(EG(function_table), ZEND_STRL("curl_setopt"));

Expand Down
2 changes: 1 addition & 1 deletion ext/handlers_curl_php7.c
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ static int dd_inject_distributed_tracing_headers(zval *ch) {
array_init(&headers);
}

ddtrace_inject_distributed_headers(Z_ARR(headers));
ddtrace_inject_distributed_headers(Z_ARR(headers), false);

zend_function *setopt_fn = zend_hash_str_find_ptr(EG(function_table), ZEND_STRL("curl_setopt"));

Expand Down
56 changes: 32 additions & 24 deletions ext/handlers_http.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,17 @@

ZEND_EXTERN_MODULE_GLOBALS(ddtrace);

static inline void ddtrace_inject_distributed_headers(zend_array *array) {
static inline void ddtrace_inject_distributed_headers(zend_array *array, bool key_value_pairs) {
zval headers;
ZVAL_ARR(&headers, array);

#define ADD_HEADER(header, ...) \
if (key_value_pairs) { \
add_assoc_str_ex(&headers, ZEND_STRL(header), zend_strpprintf(0, __VA_ARGS__)); \
} else { \
add_next_index_str(&headers, zend_strpprintf(0, header ": " __VA_ARGS__)); \
}

zend_array *inject = zai_config_is_modified(DDTRACE_CONFIG_DD_TRACE_PROPAGATION_STYLE)
&& !zai_config_is_modified(DDTRACE_CONFIG_DD_TRACE_PROPAGATION_STYLE_INJECT)
? get_DD_TRACE_PROPAGATION_STYLE() : get_DD_TRACE_PROPAGATION_STYLE_INJECT();
Expand All @@ -23,54 +30,53 @@ static inline void ddtrace_inject_distributed_headers(zend_array *array) {
zend_long sampling_priority = ddtrace_fetch_prioritySampling_from_root();
if (sampling_priority != DDTRACE_PRIORITY_SAMPLING_UNKNOWN) {
if (send_datadog) {
add_next_index_str(&headers,
zend_strpprintf(0, "x-datadog-sampling-priority: " ZEND_LONG_FMT, sampling_priority));
ADD_HEADER("x-datadog-sampling-priority", ZEND_LONG_FMT, sampling_priority);
}
if (send_b3) {
if (sampling_priority <= 0) {
add_next_index_string(&headers, "X-B3-Sampled: 0");
ADD_HEADER("x-b3-sampled", "0");
} else if (sampling_priority == PRIORITY_SAMPLING_USER_KEEP) {
add_next_index_string(&headers, "X-B3-Flags: 1");
ADD_HEADER("x-b3-flags", "1");
} else {
add_next_index_string(&headers, "X-B3-Sampled: 1");
ADD_HEADER("x-b3-sampled", "1");
}
}
}
zend_string *propagated_tags = ddtrace_format_propagated_tags();
if (send_datadog || send_b3 || send_b3single) {
if (propagated_tags) {
add_next_index_str(&headers, zend_strpprintf(0, "x-datadog-tags: %s", ZSTR_VAL(propagated_tags)));
ADD_HEADER("x-datadog-tags", "%s", ZSTR_VAL(propagated_tags));
}
if (DDTRACE_G(dd_origin)) {
add_next_index_str(&headers, zend_strpprintf(0, "x-datadog-origin: %s", ZSTR_VAL(DDTRACE_G(dd_origin))));
ADD_HEADER("x-datadog-origin", "%s", ZSTR_VAL(DDTRACE_G(dd_origin)));
}
}
ddtrace_trace_id trace_id = ddtrace_peek_trace_id();
uint64_t span_id = ddtrace_peek_span_id();
if (trace_id.low || trace_id.high) {
if (send_datadog) {
add_next_index_str(&headers, zend_strpprintf(0, "x-datadog-trace-id: %" PRIu64, trace_id.low));
ADD_HEADER("x-datadog-trace-id", "%" PRIu64, trace_id.low);
}
if (send_b3) {
if (trace_id.high) {
add_next_index_str(&headers, zend_strpprintf(0, "X-B3-TraceId: %016" PRIx64 "%016" PRIx64, trace_id.high, trace_id.low));
ADD_HEADER("X-B3-TraceId", "%016" PRIx64 "%016" PRIx64, trace_id.high, trace_id.low);
} else {
add_next_index_str(&headers, zend_strpprintf(0, "X-B3-TraceId: %016" PRIx64, trace_id.low));
ADD_HEADER("X-B3-TraceId", "%016" PRIx64, trace_id.low);
}
}
if (span_id) {
if (send_datadog) {
add_next_index_str(&headers, zend_strpprintf(0, "x-datadog-parent-id: %" PRIu64, span_id));
ADD_HEADER("x-datadog-parent-id", "%" PRIu64, span_id);
}
if (send_b3) {
add_next_index_str(&headers, zend_strpprintf(0, "X-B3-SpanId: %016" PRIx64, span_id));
ADD_HEADER("X-B3-SpanId", "%016" PRIx64, span_id);
}
if (send_tracestate) {
add_next_index_str(&headers, zend_strpprintf(0, "traceparent: 00-%016" PRIx64 "%016" PRIx64 "-%016" PRIx64 "-%02" PRIx8,
trace_id.high,
trace_id.low,
span_id,
sampling_priority > 0));
ADD_HEADER("traceparent", "00-%016" PRIx64 "%016" PRIx64 "-%016" PRIx64 "-%02" PRIx8,
trace_id.high,
trace_id.low,
span_id,
sampling_priority > 0);

smart_str str = {0};

Expand Down Expand Up @@ -138,7 +144,7 @@ static inline void ddtrace_inject_distributed_headers(zend_array *array) {
}

if (str.s) {
add_next_index_str(&headers, zend_strpprintf(0, "tracestate: %s%.*s", hasdd ? "dd=" : "", (int)ZSTR_LEN(str.s), ZSTR_VAL(str.s)));
ADD_HEADER("tracestate", "%s%.*s", hasdd ? "dd=" : "", (int)ZSTR_LEN(str.s), ZSTR_VAL(str.s));
smart_str_free(&str);
}
}
Expand All @@ -163,16 +169,18 @@ static inline void ddtrace_inject_distributed_headers(zend_array *array) {
} else {
sprintf(trace_id_buf, "%016" PRIx64, trace_id.low);
}
add_next_index_str(&headers, zend_strpprintf(0, "b3: %s-%016" PRIx64 "%s%s",
trace_id_buf,
span_id,
b3_sampling_decision ? "-" : "", b3_sampling_decision ? b3_sampling_decision : ""));
ADD_HEADER("b3", "%s-%016" PRIx64 "%s%s",
trace_id_buf,
span_id,
b3_sampling_decision ? "-" : "", b3_sampling_decision ? b3_sampling_decision : "");
} else if (b3_sampling_decision) {
add_next_index_str(&headers, zend_strpprintf(0, "b3: %s", b3_sampling_decision));
ADD_HEADER("b3", "%s", b3_sampling_decision);
}
}

if (propagated_tags) {
zend_string_release(propagated_tags);
}
}

#undef ADD_HEADER
2 changes: 1 addition & 1 deletion tests/composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
},
"require-dev": {
"mockery/mockery": "*",
"phpunit/phpunit": "*",
"phpunit/phpunit": "<10",
"phpspec/prophecy": "*",
"symfony/process": "<5",
"g1a/composer-test-scenarios": "~3.0"
Expand Down
29 changes: 29 additions & 0 deletions tests/ext/distributed_tracing/distributed_trace_generate.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
--TEST--
Test generate_distributed_tracing_headers()
--ENV--
HTTP_X_DATADOG_TRACE_ID=42
HTTP_X_DATADOG_PARENT_ID=10
HTTP_X_DATADOG_ORIGIN=datadog
HTTP_X_DATADOG_SAMPLING_PRIORITY=3
DD_TRACE_GENERATE_ROOT_SPAN=0
--FILE--
<?php

var_dump(DDTrace\generate_distributed_tracing_headers());

?>
--EXPECT--
array(6) {
["x-datadog-sampling-priority"]=>
string(1) "3"
["x-datadog-origin"]=>
string(7) "datadog"
["x-datadog-trace-id"]=>
string(2) "42"
["x-datadog-parent-id"]=>
string(2) "10"
["traceparent"]=>
string(55) "00-0000000000000000000000000000002a-000000000000000a-01"
["tracestate"]=>
string(16) "dd=o:datadog;s:3"
}