Skip to content

Commit

Permalink
Remove metric streams of disabled instrumentation scopes
Browse files Browse the repository at this point in the history
  • Loading branch information
Nevay committed Jul 23, 2024
1 parent c759e53 commit 639cc15
Show file tree
Hide file tree
Showing 15 changed files with 315 additions and 112 deletions.
72 changes: 72 additions & 0 deletions common/Internal/InstrumentationScopeCache.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
<?php declare(strict_types=1);
namespace Nevay\OTelSDK\Common\Internal;

use Closure;
use Nevay\OTelSDK\Common\InstrumentationScope;
use Psr\Log\LoggerInterface;
use WeakMap;
use WeakReference;
use function hash;
use function serialize;

/**
* @internal
*/
final class InstrumentationScopeCache {

/** @var array<string, WeakReference<InstrumentationScope>> */
private array $instrumentationScopes = [];
/**
* @var WeakMap<InstrumentationScope, object>
* @noinspection PhpPropertyOnlyWrittenInspection
*/
private readonly WeakMap $destructors;

public function __construct(
private readonly ?LoggerInterface $logger,
) {
$this->destructors = new WeakMap();
}

public function intern(InstrumentationScope $instrumentationScope): InstrumentationScope {
$instrumentationScopeId = hash('xxh128', serialize([
$instrumentationScope->name,
$instrumentationScope->version,
$instrumentationScope->schemaUrl,
]), true);

if (!$internScope = ($this->instrumentationScopes[$instrumentationScopeId] ?? null)?->get()) {
/** @noinspection PhpSecondWriteToReadonlyPropertyInspection */
$this->destructors[$instrumentationScope] = $this->destructor($instrumentationScopeId);
$this->instrumentationScopes[$instrumentationScopeId] = WeakReference::create($instrumentationScope);

return $instrumentationScope;
}

if ($internScope->attributes->toArray() !== $instrumentationScope->attributes->toArray()) {
$this->logger->warning('Instrumentation scope with same identity and differing non-identifying fields, using first-seen instrumentation scope', [
'name' => $instrumentationScope->name,
'version' => $instrumentationScope->version,
'schemaUrl' => $instrumentationScope->schemaUrl,
]);
}

return $internScope;
}

private function destructor(string $instrumentationScopeId): object {
return new class($this->prune(...), $instrumentationScopeId) {
public function __construct(
private readonly Closure $prune,
private readonly string $instrumentationScopeId,
) {}
public function __destruct() {
($this->prune)($this->instrumentationScopeId);
}
};
}

private function prune(string $instrumentationScopeId): void {
unset($this->instrumentationScopes[$instrumentationScopeId]);
}
}
6 changes: 6 additions & 0 deletions logs/Internal/EventLogger.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

