Skip to content

Commit

Permalink
Provide global access to providers
Browse files Browse the repository at this point in the history
Remove logs for now, will be replaced with `LoggerProvider` in the future.
  • Loading branch information
Nevay committed Oct 15, 2022
1 parent 2e523d6 commit d7c308d
Show file tree
Hide file tree
Showing 5 changed files with 120 additions and 97 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,23 +9,20 @@
use function class_exists;
use OpenTelemetry\API\Metrics\MeterInterface;
use OpenTelemetry\API\Metrics\MeterProviderInterface;
use OpenTelemetry\API\Metrics\Noop\NoopMeterProvider;
use OpenTelemetry\API\Trace\NoopTracerProvider;
use OpenTelemetry\API\Trace\TracerInterface;
use OpenTelemetry\API\Trace\TracerProviderInterface;
use OpenTelemetry\Context\Context;
use OpenTelemetry\Context\ContextKeyInterface;
use OpenTelemetry\Context\ContextStorageInterface;
use OpenTelemetry\Context\Propagation\NoopTextMapPropagator;
use OpenTelemetry\Context\Propagation\TextMapPropagatorInterface;
use const PHP_VERSION_ID;
use Psr\Log\LoggerInterface;
use Psr\Log\NullLogger;

final class Instrumentation
/**
* Provides access to cached {@link TracerInterface} and {@link MeterInterface}
* instances.
*
* Autoinstrumentation should prefer using a {@link CachedInstrumentation}
* instance over repeatedly obtaining instrumentation instances from
* {@link Globals}.
*/
final class CachedInstrumentation
{
private ?ContextStorageInterface $contextStorage;

private string $name;
private ?string $version;
private ?string $schemaUrl;
Expand All @@ -35,9 +32,8 @@ final class Instrumentation
/** @var ArrayAccess<MeterProviderInterface, MeterInterface>|null */
private ?ArrayAccess $meters;

public function __construct(string $name, ?string $version = null, ?string $schemaUrl = null, iterable $attributes = [], ?ContextStorageInterface $contextStorage = null)
public function __construct(string $name, ?string $version = null, ?string $schemaUrl = null, iterable $attributes = [])
{
$this->contextStorage = $contextStorage;
$this->name = $name;
$this->version = $version;
$this->schemaUrl = $schemaUrl;
Expand All @@ -61,15 +57,9 @@ private static function createWeakMap(): ?ArrayAccess
return $map;
}

private function get(ContextKeyInterface $contextKey)
{
return ($this->contextStorage ?? Context::storage())->current()->get($contextKey);
}

public function tracer(): TracerInterface
{
static $noop;
$tracerProvider = $this->get(ContextKeys::tracerProvider()) ?? $noop ??= new NoopTracerProvider();
$tracerProvider = Globals::tracerProvider();

if ($this->tracers === null) {
return $tracerProvider->getTracer($this->name, $this->version, $this->schemaUrl, $this->attributes);
Expand All @@ -80,27 +70,12 @@ public function tracer(): TracerInterface

public function meter(): MeterInterface
{
static $noop;
$meterProvider = $this->get(ContextKeys::meterProvider()) ?? $noop ??= new NoopMeterProvider();
$meterProvider = Globals::meterProvider();

if ($this->meters === null) {
return $meterProvider->getMeter($this->name, $this->version, $this->schemaUrl, $this->attributes);
}

return $this->meters[$meterProvider] ??= $meterProvider->getMeter($this->name, $this->version, $this->schemaUrl, $this->attributes);
}

public function logger(): LoggerInterface
{
static $noop;

return $this->get(ContextKeys::logger()) ?? $noop ??= new NullLogger();
}

public function propagator(): TextMapPropagatorInterface
{
static $noop;

return $this->get(ContextKeys::propagator()) ?? $noop ??= new NoopTextMapPropagator();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,76 +7,70 @@
use OpenTelemetry\API\Metrics\MeterProviderInterface;
use OpenTelemetry\API\Trace\TracerProviderInterface;
use OpenTelemetry\Context\Context;
use OpenTelemetry\Context\ContextStorageInterface;
use OpenTelemetry\Context\ContextInterface;
use OpenTelemetry\Context\ImplicitContextKeyedInterface;
use OpenTelemetry\Context\Propagation\TextMapPropagatorInterface;
use OpenTelemetry\Context\ScopeInterface;
use Psr\Log\LoggerInterface;

final class InstrumentationConfigurator
/**
* Configures the global (context scoped) instrumentation instances.
*
* @see Configurator::activate()
*/
final class Configurator implements ImplicitContextKeyedInterface
{
private ?ContextStorageInterface $contextStorage;

private ?TracerProviderInterface $tracerProvider = null;
private ?MeterProviderInterface $meterProvider = null;
private ?LoggerInterface $logger = null;
private ?TextMapPropagatorInterface $propagator = null;

private function __construct(?ContextStorageInterface $contextStorage)
private function __construct()
{
$this->contextStorage = $contextStorage;
}

public static function create(?ContextStorageInterface $contextStorage = null): InstrumentationConfigurator
public static function create(): Configurator
{
return new self($contextStorage);
return new self();
}

public function activate(): ScopeInterface
{
$contextStorage = $this->contextStorage ?? Context::storage();
$context = $contextStorage->current();
return $this->storeInContext()->activate();
}

public function storeInContext(?ContextInterface $context = null): ContextInterface
{
$context ??= Context::getCurrent();

if ($this->tracerProvider !== null) {
$context = $context->with(ContextKeys::tracerProvider(), $this->tracerProvider);
}
if ($this->meterProvider !== null) {
$context = $context->with(ContextKeys::meterProvider(), $this->meterProvider);
}
if ($this->logger !== null) {
$context = $context->with(ContextKeys::logger(), $this->logger);
}
if ($this->propagator !== null) {
$context = $context->with(ContextKeys::propagator(), $this->propagator);
}

return $contextStorage->attach($context);
return $context;
}

public function withTracerProvider(?TracerProviderInterface $tracerProvider): InstrumentationConfigurator
public function withTracerProvider(?TracerProviderInterface $tracerProvider): Configurator
{
$self = clone $this;
$self->tracerProvider = $tracerProvider;

return $self;
}

public function withMeterProvider(?MeterProviderInterface $meterProvider): InstrumentationConfigurator
public function withMeterProvider(?MeterProviderInterface $meterProvider): Configurator
{
$self = clone $this;
$self->meterProvider = $meterProvider;

return $self;
}

public function withLogger(?LoggerInterface $logger): InstrumentationConfigurator
{
$self = clone $this;
$self->logger = $logger;

return $self;
}

public function withPropagator(?TextMapPropagatorInterface $propagator): InstrumentationConfigurator
public function withPropagator(?TextMapPropagatorInterface $propagator): Configurator
{
$self = clone $this;
$self->propagator = $propagator;
Expand Down
11 changes: 0 additions & 11 deletions src/API/Common/Instrumentation/ContextKeys.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
use OpenTelemetry\Context\Context;
use OpenTelemetry\Context\ContextKeyInterface;
use OpenTelemetry\Context\Propagation\TextMapPropagatorInterface;
use Psr\Log\LoggerInterface;

/**
* @internal
Expand All @@ -36,16 +35,6 @@ public static function meterProvider(): ContextKeyInterface
return $instance ??= Context::createKey(MeterProviderInterface::class);
}

/**
* @return ContextKeyInterface<LoggerInterface>
*/
public static function logger(): ContextKeyInterface
{
static $instance;

return $instance ??= Context::createKey(LoggerInterface::class);
}

/**
* @return ContextKeyInterface<TextMapPropagatorInterface>
*/
Expand Down
40 changes: 40 additions & 0 deletions src/API/Common/Instrumentation/Globals.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<?php

declare(strict_types=1);

namespace OpenTelemetry\API\Common\Instrumentation;

use OpenTelemetry\API\Metrics\MeterProviderInterface;
use OpenTelemetry\API\Metrics\Noop\NoopMeterProvider;
use OpenTelemetry\API\Trace\NoopTracerProvider;
use OpenTelemetry\API\Trace\TracerProviderInterface;
use OpenTelemetry\Context\Context;
use OpenTelemetry\Context\Propagation\NoopTextMapPropagator;
use OpenTelemetry\Context\Propagation\TextMapPropagatorInterface;

/**
* Provides access to the globally configured instrumentation instances.
*/
final class Globals
{
public static function tracerProvider(): TracerProviderInterface
{
static $noop;

return Context::getCurrent()->get(ContextKeys::tracerProvider()) ?? $noop ??= new NoopTracerProvider();
}

public static function meterProvider(): MeterProviderInterface
{
static $noop;

return Context::getCurrent()->get(ContextKeys::meterProvider()) ?? $noop ??= new NoopMeterProvider();
}

public static function propagator(): TextMapPropagatorInterface
{
static $noop;

return Context::getCurrent()->get(ContextKeys::propagator()) ?? $noop ??= new NoopTextMapPropagator();
}
}
69 changes: 47 additions & 22 deletions tests/Unit/API/Common/Instrumentation/InstrumentationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,63 +4,88 @@

namespace OpenTelemetry\Tests\Unit\API\Common\Instrumentation;

use OpenTelemetry\API\Common\Instrumentation\Instrumentation;
use OpenTelemetry\API\Common\Instrumentation\InstrumentationConfigurator;
use OpenTelemetry\API\Common\Instrumentation\CachedInstrumentation;
use OpenTelemetry\API\Common\Instrumentation\Configurator;
use OpenTelemetry\API\Common\Instrumentation\Globals;
use OpenTelemetry\API\Metrics\MeterInterface;
use OpenTelemetry\API\Metrics\MeterProviderInterface;
use OpenTelemetry\API\Metrics\Noop\NoopMeter;
use OpenTelemetry\API\Metrics\Noop\NoopMeterProvider;
use OpenTelemetry\API\Trace\NoopTracer;
use OpenTelemetry\API\Trace\NoopTracerProvider;
use OpenTelemetry\API\Trace\TracerInterface;
use OpenTelemetry\API\Trace\TracerProviderInterface;
use OpenTelemetry\Context\ContextStorage;
use OpenTelemetry\Context\Propagation\NoopTextMapPropagator;
use OpenTelemetry\Context\Propagation\TextMapPropagatorInterface;
use PHPUnit\Framework\TestCase;
use Psr\Log\LoggerInterface;
use Psr\Log\NullLogger;

/**
* @covers \OpenTelemetry\API\Common\Instrumentation\Instrumentation
* @covers \OpenTelemetry\API\Common\Instrumentation\InstrumentationConfigurator
* @covers \OpenTelemetry\API\Common\Instrumentation\Globals
* @covers \OpenTelemetry\API\Common\Instrumentation\CachedInstrumentation
* @covers \OpenTelemetry\API\Common\Instrumentation\Configurator
* @covers \OpenTelemetry\API\Common\Instrumentation\ContextKeys
*/
final class InstrumentationTest extends TestCase
{
public function test_not_configured_returns_noop_instances(): void
public function test_globals_not_configured_returns_noop_instances(): void
{
$contextStorage = new ContextStorage();
$instrumentation = new Instrumentation('', null, null, [], $contextStorage);
$this->assertInstanceOf(NoopTracerProvider::class, Globals::tracerProvider());
$this->assertInstanceOf(NoopMeterProvider::class, Globals::meterProvider());
$this->assertInstanceOf(NoopTextMapPropagator::class, Globals::propagator());
}

public function test_globals_returns_configured_instances(): void
{
$tracerProvider = $this->createMock(TracerProviderInterface::class);
$meterProvider = $this->createMock(MeterProviderInterface::class);
$propagator = $this->createMock(TextMapPropagatorInterface::class);

$scope = Configurator::create()
->withTracerProvider($tracerProvider)
->withMeterProvider($meterProvider)
->withPropagator($propagator)
->activate();

try {
$this->assertSame($tracerProvider, Globals::tracerProvider());
$this->assertSame($meterProvider, Globals::meterProvider());
$this->assertSame($propagator, Globals::propagator());
} finally {
$scope->detach();
}
}

public function test_instrumentation_not_configured_returns_noop_instances(): void
{
$instrumentation = new CachedInstrumentation('', null, null, []);

$this->assertInstanceOf(NoopTracer::class, $instrumentation->tracer());
$this->assertInstanceOf(NoopMeter::class, $instrumentation->meter());
$this->assertInstanceOf(NullLogger::class, $instrumentation->logger());
$this->assertInstanceOf(NoopTextMapPropagator::class, $instrumentation->propagator());
}

public function test_returns_configured_instances(): void
public function test_instrumentation_returns_configured_instances(): void
{
$contextStorage = new ContextStorage();
$instrumentation = new Instrumentation('', null, null, [], $contextStorage);
$instrumentation = new CachedInstrumentation('', null, null, []);

$tracer = $this->createMock(TracerInterface::class);
$tracerProvider = $this->createMock(TracerProviderInterface::class);
$tracerProvider->method('getTracer')->willReturn($tracer);
$meter = $this->createMock(MeterInterface::class);
$meterProvider = $this->createMock(MeterProviderInterface::class);
$meterProvider->method('getMeter')->willReturn($meter);
$logger = $this->createMock(LoggerInterface::class);
$propagator = $this->createMock(TextMapPropagatorInterface::class);

InstrumentationConfigurator::create($contextStorage)
$scope = Configurator::create()
->withTracerProvider($tracerProvider)
->withMeterProvider($meterProvider)
->withLogger($logger)
->withPropagator($propagator)
->activate();

$this->assertSame($tracer, $instrumentation->tracer());
$this->assertSame($meter, $instrumentation->meter());
$this->assertSame($logger, $instrumentation->logger());
$this->assertSame($propagator, $instrumentation->propagator());
try {
$this->assertSame($tracer, $instrumentation->tracer());
$this->assertSame($meter, $instrumentation->meter());
} finally {
$scope->detach();
}
}
}

0 comments on commit d7c308d

Please sign in to comment.