A client needed a solution to filter PHP APM traces before sending them to the Datadog server to reduce ingestion fees.
The filter rules were to exclude everything except requests exceeding 1 second and errors (HTTP code >= 400, exceptions, PHP errors).
They still wanted to utilize automatic instrumentation for several libraries (e.g., Laravel, Curl, PDO).
(The client is still using PHP 7.4, which is end-of-life; I know - they will upgrade to 8.x later.)
This auto-prepend script will filter out the specified request traces (returning from the function will retain the trace).
<?php
// dd-filter.php
register_shutdown_function(function() {
// config
$TIME_LIMIT_SEC = 1.0;
// exit if Datadog (DDTrace) is NOT loaded
if (!class_exists('\DDTrace\GlobalTracer') || !class_exists('\DDTrace\Tag')) {
return;
}
// get HTTP status code
$httpResponseCode = http_response_code();
if ($httpResponseCode >= 400) {
return; // keep DD trace
}
// is the script exited with an error?
$lastError = error_get_last();
if ($lastError) {
return; // keep DD trace
}
// get current request time
if (empty($_SERVER['REQUEST_TIME_FLOAT'])) {
return; // keep DD trace
}
$startTime = $_SERVER['REQUEST_TIME_FLOAT'];
$currentTime = microtime(true);
$elapsedTime = max($currentTime - $startTime, 0.0);
if ($elapsedTime > $TIME_LIMIT_SEC) {
return; // keep DD trace
}
// drop DD trace
$tracer = \DDTrace\GlobalTracer::get();
$span = $tracer->getActiveSpan();
if (null !== $span) {
$span->setTag(\DDTrace\Tag::MANUAL_DROP, true);
}
});
(Yes, I know it would be better if the configuration, for example, TIME_LIMIT_SEC
, were kept in a separate file.)
This can be set up in the following way:
- Place this script to
/etc/php/7.4/datadog-filter/dd-filter.php
- Set the script for auto-prepending in
/etc/php/7.4/fpm/php.ini
:auto_prepend_file = /etc/php/7.4/datadog-filter/dd-filter.php
- Restart PHP-FPM:
systemctl restart php7.4-fpm
(The client is using their app on a Debian 12 Linux VM.)
Top comments (0)