From 2c1da9aaecbad2474e755739e069d48d07da20f9 Mon Sep 17 00:00:00 2001 From: Tobias Bachert Date: Wed, 16 Oct 2024 00:42:37 +0200 Subject: [PATCH] Add `TextMapPropagator` to instrumentation context (#1401) --- .../configure_instrumentation.php | 4 +- .../AutoInstrumentation/Context.php | 3 ++ .../LateBindingTextMapPropagator.php | 53 +++++++++++++++++++ src/SDK/SdkAutoloader.php | 18 ++++++- .../AutoInstrumentation/ContextTest.php | 2 + .../LateBindingProviderTest.php | 21 +++++++- 6 files changed, 96 insertions(+), 5 deletions(-) create mode 100644 src/SDK/Propagation/LateBindingTextMapPropagator.php diff --git a/examples/instrumentation/configure_instrumentation.php b/examples/instrumentation/configure_instrumentation.php index 6910c4caa..80c1a4fe3 100644 --- a/examples/instrumentation/configure_instrumentation.php +++ b/examples/instrumentation/configure_instrumentation.php @@ -8,8 +8,6 @@ use OpenTelemetry\API\Globals; use OpenTelemetry\API\Instrumentation\AutoInstrumentation\ExtensionHookManager; use OpenTelemetry\API\Instrumentation\AutoInstrumentation\Instrumentation; -use OpenTelemetry\API\Logs\NoopLoggerProvider; -use OpenTelemetry\API\Metrics\Noop\NoopMeterProvider; use OpenTelemetry\Config\SDK\Configuration; use OpenTelemetry\Config\SDK\Configuration\Context; use OpenTelemetry\Example\Example; @@ -25,7 +23,7 @@ Configuration::parseFile(__DIR__ . '/otel-sdk.yaml')->create(new Context())->setAutoShutdown(true)->buildAndRegisterGlobal(); $configuration = \OpenTelemetry\Config\SDK\Instrumentation::parseFile(__DIR__ . '/otel-sdk.yaml')->create(); $hookManager = new ExtensionHookManager(); -$context = new \OpenTelemetry\API\Instrumentation\AutoInstrumentation\Context(Globals::tracerProvider(), new NoopMeterProvider(), new NoopLoggerProvider()); +$context = new \OpenTelemetry\API\Instrumentation\AutoInstrumentation\Context(Globals::tracerProvider(), Globals::meterProvider(), Globals::loggerProvider(), Globals::propagator()); foreach (ServiceLoader::load(Instrumentation::class) as $instrumentation) { $instrumentation->register($hookManager, $configuration, $context); diff --git a/src/API/Instrumentation/AutoInstrumentation/Context.php b/src/API/Instrumentation/AutoInstrumentation/Context.php index 70005ccab..cb7889d51 100644 --- a/src/API/Instrumentation/AutoInstrumentation/Context.php +++ b/src/API/Instrumentation/AutoInstrumentation/Context.php @@ -10,6 +10,8 @@ use OpenTelemetry\API\Metrics\Noop\NoopMeterProvider; use OpenTelemetry\API\Trace\NoopTracerProvider; use OpenTelemetry\API\Trace\TracerProviderInterface; +use OpenTelemetry\Context\Propagation\NoopTextMapPropagator; +use OpenTelemetry\Context\Propagation\TextMapPropagatorInterface; /** * Context used for component creation. @@ -20,6 +22,7 @@ public function __construct( public readonly TracerProviderInterface $tracerProvider = new NoopTracerProvider(), public readonly MeterProviderInterface $meterProvider = new NoopMeterProvider(), public readonly LoggerProviderInterface $loggerProvider = new NoopLoggerProvider(), + public readonly TextMapPropagatorInterface $propagator = new NoopTextMapPropagator(), ) { } } diff --git a/src/SDK/Propagation/LateBindingTextMapPropagator.php b/src/SDK/Propagation/LateBindingTextMapPropagator.php new file mode 100644 index 000000000..6e30a0008 --- /dev/null +++ b/src/SDK/Propagation/LateBindingTextMapPropagator.php @@ -0,0 +1,53 @@ +propagator instanceof TextMapPropagatorInterface) { + $this->propagator = ($this->propagator)(); + } + + return $this->propagator->fields(); + } + + public function inject(mixed &$carrier, ?PropagationSetterInterface $setter = null, ?ContextInterface $context = null): void + { + if (!$this->propagator instanceof TextMapPropagatorInterface) { + $this->propagator = ($this->propagator)(); + } + + $this->propagator->inject($carrier, $setter, $context); + } + + public function extract($carrier, ?PropagationGetterInterface $getter = null, ?ContextInterface $context = null): ContextInterface + { + if (!$this->propagator instanceof TextMapPropagatorInterface) { + $this->propagator = ($this->propagator)(); + } + + return $this->propagator->extract($carrier, $getter, $context); + } +} diff --git a/src/SDK/SdkAutoloader.php b/src/SDK/SdkAutoloader.php index 35a2a7047..bc3208e4c 100644 --- a/src/SDK/SdkAutoloader.php +++ b/src/SDK/SdkAutoloader.php @@ -23,12 +23,14 @@ use OpenTelemetry\Config\SDK\Configuration as SdkConfiguration; use OpenTelemetry\Config\SDK\Instrumentation as SdkInstrumentation; use OpenTelemetry\Context\Context; +use OpenTelemetry\Context\Propagation\TextMapPropagatorInterface; use OpenTelemetry\SDK\Common\Configuration\Configuration; use OpenTelemetry\SDK\Common\Configuration\Variables; use OpenTelemetry\SDK\Common\Util\ShutdownHandler; use OpenTelemetry\SDK\Logs\EventLoggerProviderFactory; use OpenTelemetry\SDK\Logs\LoggerProviderFactory; use OpenTelemetry\SDK\Metrics\MeterProviderFactory; +use OpenTelemetry\SDK\Propagation\LateBindingTextMapPropagator; use OpenTelemetry\SDK\Propagation\PropagatorFactory; use OpenTelemetry\SDK\Resource\ResourceInfoFactory; use OpenTelemetry\SDK\Trace\AutoRootSpan; @@ -154,7 +156,8 @@ private static function registerInstrumentations(): void $tracerProvider = self::createLateBindingTracerProvider(); $meterProvider = self::createLateBindingMeterProvider(); $loggerProvider = self::createLateBindingLoggerProvider(); - $context = new InstrumentationContext($tracerProvider, $meterProvider, $loggerProvider); + $propagator = self::createLateBindingTextMapPropagator(); + $context = new InstrumentationContext($tracerProvider, $meterProvider, $loggerProvider, $propagator); foreach (ServiceLoader::load(Instrumentation::class) as $instrumentation) { /** @var Instrumentation $instrumentation */ @@ -204,6 +207,19 @@ private static function createLateBindingLoggerProvider(): LoggerProviderInterfa }); } + private static function createLateBindingTextMapPropagator(): TextMapPropagatorInterface + { + return new LateBindingTextMapPropagator(static function (): TextMapPropagatorInterface { + $scope = Context::getRoot()->activate(); + + try { + return Globals::propagator(); + } finally { + $scope->detach(); + } + }); + } + private static function getHookManager(): HookManagerInterface { /** @var HookManagerInterface $hookManager */ diff --git a/tests/Unit/API/Instrumentation/AutoInstrumentation/ContextTest.php b/tests/Unit/API/Instrumentation/AutoInstrumentation/ContextTest.php index e5cb4c238..cff9a9a85 100644 --- a/tests/Unit/API/Instrumentation/AutoInstrumentation/ContextTest.php +++ b/tests/Unit/API/Instrumentation/AutoInstrumentation/ContextTest.php @@ -8,6 +8,7 @@ use OpenTelemetry\API\Logs\NoopLoggerProvider; use OpenTelemetry\API\Metrics\Noop\NoopMeterProvider; use OpenTelemetry\API\Trace\NoopTracerProvider; +use OpenTelemetry\Context\Propagation\NoopTextMapPropagator; use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\TestCase; @@ -20,5 +21,6 @@ public function test_default_noops(): void $this->assertInstanceOf(NoopTracerProvider::class, $context->tracerProvider); $this->assertInstanceOf(NoopMeterProvider::class, $context->meterProvider); $this->assertInstanceOf(NoopLoggerProvider::class, $context->loggerProvider); + $this->assertInstanceOf(NoopTextMapPropagator::class, $context->propagator); } } diff --git a/tests/Unit/API/Instrumentation/AutoInstrumentation/LateBindingProviderTest.php b/tests/Unit/API/Instrumentation/AutoInstrumentation/LateBindingProviderTest.php index 97e1f5a8f..380dafe60 100644 --- a/tests/Unit/API/Instrumentation/AutoInstrumentation/LateBindingProviderTest.php +++ b/tests/Unit/API/Instrumentation/AutoInstrumentation/LateBindingProviderTest.php @@ -4,6 +4,7 @@ namespace OpenTelemetry\Tests\Unit\API\Instrumentation\AutoInstrumentation; +use function assert; use Nevay\SPI\ServiceLoader; use OpenTelemetry\API\Behavior\Internal\Logging; use OpenTelemetry\API\Configuration\ConfigProperties; @@ -25,11 +26,13 @@ use OpenTelemetry\API\Trace\LateBindingTracerProvider; use OpenTelemetry\API\Trace\TracerInterface; use OpenTelemetry\API\Trace\TracerProviderInterface; +use OpenTelemetry\Context\Propagation\TextMapPropagatorInterface; use OpenTelemetry\SDK\Common\Configuration\Variables; use OpenTelemetry\SDK\SdkAutoloader; use OpenTelemetry\Tests\TestState; use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\TestCase; +use Prophecy\PhpUnit\ProphecyTrait; #[CoversClass(LateBindingLoggerProvider::class)] #[CoversClass(LateBindingLogger::class)] @@ -45,6 +48,7 @@ class LateBindingProviderTest extends TestCase { use TestState; + use ProphecyTrait; public function setUp(): void { @@ -77,6 +81,12 @@ public function getLogger(): LoggerInterface return self::$context->loggerProvider->getLogger('test'); } + public function getPropagator(): TextMapPropagatorInterface + { + assert(self::$context !== null); + + return self::$context->propagator; + } }; $this->setEnvironmentVariable(Variables::OTEL_PHP_AUTOLOAD_ENABLED, 'true'); $tracer_accessed = false; @@ -101,14 +111,17 @@ public function getLogger(): LoggerInterface return $this->createMock(LoggerInterface::class); }); + $propagator = $this->prophesize(TextMapPropagatorInterface::class); + ServiceLoader::register(Instrumentation::class, $instrumentation::class); $this->assertTrue(SdkAutoloader::autoload()); //initializer added _after_ autoloader has run and instrumentation registered - Globals::registerInitializer(function (Configurator $configurator) use ($tracerProvider, $loggerProvider, $meterProvider): Configurator { + Globals::registerInitializer(function (Configurator $configurator) use ($tracerProvider, $loggerProvider, $meterProvider, $propagator): Configurator { return $configurator ->withTracerProvider($tracerProvider) ->withMeterProvider($meterProvider) ->withLoggerProvider($loggerProvider) + ->withPropagator($propagator->reveal()) ; }); @@ -129,5 +142,11 @@ public function getLogger(): LoggerInterface $this->assertFalse($logger_accessed); $logger->emit(new LogRecord()); /** @phpstan-ignore-next-line */ $this->assertTrue($logger_accessed); + + /** @phpstan-ignore-next-line */ + $propagator->fields()->shouldNotHaveBeenCalled(); + $instrumentation->getPropagator()->fields(); + /** @phpstan-ignore-next-line */ + $propagator->fields()->shouldHaveBeenCalledOnce(); } }