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

feat: API Gateway Tracing #3095

Open
wants to merge 45 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
f0c4bf2
Base Implementation
PROFeNoM Feb 7, 2025
4d706fb
fix: segfault
PROFeNoM Feb 10, 2025
39f9f2a
fix: duration
PROFeNoM Feb 10, 2025
fccd91b
fix: duration
PROFeNoM Feb 10, 2025
2bbf531
error log start/duration/duration_start
PROFeNoM Feb 10, 2025
291f75b
fix: duration
PROFeNoM Feb 10, 2025
6fc1632
x-dd-proxy-domain-name add debug logs
PROFeNoM Feb 10, 2025
162b382
service debug logs
PROFeNoM Feb 11, 2025
641811a
tests: Laravel x InferredProxy
PROFeNoM Feb 11, 2025
144de18
fix: Specifically do not inherit service property
PROFeNoM Feb 11, 2025
ba71c60
more debug logs
PROFeNoM Feb 12, 2025
9fb4ab9
fix: Don't overwrite inferred span's service.
PROFeNoM Feb 12, 2025
7153541
style: refactor service alter skip
PROFeNoM Feb 13, 2025
03c0569
feat: Octane Swoole support
PROFeNoM Feb 14, 2025
cf65501
style: Refactor using DDTRACE_INFERRED_SPAN type
PROFeNoM Feb 17, 2025
a1c525a
tests: Add some (unfinished) tests
PROFeNoM Feb 17, 2025
bd91a71
feat: Very quick Roadrunner support (to be enhanced)
PROFeNoM Feb 17, 2025
bcc25af
Set `_dd.inferred_span` to `1`
PROFeNoM Feb 17, 2025
d4b2745
tests: Clean EXPECTF section
PROFeNoM Feb 18, 2025
e91cc69
fix: Memory leak
PROFeNoM Feb 18, 2025
dbd2e66
chore: update snapshots
PROFeNoM Feb 18, 2025
3e1945c
tests: Distributed Tracing
PROFeNoM Feb 18, 2025
969ff8b
tests: Exceptions in Roadrunner/Swoole
PROFeNoM Feb 18, 2025
18a1527
fix: Laravel Latest CLI Test Script Location
PROFeNoM Feb 18, 2025
8c22cd5
fix: persisting DD_SERVICE on Laravel Tests
PROFeNoM Feb 18, 2025
42e3581
fix: Roadrunner tests order
PROFeNoM Feb 18, 2025
cf59fa3
fix: Laravel Connection issue
PROFeNoM Feb 18, 2025
509bc51
fix: Laravel Connection issue
PROFeNoM Feb 18, 2025
4c29c16
error output
PROFeNoM Feb 18, 2025
340b32e
error output
PROFeNoM Feb 18, 2025
5fb7511
Try to disable DD_TRACE_INFERRED_PROXY_SERVICES_ENABLED and see what …
PROFeNoM Feb 18, 2025
572fbfd
Try to split the tests
PROFeNoM Feb 19, 2025
f54687a
Remove logs
PROFeNoM Feb 19, 2025
ec98ccd
Totally split the tests
PROFeNoM Feb 19, 2025
ed31db3
style: Use `ddtrace_read_header`
PROFeNoM Feb 19, 2025
f0ccfa3
style: Remove some debug logs
PROFeNoM Feb 19, 2025
43f3bf1
style: Remove some debug logs
PROFeNoM Feb 19, 2025
e0bbd7a
Merge branch 'refs/heads/master' into alex/AIDM-548_api-gateway-bis
PROFeNoM Feb 19, 2025
d39e0b7
style: Change x-dd-proxy value from aws-apigateway to aws.apigateway
PROFeNoM Feb 20, 2025
6aecc1f
style: Remove duration from serialization debug logs
PROFeNoM Feb 20, 2025
926dd2b
fix: Prevent segfaults/mem leak on missing headers
PROFeNoM Feb 20, 2025
bdb31b5
style: one-liner
PROFeNoM Feb 20, 2025
e5707d7
style: change test description
PROFeNoM Feb 20, 2025
aaac753
Add a hashmap of supported proxies
PROFeNoM Feb 21, 2025
2a1da16
CR refactor
PROFeNoM Feb 27, 2025
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
4 changes: 4 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -981,6 +981,7 @@ TEST_WEB_82 := \
test_web_laravel_9x \
test_web_laravel_10x \
test_web_laravel_latest \
test_web_apigw \
test_web_laravel_octane_latest \
test_web_lumen_81 \
test_web_lumen_90 \
Expand Down Expand Up @@ -1042,6 +1043,7 @@ TEST_WEB_83 := \
test_web_laravel_9x \
test_web_laravel_10x \
test_web_laravel_latest \
test_web_apigw \
test_web_laravel_octane_latest \
test_web_lumen_81 \
test_web_lumen_90 \
Expand Down Expand Up @@ -1311,6 +1313,8 @@ test_integrations_sqlsrv: global_test_run_dependencies
$(eval TEST_EXTRA_INI=)
test_integrations_swoole_5: global_test_run_dependencies
$(call run_tests_debug,--testsuite=swoole-test)
test_web_apigw: global_test_run_dependencies tests/Frameworks/Laravel/Latest/composer.lock-php$(PHP_MAJOR_MINOR) tests/Frameworks/Laravel/Octane/Latest/composer.lock-php$(PHP_MAJOR_MINOR) tests/Frameworks/Roadrunner/Version_2/composer.lock-php$(PHP_MAJOR_MINOR)
$(call run_tests_debug,--testsuite=api-gateway-test)
test_web_cakephp_28: global_test_run_dependencies tests/Frameworks/CakePHP/Version_2_8/composer.lock-php$(PHP_MAJOR_MINOR)
$(call run_tests_debug,--testsuite=cakephp-28-test)
test_web_cakephp_310: global_test_run_dependencies tests/Frameworks/CakePHP/Version_3_10/composer.lock-php$(PHP_MAJOR_MINOR)
Expand Down
1 change: 1 addition & 0 deletions config.m4
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,7 @@ if test "$PHP_DDTRACE" != "no"; then
ext/handlers_kafka.c \
ext/handlers_pcntl.c \
ext/handlers_signal.c \
ext/inferred_proxy_headers.c \
ext/integrations/exec_integration.c \
ext/integrations/integrations.c \
ext/ip_extraction.c \
Expand Down
1 change: 1 addition & 0 deletions config.w32
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ if (PHP_DDTRACE != 'no') {
DDTRACE_EXT_SOURCES += " handlers_internal.c";
DDTRACE_EXT_SOURCES += " handlers_kafka.c";
DDTRACE_EXT_SOURCES += " handlers_pcntl.c";
DDTRACE_EXT_SOURCES += " inferred_proxy_headers.c";
DDTRACE_EXT_SOURCES += " ip_extraction.c";
DDTRACE_EXT_SOURCES += " standalone_limiter.c";
DDTRACE_EXT_SOURCES += " live_debugger.c";
Expand Down
1 change: 1 addition & 0 deletions ext/configuration.h
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,7 @@ enum ddtrace_sampling_rules_format {
CONFIG(SET, DD_DYNAMIC_INSTRUMENTATION_REDACTED_IDENTIFIERS, "", .ini_change = zai_config_system_ini_change) \
CONFIG(BOOL, DD_EXPERIMENTAL_APPSEC_STANDALONE_ENABLED, "false") \
CONFIG(SET, DD_DYNAMIC_INSTRUMENTATION_REDACTED_TYPES, "", .ini_change = zai_config_system_ini_change) \
CONFIG(BOOL, DD_TRACE_INFERRED_PROXY_SERVICES_ENABLED, "false") \
DD_INTEGRATIONS

#ifndef _WIN32
Expand Down
69 changes: 54 additions & 15 deletions ext/ddtrace.c
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@
#endif
#include "ddtrace_arginfo.h"
#include "distributed_tracing_headers.h"
#include "inferred_proxy_headers.h"
#include "live_debugger.h"
#include "agent_info.h"

Expand Down Expand Up @@ -374,20 +375,40 @@ bool ddtrace_alter_sampling_rules_file_config(zval *old_value, zval *new_value,
return dd_save_sampling_rules_file_config(Z_STR_P(new_value), PHP_INI_USER, PHP_INI_STAGE_RUNTIME);
}

static inline void dd_alter_prop(size_t prop_offset, zval *old_value, zval *new_value, zend_string *new_str) {
static inline void dd_alter_prop_common(size_t prop_offset, zval *old_value, zval *new_value, zend_string *new_str, bool skip_inferred) {
UNUSED(old_value, new_str);

ddtrace_span_properties *pspan = ddtrace_active_span_props();
while (pspan) {
if (skip_inferred) {
ddtrace_span_data *span = SPANDATA(pspan);
if (span->type == DDTRACE_INFERRED_SPAN) {
pspan = pspan->parent; // It should be NULL, but just in case...
continue;
}
}

zval *property = (zval *) (prop_offset + (char *) pspan), garbage = *property;
ZVAL_COPY(property, new_value);
zval_ptr_dtor(&garbage);
pspan = pspan->parent;
}
}

static inline void dd_alter_prop(size_t prop_offset, zval *old_value, zval *new_value, zend_string *new_str) {
dd_alter_prop_common(prop_offset, old_value, new_value, new_str, false);
}

static inline void dd_alter_prop_skip_inferred_span(size_t prop_offset, zval *old_value, zval *new_value, zend_string *new_str) {
dd_alter_prop_common(prop_offset, old_value, new_value, new_str, true);
}

bool ddtrace_alter_dd_service(zval *old_value, zval *new_value, zend_string *new_str) {
dd_alter_prop(XtOffsetOf(ddtrace_span_properties, property_service), old_value, new_value, new_str);
if (get_DD_TRACE_INFERRED_PROXY_SERVICES_ENABLED()) {
dd_alter_prop_skip_inferred_span(XtOffsetOf(ddtrace_span_properties, property_service), old_value, new_value, new_str);
} else {
dd_alter_prop(XtOffsetOf(ddtrace_span_properties, property_service), old_value, new_value, new_str);
}
if (DDTRACE_G(request_initialized)) {
ddtrace_sidecar_submit_root_span_data_direct(NULL, new_str, get_DD_ENV(), get_DD_VERSION());
}
Expand Down Expand Up @@ -932,6 +953,7 @@ static zend_object *ddtrace_root_span_data_create(zend_class_entry *class_type)
array_init(&span->property_propagated_tags);
array_init(&span->property_tracestate_tags);
#endif
span->inferred_root = NULL;
return &span->std;
}

Expand Down Expand Up @@ -1459,6 +1481,8 @@ static PHP_MINIT_FUNCTION(ddtrace) {
ddtrace_minit_remote_config();
ddtrace_appsec_minit();

ddtrace_init_proxy_info_map();

return SUCCESS;
}

Expand Down Expand Up @@ -1612,6 +1636,10 @@ static void dd_initialize_request(void) {
ddtrace_distributed_tracing_result distributed_result = ddtrace_read_distributed_tracing_ids(ddtrace_read_zai_header, NULL);
ddtrace_apply_distributed_tracing_result(&distributed_result, NULL);

if (get_DD_TRACE_INFERRED_PROXY_SERVICES_ENABLED()) {
ddtrace_infer_proxy_services();
}

if (get_DD_TRACE_GENERATE_ROOT_SPAN()) {
ddtrace_push_root_span();
}
Expand Down Expand Up @@ -2693,6 +2721,10 @@ PHP_FUNCTION(DDTrace_root_span) {
}
dd_ensure_root_span();
ddtrace_root_span_data *span = DDTRACE_G(active_stack)->root_span;
if (span && span->type == DDTRACE_INFERRED_SPAN) {
span = span->inferred_root;
}

if (span) {
RETURN_OBJ_COPY(&span->std);
}
Expand Down Expand Up @@ -2736,6 +2768,25 @@ PHP_FUNCTION(DDTrace_start_trace_span) {
dd_start_span(INTERNAL_FUNCTION_PARAM_PASSTHRU);
}

/* {{{ proto RootSpanData|null DDTrace\start_inferred_span(array $headers) */
PHP_FUNCTION(DDTrace_start_inferred_span) {
zval *headers_zv = NULL;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "a", &headers_zv) != SUCCESS) {
RETURN_THROWS();
}
zend_array *headers = Z_ARRVAL_P(headers_zv);

if (!get_DD_TRACE_ENABLED() || !get_DD_TRACE_INFERRED_PROXY_SERVICES_ENABLED()) {
RETURN_NULL();
}

ddtrace_root_span_data *root_span = ddtrace_open_inferred_span(headers);
if (root_span) {
RETURN_OBJ_COPY(&root_span->std);
}
RETURN_NULL();
}

static void dd_set_span_finish_time(ddtrace_span_data *span, double finish_time_seconds) {
// we do not expose the monotonic time here, so do not use it as reference time to calculate difference
uint64_t start_time = span->start;
Expand Down Expand Up @@ -3065,18 +3116,6 @@ static bool dd_read_userspace_header(zai_str zai_header, const char *lowercase_h
return true;
}

static bool dd_read_array_header(zai_str zai_header, const char *lowercase_header, zend_string **header_value, void *data) {
UNUSED(zai_header);
zend_array *array = (zend_array *) data;
zval *value = zend_hash_str_find(array, lowercase_header, strlen(lowercase_header));
if (!value) {
return false;
}

*header_value = zval_get_string(value);
return true;
}

static ddtrace_distributed_tracing_result dd_parse_distributed_tracing_headers_function(INTERNAL_FUNCTION_PARAMETERS, bool *success) {
UNUSED(return_value);

Expand Down Expand Up @@ -3119,7 +3158,7 @@ static ddtrace_distributed_tracing_result dd_parse_distributed_tracing_headers_f
func.fci.param_count = 1;

if (array) {
return ddtrace_read_distributed_tracing_ids(dd_read_array_header, array);
return ddtrace_read_distributed_tracing_ids(ddtrace_read_array_header, array);
} else if (use_server_headers) {
return ddtrace_read_distributed_tracing_ids(ddtrace_read_zai_header, &func);
} else {
Expand Down
6 changes: 6 additions & 0 deletions ext/ddtrace.stub.php
Original file line number Diff line number Diff line change
Expand Up @@ -545,6 +545,12 @@ function update_span_duration(SpanData $span, float $finishTime = 0): false|null
*/
function start_trace_span(float $startTime = 0): SpanData {}

/**
* @internal
* @return RootSpanData|null The newly created inferred root span, or 'null' if headers extraction failed.
*/
function start_inferred_span(array $headers): RootSpanData|null {}

/**
* Get the active stack
*
Expand Down
8 changes: 7 additions & 1 deletion ext/ddtrace_arginfo.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* This is a generated file, edit the .stub.php file instead.
* Stub hash: 5edec61a2b1ae22c8473ffbd3c509df6196abbae */
* Stub hash: 2ef1574e246f5a5c696b74152169237fad040333 */

ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_DDTrace_trace_method, 0, 3, _IS_BOOL, 0)
ZEND_ARG_TYPE_INFO(0, className, IS_STRING, 0)
Expand Down Expand Up @@ -65,6 +65,10 @@ ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_DDTrace_start_trace_span, 0, 0, D
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, startTime, IS_DOUBLE, 0, "0")
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_DDTrace_start_inferred_span, 0, 1, DDTrace\\RootSpanData, 1)
ZEND_ARG_TYPE_INFO(0, headers, IS_ARRAY, 0)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_DDTrace_active_stack, 0, 0, DDTrace\\SpanStack, 1)
ZEND_END_ARG_INFO()

Expand Down Expand Up @@ -318,6 +322,7 @@ ZEND_FUNCTION(DDTrace_start_span);
ZEND_FUNCTION(DDTrace_close_span);
ZEND_FUNCTION(DDTrace_update_span_duration);
ZEND_FUNCTION(DDTrace_start_trace_span);
ZEND_FUNCTION(DDTrace_start_inferred_span);
ZEND_FUNCTION(DDTrace_active_stack);
ZEND_FUNCTION(DDTrace_create_stack);
ZEND_FUNCTION(DDTrace_switch_stack);
Expand Down Expand Up @@ -402,6 +407,7 @@ static const zend_function_entry ext_functions[] = {
ZEND_RAW_FENTRY(ZEND_NS_NAME("DDTrace", "close_span"), zif_DDTrace_close_span, arginfo_DDTrace_close_span, 0, NULL, NULL)
ZEND_RAW_FENTRY(ZEND_NS_NAME("DDTrace", "update_span_duration"), zif_DDTrace_update_span_duration, arginfo_DDTrace_update_span_duration, 0, NULL, NULL)
ZEND_RAW_FENTRY(ZEND_NS_NAME("DDTrace", "start_trace_span"), zif_DDTrace_start_trace_span, arginfo_DDTrace_start_trace_span, 0, NULL, NULL)
ZEND_RAW_FENTRY(ZEND_NS_NAME("DDTrace", "start_inferred_span"), zif_DDTrace_start_inferred_span, arginfo_DDTrace_start_inferred_span, 0, NULL, NULL)
ZEND_RAW_FENTRY(ZEND_NS_NAME("DDTrace", "active_stack"), zif_DDTrace_active_stack, arginfo_DDTrace_active_stack, 0, NULL, NULL)
ZEND_RAW_FENTRY(ZEND_NS_NAME("DDTrace", "create_stack"), zif_DDTrace_create_stack, arginfo_DDTrace_create_stack, 0, NULL, NULL)
ZEND_RAW_FENTRY(ZEND_NS_NAME("DDTrace", "switch_stack"), zif_DDTrace_switch_stack, arginfo_DDTrace_switch_stack, 0, NULL, NULL)
Expand Down
12 changes: 12 additions & 0 deletions ext/distributed_tracing_headers.c
Original file line number Diff line number Diff line change
Expand Up @@ -522,3 +522,15 @@ bool ddtrace_read_zai_header(zai_str zai_header, const char *lowercase_header, z
*header_value = zend_string_copy(*header_value);
return true;
}

bool ddtrace_read_array_header(zai_str zai_header, const char *lowercase_header, zend_string **header_value, void *data) {
UNUSED(zai_header);
zend_array *array = (zend_array *) data;
zval *value = zend_hash_str_find(array, lowercase_header, strlen(lowercase_header));
if (!value) {
return false;
}

*header_value = zval_get_string(value);
return true;
}
1 change: 1 addition & 0 deletions ext/distributed_tracing_headers.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,6 @@ typedef bool (ddtrace_read_header)(zai_str zai_header, const char *lowercase_hea
ddtrace_distributed_tracing_result ddtrace_read_distributed_tracing_ids(ddtrace_read_header *read_header, void *data);
void ddtrace_apply_distributed_tracing_result(ddtrace_distributed_tracing_result *result, ddtrace_root_span_data *span);
bool ddtrace_read_zai_header(zai_str zai_header, const char *lowercase_header, zend_string **header_value, void *data);
bool ddtrace_read_array_header(zai_str zai_header, const char *lowercase_header, zend_string **header_value, void *data);

#endif // DD_DISTRIBUTED_TRACING_HEADERS_H
41 changes: 41 additions & 0 deletions ext/inferred_proxy_headers.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#include "inferred_proxy_headers.h"

ZEND_EXTERN_MODULE_GLOBALS(ddtrace);

static HashTable proxy_info_map;

void ddtrace_add_proxy_info(const char *system, const char *span_name, const char *component) {
ddtrace_proxy_info *info = pemalloc(sizeof(ddtrace_proxy_info), 1);
info->span_name = span_name;
info->component = component;
zend_hash_str_add_ptr(&proxy_info_map, system, strlen(system), info);
}

static void dd_proxy_info_dtor(zval *zv) {
pefree(Z_PTR_P(zv), 1);
}

void ddtrace_init_proxy_info_map(void) {
zend_hash_init(&proxy_info_map, 8, NULL, (dtor_func_t)dd_proxy_info_dtor, 1);

ddtrace_add_proxy_info("aws-apigateway", "aws.apigateway", "aws-apigateway");

// Add more proxies using ddtrace_add_proxy_info
}

ddtrace_inferred_proxy_result ddtrace_read_inferred_proxy_headers(ddtrace_read_header *read_header, void *data) {
ddtrace_inferred_proxy_result result = {0};

read_header((zai_str)ZAI_STRL("X_DD_PROXY"), "x-dd-proxy", &result.system, data);
read_header((zai_str)ZAI_STRL("X_DD_PROXY_REQUEST_TIME_MS"), "x-dd-proxy-request-time-ms", &result.start_time_ms, data);
read_header((zai_str)ZAI_STRL("X_DD_PROXY_PATH"), "x-dd-proxy-path", &result.path, data);
read_header((zai_str)ZAI_STRL("X_DD_PROXY_HTTPMETHOD"), "x-dd-proxy-httpmethod", &result.http_method, data);
read_header((zai_str)ZAI_STRL("X_DD_PROXY_DOMAIN_NAME"), "x-dd-proxy-domain-name", &result.domain, data);
read_header((zai_str)ZAI_STRL("X_DD_PROXY_STAGE"), "x-dd-proxy-stage", &result.stage, data);

return result;
}

const ddtrace_proxy_info* ddtrace_get_proxy_info(zend_string *system) {
return zend_hash_find_ptr(&proxy_info_map, system);
}
25 changes: 25 additions & 0 deletions ext/inferred_proxy_headers.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#ifndef DD_INFERRED_PROXY_HEADERS_H
#define DD_INFERRED_PROXY_HEADERS_H

#include "ddtrace.h"
#include "distributed_tracing_headers.h"

typedef struct {
zend_string *system;
zend_string *start_time_ms;
zend_string *path;
zend_string *http_method;
zend_string *domain;
zend_string *stage;
} ddtrace_inferred_proxy_result;

typedef struct {
const char *span_name;
const char *component;
} ddtrace_proxy_info;

ddtrace_inferred_proxy_result ddtrace_read_inferred_proxy_headers(ddtrace_read_header *read_header, void *data);
const ddtrace_proxy_info* ddtrace_get_proxy_info(zend_string *system);
void ddtrace_init_proxy_info_map(void);

#endif // DD_INFERRED_PROXY_HEADERS_H
Loading