use Nevay\OTelSDK\Common\ContextResolver;
use Nevay\OTelSDK\Common\InstrumentationScope;
use Nevay\OTelSDK\Logs\LoggerConfig;
use OpenTelemetry\API\Logs\EventLoggerInterface;
use OpenTelemetry\API\Logs\Severity;
use OpenTelemetry\API\Trace\Span;
Expand All @@ -16,6 +17,7 @@ final class EventLogger implements EventLoggerInterface {
public function __construct(
private readonly LoggerState $loggerState,
private readonly InstrumentationScope $instrumentationScope,
private readonly LoggerConfig $loggerConfig,
) {}

public function emit(
Expand All @@ -26,6 +28,10 @@ public function emit(
?Severity $severityNumber = null,
iterable $attributes = [],
): void {
if ($this->loggerConfig->disabled) {
return;
}

$context = ContextResolver::resolve($context, $this->loggerState->contextStorage);
$observedTimestamp = $this->loggerState->clock->now();

Expand Down
21 changes: 14 additions & 7 deletions logs/Internal/LoggerProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
use Nevay\OTelSDK\Common\AttributesFactory;
use Nevay\OTelSDK\Common\Clock;
use Nevay\OTelSDK\Common\InstrumentationScope;
use Nevay\OTelSDK\Common\Internal\InstrumentationScopeCache;
use Nevay\OTelSDK\Common\Provider;
use Nevay\OTelSDK\Common\Resource;
use Nevay\OTelSDK\Logs\LoggerConfig;
Expand All @@ -14,9 +15,9 @@
use OpenTelemetry\API\Logs\EventLoggerProviderInterface;
use OpenTelemetry\API\Logs\LoggerInterface;
use OpenTelemetry\API\Logs\LoggerProviderInterface;
use OpenTelemetry\API\Logs\NoopEventLogger;
use OpenTelemetry\Context\ContextStorageInterface;
use Psr\Log\LoggerInterface as PsrLoggerInterface;
use WeakMap;

/**
* @internal
Expand All @@ -25,6 +26,8 @@ final class LoggerProvider implements LoggerProviderInterface, EventLoggerProvid

private readonly LoggerState $loggerState;
private readonly AttributesFactory $instrumentationScopeAttributesFactory;
private readonly InstrumentationScopeCache $instrumentationScopeCache;
private readonly WeakMap $configCache;
private readonly Closure $loggerConfigurator;

/**
Expand All @@ -49,6 +52,8 @@ public function __construct(
$logger,
);
$this->instrumentationScopeAttributesFactory = $instrumentationScopeAttributesFactory;
$this->instrumentationScopeCache = new InstrumentationScopeCache($logger);
$this->configCache = new WeakMap();
$this->loggerConfigurator = $loggerConfigurator;
}

Expand All @@ -64,7 +69,10 @@ public function getLogger(

$instrumentationScope = new InstrumentationScope($name, $version, $schemaUrl,
$this->instrumentationScopeAttributesFactory->builder()->addAll($attributes)->build());
$loggerConfig = ($this->loggerConfigurator)($instrumentationScope);
$instrumentationScope = $this->instrumentationScopeCache->intern($instrumentationScope);

/** @noinspection PhpSecondWriteToReadonlyPropertyInspection */
$loggerConfig = $this->configCache[$instrumentationScope] ??= ($this->loggerConfigurator)($instrumentationScope);

return new Logger($this->loggerState, $instrumentationScope, $loggerConfig);
}
Expand All @@ -81,13 +89,12 @@ public function getEventLogger(

$instrumentationScope = new InstrumentationScope($name, $version, $schemaUrl,
$this->instrumentationScopeAttributesFactory->builder()->addAll($attributes)->build());
$instrumentationScope = $this->instrumentationScopeCache->intern($instrumentationScope);

$config = ($this->loggerConfigurator)($instrumentationScope);
if ($config->disabled) {
return new NoopEventLogger();
}
/** @noinspection PhpSecondWriteToReadonlyPropertyInspection */
$loggerConfig = $this->configCache[$instrumentationScope] ??= ($this->loggerConfigurator)($instrumentationScope);

return new EventLogger($this->loggerState, $instrumentationScope);
return new EventLogger($this->loggerState, $instrumentationScope, $loggerConfig);
}

public function shutdown(?Cancellation $cancellation = null): bool {
Expand Down
8 changes: 8 additions & 0 deletions logs/LoggerConfig.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,19 @@
namespace Nevay\OTelSDK\Logs;

/**
* @property-read bool $disabled
*
* @experimental
*/
final class LoggerConfig {

public function __construct(
public bool $disabled = false,
) {}

public function setDisabled(bool $disabled): self {
$this->disabled = $disabled;

return $this;
}
}
4 changes: 1 addition & 3 deletions metrics/Internal/Instrument/AsynchronousInstrument.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
use Nevay\OTelSDK\Metrics\Instrument;
use Nevay\OTelSDK\Metrics\Internal\Registry\MetricWriter;
use Nevay\OTelSDK\Metrics\Internal\StalenessHandler\ReferenceCounter;
use Nevay\OTelSDK\Metrics\MeterConfig;
use OpenTelemetry\API\Metrics\ObservableCallbackInterface;
use OpenTelemetry\API\Metrics\ObserverInterface;
use WeakMap;
Expand All @@ -23,7 +22,6 @@ public function __construct(
private readonly Instrument $instrument,
private readonly ReferenceCounter $referenceCounter,
private readonly WeakMap $destructors,
private readonly MeterConfig $meterConfig,
) {
assert($this instanceof InstrumentHandle);

Expand All @@ -39,7 +37,7 @@ public function getHandle(): Instrument {
}

public function enabled(): bool {
return !$this->meterConfig->disabled && $this->writer->enabled($this->instrument);
return $this->writer->enabled($this->instrument);
}

/**
Expand Down
8 changes: 1 addition & 7 deletions metrics/Internal/Instrument/SynchronousInstrument.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
use Nevay\OTelSDK\Metrics\Instrument;
use Nevay\OTelSDK\Metrics\Internal\Registry\MetricWriter;
use Nevay\OTelSDK\Metrics\Internal\StalenessHandler\ReferenceCounter;
use Nevay\OTelSDK\Metrics\MeterConfig;
use OpenTelemetry\Context\ContextInterface;
use function assert;

Expand All @@ -17,7 +16,6 @@ public function __construct(
private readonly MetricWriter $writer,
private readonly Instrument $instrument,
private readonly ReferenceCounter $referenceCounter,
private readonly MeterConfig $meterConfig,
) {
assert($this instanceof InstrumentHandle);

Expand All @@ -33,7 +31,7 @@ public function getHandle(): Instrument {
}

public function enabled(): bool {
return !$this->meterConfig->disabled && $this->writer->enabled($this->instrument);
return $this->writer->enabled($this->instrument);
}

/**
Expand All @@ -43,10 +41,6 @@ public function enabled(): bool {
* @noinspection PhpMissingParamTypeInspection
*/
public function write($amount, iterable $attributes = [], $context = null): void {
if ($this->meterConfig->disabled) {
return;
}

$this->writer->record($this->instrument, $amount, $attributes, $context);
}
}
10 changes: 4 additions & 6 deletions metrics/Internal/Meter.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
use Nevay\OTelSDK\Metrics\Internal\Instrument\ObservableUpDownCounter;
use Nevay\OTelSDK\Metrics\Internal\Instrument\UpDownCounter;
use Nevay\OTelSDK\Metrics\Internal\StalenessHandler\MultiReferenceCounter;
use Nevay\OTelSDK\Metrics\MeterConfig;
use OpenTelemetry\API\Metrics\AsynchronousInstrument;
use OpenTelemetry\API\Metrics\CounterInterface;
use OpenTelemetry\API\Metrics\GaugeInterface;
Expand All @@ -36,7 +35,6 @@ final class Meter implements MeterInterface {
public function __construct(
private readonly MeterState $meterState,
private readonly InstrumentationScope $instrumentationScope,
private readonly MeterConfig $meterConfig,
) {}

private static function dummyInstrument(): Instrument {
Expand Down Expand Up @@ -123,9 +121,9 @@ public function createObservableUpDownCounter(string $name, ?string $unit = null
*/
private function createSynchronousInstrument(string $class, InstrumentType $type, string $name, ?string $unit, ?string $description, array $advisory): InstrumentHandle {
[$instrument, $referenceCounter] = $this->meterState->createSynchronousInstrument(new Instrument(
$type, $name, $unit, $description, $advisory), $this->instrumentationScope, $this->meterConfig);
$type, $name, $unit, $description, $advisory), $this->instrumentationScope);

return new $class($this->meterState->registry, $instrument, $referenceCounter, $this->meterConfig);
return new $class($this->meterState->registry, $instrument, $referenceCounter);
}

/**
Expand All @@ -140,13 +138,13 @@ private function createAsynchronousInstrument(string $class, InstrumentType $typ
$advisory = [];
}
[$instrument, $referenceCounter] = $this->meterState->createAsynchronousInstrument(new Instrument(
$type, $name, $unit, $description, $advisory), $this->instrumentationScope, $this->meterConfig);
$type, $name, $unit, $description, $advisory), $this->instrumentationScope);

foreach ($callbacks as $callback) {
$this->meterState->registry->registerCallback(closure($callback), $instrument);
$referenceCounter->acquire(true);
}

return new $class($this->meterState->registry, $instrument, $referenceCounter, $this->meterState->destructors, $this->meterConfig);
return new $class($this->meterState->registry, $instrument, $referenceCounter, $this->meterState->destructors);
}
}
27 changes: 10 additions & 17 deletions metrics/Internal/MeterMetricProducer.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,9 @@ public function registerMetricSource(int $streamId, MetricStreamSource $streamSo
}

public function produce(?MetricFilter $metricFilter = null, ?Cancellation $cancellation = null): iterable {
$sources = $this->applyMetricFilter($this->sources, $metricFilter);
$sources = $metricFilter
? $this->applyMetricFilter($this->sources, $metricFilter)
: $this->sources;
$streamIds = count($sources) === count($this->sources)
? $this->streamIds ??= array_keys($this->sources)
: array_keys($sources);
Expand Down Expand Up @@ -71,10 +73,15 @@ public function produce(?MetricFilter $metricFilter = null, ?Cancellation $cance
* @param array<int, list<MetricStreamSource>> $sources
* @return array<int, array<int, MetricStreamSource>>
*/
private function applyMetricFilter(array $sources, ?MetricFilter $filter): array {
private function applyMetricFilter(array $sources, MetricFilter $filter): array {
foreach ($sources as $streamId => $streamSources) {
foreach ($streamSources as $sourceId => $source) {
$result = self::testMetric($source, $filter);
$result = $filter->testMetric(
$source->descriptor->instrumentationScope,
$source->descriptor->name,
$source->descriptor->instrumentType,
$source->descriptor->unit,
);

if ($result === MetricFilterResult::Accept) {
// no-op
Expand All @@ -84,7 +91,6 @@ private function applyMetricFilter(array $sources, ?MetricFilter $filter): array
$source->descriptor,
new FilteredMetricStream($source->descriptor, $source->stream, $filter),
$source->reader,
$source->meterConfig,
);
}
if ($result === MetricFilterResult::Drop) {
Expand All @@ -99,17 +105,4 @@ private function applyMetricFilter(array $sources, ?MetricFilter $filter): array

return $sources;
}

private static function testMetric(MetricStreamSource $source, ?MetricFilter $filter): MetricFilterResult {
if ($source->meterConfig->disabled) {
return MetricFilterResult::Drop;
}

return $filter?->testMetric(
$source->descriptor->instrumentationScope,
$source->descriptor->name,
$source->descriptor->instrumentType,
$source->descriptor->unit,
) ?? MetricFilterResult::Accept;
}
}
16 changes: 14 additions & 2 deletions metrics/Internal/MeterProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use Nevay\OTelSDK\Common\AttributesFactory;
use Nevay\OTelSDK\Common\Clock;
use Nevay\OTelSDK\Common\InstrumentationScope;
use Nevay\OTelSDK\Common\Internal\InstrumentationScopeCache;
use Nevay\OTelSDK\Common\Provider;
use Nevay\OTelSDK\Common\Resource;
use Nevay\OTelSDK\Metrics\Aggregator;
Expand All @@ -31,6 +32,8 @@ final class MeterProvider implements MeterProviderInterface, Provider {

private readonly MeterState $meterState;
private readonly AttributesFactory $instrumentationScopeAttributesFactory;
private readonly InstrumentationScopeCache $instrumentationScopeCache;
private readonly WeakMap $configCache;
private readonly Closure $meterConfigurator;

/**
Expand Down Expand Up @@ -74,6 +77,8 @@ public function __construct(
$logger,
);
$this->instrumentationScopeAttributesFactory = $instrumentationScopeAttributesFactory;
$this->instrumentationScopeCache = new InstrumentationScopeCache($logger);
$this->configCache = new WeakMap();
$this->meterConfigurator = $meterConfigurator;
}

Expand All @@ -89,9 +94,16 @@ public function getMeter(

$instrumentationScope = new InstrumentationScope($name, $version, $schemaUrl,
$this->instrumentationScopeAttributesFactory->builder()->addAll($attributes)->build());
$meterConfig = ($this->meterConfigurator)($instrumentationScope);
$instrumentationScope = $this->instrumentationScopeCache->intern($instrumentationScope);

return new Meter($this->meterState, $instrumentationScope, $meterConfig);
/** @noinspection PhpSecondWriteToReadonlyPropertyInspection */
$this->configCache[$instrumentationScope] ??= ($this->meterConfigurator)($instrumentationScope)
->onChange(fn(MeterConfig $meterConfig) => $meterConfig->disabled
? $this->meterState->disableInstrumentationScope($instrumentationScope)
: $this->meterState->enableInstrumentationScope($instrumentationScope))
->triggerOnChange();

return new Meter($this->meterState, $instrumentationScope);
}

public function shutdown(?Cancellation $cancellation = null): bool {
Expand Down
Loading

0 comments on commit 639cc15

Please sign in to comment.