From 36e2b7f61363215d0d98ad6015b211c6c5860a05 Mon Sep 17 00:00:00 2001 From: Brett McBride Date: Fri, 2 Feb 2024 00:21:30 +1100 Subject: [PATCH] adding OTEL_PHP_EXCLUDED_URLS (#1226) Modeled on python's feature to turn off all instrumentation for specific URLs, https://opentelemetry.io/docs/languages/python/automatic/agent-config/#excluded-urls this feature will effectively disable SDK autoloading if there is a request URI that matches one of the provided excluded URLs, and no-op implementations will be used for tracer/logger/meter providers. --- .../traces/features/ignore_request_urls.php | 22 ++++++++ src/SDK/Common/Configuration/Variables.php | 1 + src/SDK/SdkAutoloader.php | 26 ++++++++- tests/Unit/SDK/SdkAutoloaderTest.php | 55 +++++++++++++++++++ 4 files changed, 103 insertions(+), 1 deletion(-) create mode 100644 examples/traces/features/ignore_request_urls.php diff --git a/examples/traces/features/ignore_request_urls.php b/examples/traces/features/ignore_request_urls.php new file mode 100644 index 00000000..ff2c33d3 --- /dev/null +++ b/examples/traces/features/ignore_request_urls.php @@ -0,0 +1,22 @@ +getTracer('demo'); +$tracer->spanBuilder('healthcheck')->startSpan()->end(); diff --git a/src/SDK/Common/Configuration/Variables.php b/src/SDK/Common/Configuration/Variables.php index d0bb3c8a..8ccb28ac 100644 --- a/src/SDK/Common/Configuration/Variables.php +++ b/src/SDK/Common/Configuration/Variables.php @@ -139,4 +139,5 @@ interface Variables public const OTEL_PHP_AUTOLOAD_ENABLED = 'OTEL_PHP_AUTOLOAD_ENABLED'; public const OTEL_PHP_INTERNAL_METRICS_ENABLED = 'OTEL_PHP_INTERNAL_METRICS_ENABLED'; //whether the SDK should emit its own metrics public const OTEL_PHP_DISABLED_INSTRUMENTATIONS = 'OTEL_PHP_DISABLED_INSTRUMENTATIONS'; + public const OTEL_PHP_EXCLUDED_URLS = 'OTEL_PHP_EXCLUDED_URLS'; } diff --git a/src/SDK/SdkAutoloader.php b/src/SDK/SdkAutoloader.php index 246f578c..d901cf8b 100644 --- a/src/SDK/SdkAutoloader.php +++ b/src/SDK/SdkAutoloader.php @@ -31,7 +31,7 @@ class SdkAutoloader //invalid setting, assume false self::$enabled = false; } - if (!self::$enabled) { + if (!self::$enabled || self::isIgnoredUrl()) { return false; } Globals::registerInitializer(function (Configurator $configurator) { @@ -69,6 +69,30 @@ class SdkAutoloader return true; } + /** + * Test whether a request URI is set, and if it matches the excluded urls configuration option + * + * @internal + */ + public static function isIgnoredUrl(): bool + { + $ignoreUrls = Configuration::getList(Variables::OTEL_PHP_EXCLUDED_URLS, []); + if ($ignoreUrls === []) { + return false; + } + $url = $_SERVER['REQUEST_URI'] ?? null; + if (!$url) { + return false; + } + foreach ($ignoreUrls as $ignore) { + if (preg_match(sprintf('|%s|', $ignore), $url) === 1) { + return true; + } + } + + return false; + } + /** * @internal */ diff --git a/tests/Unit/SDK/SdkAutoloaderTest.php b/tests/Unit/SDK/SdkAutoloaderTest.php index 51cb66df..598a4177 100644 --- a/tests/Unit/SDK/SdkAutoloaderTest.php +++ b/tests/Unit/SDK/SdkAutoloaderTest.php @@ -69,4 +69,59 @@ class SdkAutoloaderTest extends TestCase $this->assertNotInstanceOf(NoopTracerProvider::class, Globals::tracerProvider()); $this->assertNotInstanceOf(NoopLoggerProvider::class, Globals::loggerProvider()); } + + public function test_ignore_urls_without_request_uri(): void + { + $this->setEnvironmentVariable(Variables::OTEL_PHP_AUTOLOAD_ENABLED, 'true'); + $this->setEnvironmentVariable(Variables::OTEL_PHP_EXCLUDED_URLS, '*'); + unset($_SERVER['REQUEST_URI']); + $this->assertFalse(SdkAutoloader::isIgnoredUrl()); + } + + /** + * @dataProvider ignoreUrlsProvider + */ + public function test_ignore_urls(string $ignore, string $uri, bool $expected): void + { + $this->setEnvironmentVariable(Variables::OTEL_PHP_AUTOLOAD_ENABLED, 'true'); + $this->setEnvironmentVariable(Variables::OTEL_PHP_EXCLUDED_URLS, $ignore); + $_SERVER['REQUEST_URI'] = $uri; + $this->assertSame($expected, SdkAutoloader::isIgnoredUrl()); + } + + public static function ignoreUrlsProvider(): array + { + return [ + [ + 'foo', + '/foo?bar=baz', + true, + ], + [ + 'foo', + '/bar', + false, + ], + [ + 'foo,bar', + 'https://example.com/bar?p1=2', + true, + ], + [ + 'foo,bar', + 'https://example.com/baz?p1=2', + false, + ], + [ + 'client/.*/info,healthcheck', + 'https://site/client/123/info', + true, + ], + [ + 'client/.*/info,healthcheck', + 'https://site/xyz/healthcheck', + true, + ], + ]; + } }