From c0ae73677fb87dc3ab49885e196ae76d3f54b9c1 Mon Sep 17 00:00:00 2001 From: Alexandre Rulleau Date: Tue, 24 Feb 2026 17:03:16 +0100 Subject: [PATCH 1/5] test(request-replayer): restore latest request-replayer image Signed-off-by: Alexandre Rulleau --- .gitlab/generate-common.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab/generate-common.php b/.gitlab/generate-common.php index 7cb36765ea..009673d1e9 100644 --- a/.gitlab/generate-common.php +++ b/.gitlab/generate-common.php @@ -104,7 +104,7 @@ function dockerhub_login() { SNAPSHOT_REGEX_PLACEHOLDERS: 'path:/\S+/dd-trace-php(?=/),httpbin:(?<=//)httpbin-integration:8080' request-replayer: - name: registry.ddbuild.io/images/mirror/datadog/dd-trace-ci:php-request-replayer-2.0@sha256:4f26c11d568d2401bdd35d592aeff003b89b289e525166ee5ad376066877e4ad + name: registry.ddbuild.io/images/mirror/datadog/dd-trace-ci:php-request-replayer-2.0 alias: request-replayer command: ["php", "-S", ":80", "index.php"] variables: From 8d3e3f2ebb492a0e2e7966327107e94c1121e093 Mon Sep 17 00:00:00 2001 From: Alexandre Rulleau Date: Tue, 24 Feb 2026 17:21:13 +0100 Subject: [PATCH 2/5] test(crashtracker_segfault_disabled): limit number of iterations and properly filter Signed-off-by: Alexandre Rulleau --- tests/ext/crashtracker_segfault_disabled.phpt | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/tests/ext/crashtracker_segfault_disabled.phpt b/tests/ext/crashtracker_segfault_disabled.phpt index 654a966632..0307aea26e 100644 --- a/tests/ext/crashtracker_segfault_disabled.phpt +++ b/tests/ext/crashtracker_segfault_disabled.phpt @@ -22,6 +22,7 @@ datadog.trace.agent_test_session_token=tests/ext/crashtracker_segfault_disabled. include __DIR__ . '/includes/request_replayer.inc'; $rr = new RequestReplayer(); $rr->replayRequest(); // cleanup possible leftover +$rr->maxIteration = 100; usleep(100000); // Let time to the sidecar to open the crashtracker socket @@ -44,10 +45,15 @@ $rr->waitForRequest(function ($request) { foreach ($json["payload"]["logs"] as $payload) { $payload["message"] = json_decode($payload["message"], true); - $output = json_encode($payload, JSON_PRETTY_PRINT); + if (!isset($payload["message"]["metadata"])) { + continue; + } + if (($payload["message"]["kind"] ?? "") == "Crash ping") { + continue; + } + $output = json_encode($payload, JSON_PRETTY_PRINT); echo $output; - return true; } } From 023b7a9614b1b752f521a21c2ac0794dcc44499a Mon Sep 17 00:00:00 2001 From: Alexandre Rulleau Date: Wed, 25 Feb 2026 12:40:23 +0100 Subject: [PATCH 3/5] feat(request-replayer): write remote config requests to a separate file Signed-off-by: Alexandre Rulleau --- .../services/request-replayer/src/index.php | 20 ++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/dockerfiles/services/request-replayer/src/index.php b/dockerfiles/services/request-replayer/src/index.php index 43ec981cda..c40105a0b9 100644 --- a/dockerfiles/services/request-replayer/src/index.php +++ b/dockerfiles/services/request-replayer/src/index.php @@ -76,6 +76,7 @@ function decodeDogStatsDMetrics($metrics) define('REQUEST_NEXT_RESPONSE_FILE', getenv('REQUEST_NEXT_RESPONSE_FILE') ?: ("$temp_location/response.json")); define('REQUEST_LOG_FILE', getenv('REQUEST_LOG_FILE') ?: ("$temp_location/requests-log.txt")); define('REQUEST_RC_CONFIGS_FILE', getenv('REQUEST_RC_CONFIGS_FILE') ?: ("$temp_location/rc_configs.json")); +define('REQUEST_RC_REQUESTS_FILE', getenv('REQUEST_RC_REQUESTS_FILE') ?: ("$temp_location/rc_requests.json")); define('REQUEST_METRICS_FILE', getenv('REQUEST_METRICS_FILE') ?: ("$temp_location/metrics.json")); define('REQUEST_METRICS_LOG_FILE', getenv('REQUEST_METRICS_LOG_FILE') ?: ("$temp_location/metrics-log.txt")); define('REQUEST_AGENT_INFO_FILE', getenv('REQUEST_AGENT_INFO_FILE') ?: ("$temp_location/agent-info.txt")); @@ -124,6 +125,16 @@ function logRequest($message, $data = '') unlink(REQUEST_METRICS_LOG_FILE); logRequest('Returned last metrics and deleted metrics log', $request); break; + case '/replay-rc-requests': + if (!file_exists(REQUEST_RC_REQUESTS_FILE)) { + logRequest('Cannot replay RC requests; RC requests log does not exist'); + break; + } + $request = file_get_contents(REQUEST_RC_REQUESTS_FILE); + echo $request; + unlink(REQUEST_RC_REQUESTS_FILE); + logRequest('Returned RC requests and deleted RC requests log', $request); + break; case '/clear-dumped-data': if (!file_exists(REQUEST_LATEST_DUMP_FILE) && !file_exists(REQUEST_METRICS_FILE) && !file_exists(REQUEST_RC_CONFIGS_FILE)) { logRequest('Cannot delete request log; request log does not exist'); @@ -146,6 +157,9 @@ function logRequest($message, $data = '') if (file_exists(REQUEST_AGENT_INFO_FILE)) { unlink(REQUEST_AGENT_INFO_FILE); } + if (file_exists(REQUEST_RC_REQUESTS_FILE)) { + unlink(REQUEST_RC_REQUESTS_FILE); + } logRequest('Deleted request log'); break; case '/next-response': @@ -164,13 +178,13 @@ function logRequest($message, $data = '') $request = file_get_contents('php://input'); logRequest("Requested remote config", $request); - if (file_exists(REQUEST_LATEST_DUMP_FILE)) { - $tracesStack = json_decode(file_get_contents(REQUEST_LATEST_DUMP_FILE), true); + if (file_exists(REQUEST_RC_REQUESTS_FILE)) { + $tracesStack = json_decode(file_get_contents(REQUEST_RC_REQUESTS_FILE), true); } else { $tracesStack = []; } $tracesStack[] = ['uri' => $_SERVER['REQUEST_URI'], 'headers' => getallheaders(), 'body' => $request]; - file_put_contents(REQUEST_LATEST_DUMP_FILE, json_encode($tracesStack)); + file_put_contents(REQUEST_RC_REQUESTS_FILE, json_encode($tracesStack)); $request = json_decode($request, true); $recentUpdate = @filemtime(REQUEST_RC_CONFIGS_FILE) > time() - 2; From a7a4d15f1ab3a1cc2e1b385c3876f0523511ede5 Mon Sep 17 00:00:00 2001 From: Alexandre Rulleau Date: Wed, 25 Feb 2026 12:40:52 +0100 Subject: [PATCH 4/5] test(crashtracker_segfault_disabled): update tet to make it more reliable Signed-off-by: Alexandre Rulleau --- .gitlab/generate-common.php | 2 +- tests/ext/crashtracker_segfault_disabled.phpt | 49 +++++++++---------- tests/ext/includes/request_replayer.inc | 9 ++++ 3 files changed, 32 insertions(+), 28 deletions(-) diff --git a/.gitlab/generate-common.php b/.gitlab/generate-common.php index 009673d1e9..26560d1851 100644 --- a/.gitlab/generate-common.php +++ b/.gitlab/generate-common.php @@ -104,7 +104,7 @@ function dockerhub_login() { SNAPSHOT_REGEX_PLACEHOLDERS: 'path:/\S+/dd-trace-php(?=/),httpbin:(?<=//)httpbin-integration:8080' request-replayer: - name: registry.ddbuild.io/images/mirror/datadog/dd-trace-ci:php-request-replayer-2.0 + name: registry.ddbuild.io/images/mirror/datadog/dd-trace-ci:php-request-replayer-2.0-debug alias: request-replayer command: ["php", "-S", ":80", "index.php"] variables: diff --git a/tests/ext/crashtracker_segfault_disabled.phpt b/tests/ext/crashtracker_segfault_disabled.phpt index 0307aea26e..1eb9aafb9d 100644 --- a/tests/ext/crashtracker_segfault_disabled.phpt +++ b/tests/ext/crashtracker_segfault_disabled.phpt @@ -21,8 +21,7 @@ datadog.trace.agent_test_session_token=tests/ext/crashtracker_segfault_disabled. include __DIR__ . '/includes/request_replayer.inc'; $rr = new RequestReplayer(); -$rr->replayRequest(); // cleanup possible leftover -$rr->maxIteration = 100; +$rr->clearDumpedData(); // ensure clean state (avoids stale /v0.7/config entries in dump) usleep(100000); // Let time to the sidecar to open the crashtracker socket @@ -31,38 +30,34 @@ $args = getenv('TEST_PHP_ARGS')." ".getenv("TEST_PHP_EXTRA_ARGS"); $cmd = $php." ".$args." -r 'posix_kill(posix_getpid(), 11);'"; system($cmd); -$rr->waitForRequest(function ($request) { - if ($request["uri"] != "/telemetry/proxy/api/v2/apmtelemetry") { - return false; - } - $body = json_decode($request["body"], true); - $batch = $body["request_type"] == "message-batch" ? $body["payload"] : [$body]; - - foreach ($batch as $json) { - if ($json["request_type"] != "logs" || !isset($json["payload"]["logs"])) { +// Poll up to 5s to confirm no crash report (is_crash:true) arrives. +// Using is_crash:true as the definitive discriminator avoids false positives +// from regular telemetry or remote config requests stored in the same dump. +$crashReportFound = false; +for ($i = 0; $i < 10 && !$crashReportFound; $i++) { + usleep(500000); // 0.5s per iteration = 5s total max + foreach ($rr->replayAllRequests() ?: [] as $request) { + if ($request["uri"] != "/telemetry/proxy/api/v2/apmtelemetry") { continue; } - - foreach ($json["payload"]["logs"] as $payload) { - $payload["message"] = json_decode($payload["message"], true); - if (!isset($payload["message"]["metadata"])) { + $body = json_decode($request["body"], true); + $batch = $body["request_type"] == "message-batch" ? $body["payload"] : [$body]; + foreach ($batch as $json) { + if ($json["request_type"] != "logs" || !isset($json["payload"]["logs"])) { continue; } - if (($payload["message"]["kind"] ?? "") == "Crash ping") { - continue; + foreach ($json["payload"]["logs"] as $payload) { + if ($payload["is_crash"] ?? false) { + $crashReportFound = true; + break 3; + } } - - $output = json_encode($payload, JSON_PRETTY_PRINT); - echo $output; - return true; } } +} - return false; -}); +echo $crashReportFound ? "FAIL: unexpected crash report sent\n" : "OK\n"; ?> ---EXPECTF-- -%A -Fatal error: Uncaught Exception: wait for replay timeout in %s -%A +--EXPECT-- +OK diff --git a/tests/ext/includes/request_replayer.inc b/tests/ext/includes/request_replayer.inc index 609a0c075a..0e0d811336 100644 --- a/tests/ext/includes/request_replayer.inc +++ b/tests/ext/includes/request_replayer.inc @@ -104,6 +104,15 @@ class RequestReplayer ])), true); } + public function clearDumpedData() + { + file_get_contents($this->endpoint . '/clear-dumped-data', false, stream_context_create([ + "http" => [ + "header" => "X-Datadog-Test-Session-Token: " . ini_get("datadog.trace.agent_test_session_token"), + ], + ])); + } + public function replayHeaders($showOnly = []) { $request = $this->waitForDataAndReplay(); From 584ffcd63e5486428ab87c080bbc62a88a06f73a Mon Sep 17 00:00:00 2001 From: Alexandre Rulleau Date: Wed, 25 Feb 2026 14:14:10 +0100 Subject: [PATCH 5/5] fix(crashtracker_segfault_disabled): suppress segfault output and use non-debug request-replayer - Add 2>/dev/null to silence segfault output from child process on stdout - Switch CI to use php-request-replayer-2.0 instead of the debug variant --- .gitlab/generate-common.php | 2 +- tests/ext/crashtracker_segfault_disabled.phpt | 8 +++----- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/.gitlab/generate-common.php b/.gitlab/generate-common.php index 26560d1851..009673d1e9 100644 --- a/.gitlab/generate-common.php +++ b/.gitlab/generate-common.php @@ -104,7 +104,7 @@ function dockerhub_login() { SNAPSHOT_REGEX_PLACEHOLDERS: 'path:/\S+/dd-trace-php(?=/),httpbin:(?<=//)httpbin-integration:8080' request-replayer: - name: registry.ddbuild.io/images/mirror/datadog/dd-trace-ci:php-request-replayer-2.0-debug + name: registry.ddbuild.io/images/mirror/datadog/dd-trace-ci:php-request-replayer-2.0 alias: request-replayer command: ["php", "-S", ":80", "index.php"] variables: diff --git a/tests/ext/crashtracker_segfault_disabled.phpt b/tests/ext/crashtracker_segfault_disabled.phpt index 1eb9aafb9d..79e754a918 100644 --- a/tests/ext/crashtracker_segfault_disabled.phpt +++ b/tests/ext/crashtracker_segfault_disabled.phpt @@ -21,21 +21,19 @@ datadog.trace.agent_test_session_token=tests/ext/crashtracker_segfault_disabled. include __DIR__ . '/includes/request_replayer.inc'; $rr = new RequestReplayer(); -$rr->clearDumpedData(); // ensure clean state (avoids stale /v0.7/config entries in dump) +$rr->clearDumpedData(); // ensure clean state usleep(100000); // Let time to the sidecar to open the crashtracker socket $php = getenv('TEST_PHP_EXECUTABLE'); $args = getenv('TEST_PHP_ARGS')." ".getenv("TEST_PHP_EXTRA_ARGS"); -$cmd = $php." ".$args." -r 'posix_kill(posix_getpid(), 11);'"; +$cmd = $php." ".$args." -r 'posix_kill(posix_getpid(), 11);' 2>/dev/null"; system($cmd); // Poll up to 5s to confirm no crash report (is_crash:true) arrives. -// Using is_crash:true as the definitive discriminator avoids false positives -// from regular telemetry or remote config requests stored in the same dump. $crashReportFound = false; for ($i = 0; $i < 10 && !$crashReportFound; $i++) { - usleep(500000); // 0.5s per iteration = 5s total max + usleep(500000); foreach ($rr->replayAllRequests() ?: [] as $request) { if ($request["uri"] != "/telemetry/proxy/api/v2/apmtelemetry") { continue;