diff options
Diffstat (limited to 'vendor/open-telemetry/sdk/Metrics')
112 files changed, 4907 insertions, 0 deletions
diff --git a/vendor/open-telemetry/sdk/Metrics/Aggregation/ExplicitBucketHistogramAggregation.php b/vendor/open-telemetry/sdk/Metrics/Aggregation/ExplicitBucketHistogramAggregation.php new file mode 100644 index 000000000..d68ecd830 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/Aggregation/ExplicitBucketHistogramAggregation.php @@ -0,0 +1,167 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\Aggregation; + +use function array_fill; +use function count; +use const INF; +use const NAN; +use OpenTelemetry\Context\ContextInterface; +use OpenTelemetry\SDK\Common\Attribute\AttributesInterface; +use OpenTelemetry\SDK\Metrics\AggregationInterface; +use OpenTelemetry\SDK\Metrics\Data; + +/** + * @implements AggregationInterface<ExplicitBucketHistogramSummary> + */ +final class ExplicitBucketHistogramAggregation implements AggregationInterface +{ + /** + * @var list<float|int> + * @readonly + */ + public array $boundaries; + + /** + * @param list<float|int> $boundaries strictly ascending histogram bucket boundaries + */ + public function __construct(array $boundaries) + { + $this->boundaries = $boundaries; + } + + public function initialize(): ExplicitBucketHistogramSummary + { + return new ExplicitBucketHistogramSummary( + 0, + 0, + +INF, + -INF, + array_fill(0, count($this->boundaries) + 1, 0), + ); + } + + /** + * @param ExplicitBucketHistogramSummary $summary + */ + public function record($summary, $value, AttributesInterface $attributes, ContextInterface $context, int $timestamp): void + { + $boundariesCount = count($this->boundaries); + for ($i = 0; $i < $boundariesCount && $this->boundaries[$i] < $value; $i++) { + } + $summary->count++; + $summary->sum += $value; + $summary->min = self::min($value, $summary->min); + $summary->max = self::max($value, $summary->max); + $summary->buckets[$i]++; + } + + /** + * @param ExplicitBucketHistogramSummary $left + * @param ExplicitBucketHistogramSummary $right + */ + public function merge($left, $right): ExplicitBucketHistogramSummary + { + $count = $left->count + $right->count; + $sum = $left->sum + $right->sum; + $min = self::min($left->min, $right->min); + $max = self::max($left->max, $right->max); + $buckets = $right->buckets; + foreach ($left->buckets as $i => $bucketCount) { + $buckets[$i] += $bucketCount; + } + + return new ExplicitBucketHistogramSummary( + $count, + $sum, + $min, + $max, + $buckets, + ); + } + + /** + * @param ExplicitBucketHistogramSummary $left + * @param ExplicitBucketHistogramSummary $right + */ + public function diff($left, $right): ExplicitBucketHistogramSummary + { + $count = -$left->count + $right->count; + $sum = -$left->sum + $right->sum; + $min = $left->min > $right->min ? $right->min : NAN; + $max = $left->max < $right->max ? $right->max : NAN; + $buckets = $right->buckets; + foreach ($left->buckets as $i => $bucketCount) { + $buckets[$i] -= $bucketCount; + } + + return new ExplicitBucketHistogramSummary( + $count, + $sum, + $min, + $max, + $buckets, + ); + } + + /** + * @param array<ExplicitBucketHistogramSummary> $summaries + */ + public function toData( + array $attributes, + array $summaries, + array $exemplars, + int $startTimestamp, + int $timestamp, + $temporality + ): Data\Histogram { + $dataPoints = []; + foreach ($attributes as $key => $dataPointAttributes) { + if ($summaries[$key]->count === 0) { + continue; + } + + $dataPoints[] = new Data\HistogramDataPoint( + $summaries[$key]->count, + $summaries[$key]->sum, + $summaries[$key]->min, + $summaries[$key]->max, + $summaries[$key]->buckets, + $this->boundaries, + $dataPointAttributes, + $startTimestamp, + $timestamp, + $exemplars[$key] ?? [], + ); + } + + return new Data\Histogram( + $dataPoints, + $temporality, + ); + } + + /** + * @param float|int $left + * @param float|int $right + * @return float|int + */ + private static function min($left, $right) + { + /** @noinspection PhpConditionAlreadyCheckedInspection */ + return $left <= $right ? $left : ($right <= $left ? $right : NAN); + } + + /** + * @param float|int $left + * @param float|int $right + * @return float|int + */ + private static function max($left, $right) + { + /** @noinspection PhpConditionAlreadyCheckedInspection */ + return $left >= $right ? $left : ($right >= $left ? $right : NAN); + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/Aggregation/ExplicitBucketHistogramSummary.php b/vendor/open-telemetry/sdk/Metrics/Aggregation/ExplicitBucketHistogramSummary.php new file mode 100644 index 000000000..1878a34a0 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/Aggregation/ExplicitBucketHistogramSummary.php @@ -0,0 +1,40 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\Aggregation; + +final class ExplicitBucketHistogramSummary +{ + public int $count; + /** + * @var float|int + */ + public $sum; + /** + * @var float|int + */ + public $min; + /** + * @var float|int + */ + public $max; + /** + * @var int[] + */ + public array $buckets; + /** + * @param float|int $sum + * @param float|int $min + * @param float|int $max + * @param int[] $buckets + */ + public function __construct(int $count, $sum, $min, $max, array $buckets) + { + $this->count = $count; + $this->sum = $sum; + $this->min = $min; + $this->max = $max; + $this->buckets = $buckets; + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/Aggregation/LastValueAggregation.php b/vendor/open-telemetry/sdk/Metrics/Aggregation/LastValueAggregation.php new file mode 100644 index 000000000..aff04e315 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/Aggregation/LastValueAggregation.php @@ -0,0 +1,81 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\Aggregation; + +use OpenTelemetry\Context\ContextInterface; +use OpenTelemetry\SDK\Common\Attribute\AttributesInterface; +use OpenTelemetry\SDK\Metrics\AggregationInterface; +use OpenTelemetry\SDK\Metrics\Data; + +/** + * @implements AggregationInterface<LastValueSummary> + */ +final class LastValueAggregation implements AggregationInterface +{ + public function initialize(): LastValueSummary + { + return new LastValueSummary(null, 0); + } + + /** + * @param LastValueSummary $summary + */ + public function record($summary, $value, AttributesInterface $attributes, ContextInterface $context, int $timestamp): void + { + if ($summary->value === null || $timestamp >= $summary->timestamp) { + $summary->value = $value; + $summary->timestamp = $timestamp; + } + } + + /** + * @param LastValueSummary $left + * @param LastValueSummary $right + */ + public function merge($left, $right): LastValueSummary + { + return $right->timestamp >= $left->timestamp ? $right : $left; + } + + /** + * @param LastValueSummary $left + * @param LastValueSummary $right + */ + public function diff($left, $right): LastValueSummary + { + return $right->timestamp >= $left->timestamp ? $right : $left; + } + + /** + * @param array<LastValueSummary> $summaries + */ + public function toData( + array $attributes, + array $summaries, + array $exemplars, + int $startTimestamp, + int $timestamp, + $temporality + ): Data\Gauge { + $dataPoints = []; + foreach ($attributes as $key => $dataPointAttributes) { + if ($summaries[$key]->value === null) { + continue; + } + + $dataPoints[] = new Data\NumberDataPoint( + $summaries[$key]->value, + $dataPointAttributes, + $startTimestamp, + $timestamp, + $exemplars[$key] ?? [], + ); + } + + return new Data\Gauge( + $dataPoints, + ); + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/Aggregation/LastValueSummary.php b/vendor/open-telemetry/sdk/Metrics/Aggregation/LastValueSummary.php new file mode 100644 index 000000000..6cdb5ac9f --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/Aggregation/LastValueSummary.php @@ -0,0 +1,22 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\Aggregation; + +final class LastValueSummary +{ + /** + * @var float|int|null + */ + public $value; + public int $timestamp; + /** + * @param float|int|null $value + */ + public function __construct($value, int $timestamp) + { + $this->value = $value; + $this->timestamp = $timestamp; + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/Aggregation/SumAggregation.php b/vendor/open-telemetry/sdk/Metrics/Aggregation/SumAggregation.php new file mode 100644 index 000000000..dc317ce73 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/Aggregation/SumAggregation.php @@ -0,0 +1,91 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\Aggregation; + +use OpenTelemetry\Context\ContextInterface; +use OpenTelemetry\SDK\Common\Attribute\AttributesInterface; +use OpenTelemetry\SDK\Metrics\AggregationInterface; +use OpenTelemetry\SDK\Metrics\Data; + +/** + * @implements AggregationInterface<SumSummary> + */ +final class SumAggregation implements AggregationInterface +{ + private bool $monotonic; + + public function __construct(bool $monotonic = false) + { + $this->monotonic = $monotonic; + } + + public function initialize(): SumSummary + { + return new SumSummary(0); + } + + /** + * @param SumSummary $summary + */ + public function record($summary, $value, AttributesInterface $attributes, ContextInterface $context, int $timestamp): void + { + $summary->value += $value; + } + + /** + * @param SumSummary $left + * @param SumSummary $right + */ + public function merge($left, $right): SumSummary + { + $sum = $left->value + $right->value; + + return new SumSummary( + $sum, + ); + } + + /** + * @param SumSummary $left + * @param SumSummary $right + */ + public function diff($left, $right): SumSummary + { + $sum = -$left->value + $right->value; + + return new SumSummary( + $sum, + ); + } + + /** + * @param array<SumSummary> $summaries + */ + public function toData( + array $attributes, + array $summaries, + array $exemplars, + int $startTimestamp, + int $timestamp, + $temporality + ): Data\Sum { + $dataPoints = []; + foreach ($attributes as $key => $dataPointAttributes) { + $dataPoints[] = new Data\NumberDataPoint( + $summaries[$key]->value, + $dataPointAttributes, + $startTimestamp, + $timestamp, + $exemplars[$key] ?? [], + ); + } + + return new Data\Sum( + $dataPoints, + $temporality, + $this->monotonic, + ); + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/Aggregation/SumSummary.php b/vendor/open-telemetry/sdk/Metrics/Aggregation/SumSummary.php new file mode 100644 index 000000000..9b257193c --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/Aggregation/SumSummary.php @@ -0,0 +1,20 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\Aggregation; + +final class SumSummary +{ + /** + * @var float|int + */ + public $value; + /** + * @param float|int $value + */ + public function __construct($value) + { + $this->value = $value; + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/AggregationInterface.php b/vendor/open-telemetry/sdk/Metrics/AggregationInterface.php new file mode 100644 index 000000000..0a85207e0 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/AggregationInterface.php @@ -0,0 +1,57 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics; + +use OpenTelemetry\Context\ContextInterface; +use OpenTelemetry\SDK\Common\Attribute\AttributesInterface; +use OpenTelemetry\SDK\Metrics\Data\DataInterface; +use OpenTelemetry\SDK\Metrics\Data\Exemplar; +use OpenTelemetry\SDK\Metrics\Data\Temporality; + +/** + * @psalm-template T + */ +interface AggregationInterface +{ + /** + * @psalm-return T + */ + public function initialize(); + + /** + * @psalm-param T $summary + * @psalm-param float|int $value + */ + public function record($summary, $value, AttributesInterface $attributes, ContextInterface $context, int $timestamp): void; + + /** + * @psalm-param T $left + * @psalm-param T $right + * @psalm-return T + */ + public function merge($left, $right); + + /** + * @psalm-param T $left + * @psalm-param T $right + * @psalm-return T + */ + public function diff($left, $right); + + /** + * @param array<AttributesInterface> $attributes + * @psalm-param array<T> $summaries + * @param array<list<Exemplar>> $exemplars + * @param string|Temporality $temporality + */ + public function toData( + array $attributes, + array $summaries, + array $exemplars, + int $startTimestamp, + int $timestamp, + $temporality + ): DataInterface; +} diff --git a/vendor/open-telemetry/sdk/Metrics/AggregationTemporalitySelectorInterface.php b/vendor/open-telemetry/sdk/Metrics/AggregationTemporalitySelectorInterface.php new file mode 100644 index 000000000..f046d033d --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/AggregationTemporalitySelectorInterface.php @@ -0,0 +1,21 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics; + +use OpenTelemetry\SDK\Metrics\Data\Temporality; + +interface AggregationTemporalitySelectorInterface +{ + /** + * Returns the temporality to use for the given metric. + * + * It is recommended to return {@see MetricMetadataInterface::temporality()} + * if the exporter does not require a specific temporality. + * + * @return string|Temporality|null temporality to use, or null to signal + * that the given metric should not be exported by this exporter + */ + public function temporality(MetricMetadataInterface $metric); +} diff --git a/vendor/open-telemetry/sdk/Metrics/AttributeProcessor/FilteredAttributeProcessor.php b/vendor/open-telemetry/sdk/Metrics/AttributeProcessor/FilteredAttributeProcessor.php new file mode 100644 index 000000000..c4df8e878 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/AttributeProcessor/FilteredAttributeProcessor.php @@ -0,0 +1,33 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\AttributeProcessor; + +use OpenTelemetry\Context\ContextInterface; +use OpenTelemetry\SDK\Common\Attribute\Attributes; +use OpenTelemetry\SDK\Common\Attribute\AttributesInterface; +use OpenTelemetry\SDK\Metrics\AttributeProcessorInterface; + +/** + * @internal + */ +final class FilteredAttributeProcessor implements AttributeProcessorInterface +{ + private array $attributeKeys; + + public function __construct(array $attributeKeys) + { + $this->attributeKeys = $attributeKeys; + } + + public function process(AttributesInterface $attributes, ContextInterface $context): AttributesInterface + { + $filtered = []; + foreach ($this->attributeKeys as $key) { + $filtered[$key] = $attributes->get($key); + } + + return new Attributes($filtered, 0); + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/AttributeProcessor/IdentityAttributeProcessor.php b/vendor/open-telemetry/sdk/Metrics/AttributeProcessor/IdentityAttributeProcessor.php new file mode 100644 index 000000000..f261563ea --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/AttributeProcessor/IdentityAttributeProcessor.php @@ -0,0 +1,20 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\AttributeProcessor; + +use OpenTelemetry\Context\ContextInterface; +use OpenTelemetry\SDK\Common\Attribute\AttributesInterface; +use OpenTelemetry\SDK\Metrics\AttributeProcessorInterface; + +/** + * @internal + */ +final class IdentityAttributeProcessor implements AttributeProcessorInterface +{ + public function process(AttributesInterface $attributes, ContextInterface $context): AttributesInterface + { + return $attributes; + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/AttributeProcessorInterface.php b/vendor/open-telemetry/sdk/Metrics/AttributeProcessorInterface.php new file mode 100644 index 000000000..d2077aa39 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/AttributeProcessorInterface.php @@ -0,0 +1,16 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics; + +use OpenTelemetry\Context\ContextInterface; +use OpenTelemetry\SDK\Common\Attribute\AttributesInterface; + +/** + * @internal + */ +interface AttributeProcessorInterface +{ + public function process(AttributesInterface $attributes, ContextInterface $context): AttributesInterface; +} diff --git a/vendor/open-telemetry/sdk/Metrics/Counter.php b/vendor/open-telemetry/sdk/Metrics/Counter.php new file mode 100644 index 000000000..9cc6b75f9 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/Counter.php @@ -0,0 +1,37 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics; + +use OpenTelemetry\API\Metrics\CounterInterface; +use OpenTelemetry\SDK\Metrics\MetricRegistry\MetricWriterInterface; + +/** + * @internal + */ +final class Counter implements CounterInterface +{ + private MetricWriterInterface $writer; + private Instrument $instrument; + private ReferenceCounterInterface $referenceCounter; + + public function __construct(MetricWriterInterface $writer, Instrument $instrument, ReferenceCounterInterface $referenceCounter) + { + $this->writer = $writer; + $this->instrument = $instrument; + $this->referenceCounter = $referenceCounter; + + $this->referenceCounter->acquire(); + } + + public function __destruct() + { + $this->referenceCounter->release(); + } + + public function add($amount, iterable $attributes = [], $context = null): void + { + $this->writer->record($this->instrument, $amount, $attributes, $context); + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/Data/DataInterface.php b/vendor/open-telemetry/sdk/Metrics/Data/DataInterface.php new file mode 100644 index 000000000..7aa0c0e20 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/Data/DataInterface.php @@ -0,0 +1,9 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\Data; + +interface DataInterface +{ +} diff --git a/vendor/open-telemetry/sdk/Metrics/Data/Exemplar.php b/vendor/open-telemetry/sdk/Metrics/Data/Exemplar.php new file mode 100644 index 000000000..bd2034f75 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/Data/Exemplar.php @@ -0,0 +1,65 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\Data; + +use OpenTelemetry\SDK\Common\Attribute\AttributesInterface; + +final class Exemplar +{ + + /** + * @var int|string + */ + private $index; + /** + * @var float|int + * @readonly + */ + public $value; + /** + * @readonly + */ + public int $timestamp; + /** + * @readonly + */ + public AttributesInterface $attributes; + /** + * @readonly + */ + public ?string $traceId; + /** + * @readonly + */ + public ?string $spanId; + + /** + * @param int|string $index + * @param float|int $value + */ + public function __construct($index, $value, int $timestamp, AttributesInterface $attributes, ?string $traceId, ?string $spanId) + { + $this->index = $index; + $this->value = $value; + $this->timestamp = $timestamp; + $this->attributes = $attributes; + $this->traceId = $traceId; + $this->spanId = $spanId; + } + + /** + * @param iterable<Exemplar> $exemplars + * @return array<list<Exemplar>> + */ + public static function groupByIndex(iterable $exemplars): array + { + $grouped = []; + foreach ($exemplars as $exemplar) { + $grouped[$exemplar->index][] = $exemplar; + } + + return $grouped; + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/Data/Gauge.php b/vendor/open-telemetry/sdk/Metrics/Data/Gauge.php new file mode 100644 index 000000000..00eb50939 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/Data/Gauge.php @@ -0,0 +1,22 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\Data; + +final class Gauge implements DataInterface +{ + + /** + * @var iterable<NumberDataPoint> + * @readonly + */ + public iterable $dataPoints; + /** + * @param iterable<NumberDataPoint> $dataPoints + */ + public function __construct(iterable $dataPoints) + { + $this->dataPoints = $dataPoints; + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/Data/Histogram.php b/vendor/open-telemetry/sdk/Metrics/Data/Histogram.php new file mode 100644 index 000000000..782698026 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/Data/Histogram.php @@ -0,0 +1,29 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\Data; + +final class Histogram implements DataInterface +{ + + /** + * @var iterable<HistogramDataPoint> + * @readonly + */ + public iterable $dataPoints; + /** + * @var string|Temporality + * @readonly + */ + public $temporality; + /** + * @param iterable<HistogramDataPoint> $dataPoints + * @param string|Temporality $temporality + */ + public function __construct(iterable $dataPoints, $temporality) + { + $this->dataPoints = $dataPoints; + $this->temporality = $temporality; + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/Data/HistogramDataPoint.php b/vendor/open-telemetry/sdk/Metrics/Data/HistogramDataPoint.php new file mode 100644 index 000000000..4c9df07b4 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/Data/HistogramDataPoint.php @@ -0,0 +1,76 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\Data; + +use OpenTelemetry\SDK\Common\Attribute\AttributesInterface; + +final class HistogramDataPoint +{ + /** + * @readonly + */ + public int $count; + /** + * @var float|int + * @readonly + */ + public $sum; + /** + * @var float|int + * @readonly + */ + public $min; + /** + * @var float|int + * @readonly + */ + public $max; + /** + * @var int[] + * @readonly + */ + public array $bucketCounts; + /** + * @var list<float|int> + * @readonly + */ + public array $explicitBounds; + /** + * @readonly + */ + public AttributesInterface $attributes; + /** + * @readonly + */ + public int $startTimestamp; + /** + * @readonly + */ + public int $timestamp; + /** + * @readonly + */ + public iterable $exemplars = []; + /** + * @param float|int $sum + * @param float|int $min + * @param float|int $max + * @param int[] $bucketCounts + * @param list<float|int> $explicitBounds + */ + public function __construct(int $count, $sum, $min, $max, array $bucketCounts, array $explicitBounds, AttributesInterface $attributes, int $startTimestamp, int $timestamp, iterable $exemplars = []) + { + $this->count = $count; + $this->sum = $sum; + $this->min = $min; + $this->max = $max; + $this->bucketCounts = $bucketCounts; + $this->explicitBounds = $explicitBounds; + $this->attributes = $attributes; + $this->startTimestamp = $startTimestamp; + $this->timestamp = $timestamp; + $this->exemplars = $exemplars; + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/Data/Metric.php b/vendor/open-telemetry/sdk/Metrics/Data/Metric.php new file mode 100644 index 000000000..41fcb52dd --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/Data/Metric.php @@ -0,0 +1,46 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\Data; + +use OpenTelemetry\SDK\Common\Instrumentation\InstrumentationScopeInterface; +use OpenTelemetry\SDK\Resource\ResourceInfo; + +final class Metric +{ + /** + * @readonly + */ + public InstrumentationScopeInterface $instrumentationScope; + /** + * @readonly + */ + public ResourceInfo $resource; + /** + * @readonly + */ + public string $name; + /** + * @readonly + */ + public ?string $description; + /** + * @readonly + */ + public ?string $unit; + /** + * @readonly + */ + public DataInterface $data; + + public function __construct(InstrumentationScopeInterface $instrumentationScope, ResourceInfo $resource, string $name, ?string $unit, ?string $description, DataInterface $data) + { + $this->instrumentationScope = $instrumentationScope; + $this->resource = $resource; + $this->name = $name; + $this->description = $description; + $this->unit = $unit; + $this->data = $data; + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/Data/NumberDataPoint.php b/vendor/open-telemetry/sdk/Metrics/Data/NumberDataPoint.php new file mode 100644 index 000000000..1d00e783a --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/Data/NumberDataPoint.php @@ -0,0 +1,43 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\Data; + +use OpenTelemetry\SDK\Common\Attribute\AttributesInterface; + +final class NumberDataPoint +{ + /** + * @var float|int + * @readonly + */ + public $value; + /** + * @readonly + */ + public AttributesInterface $attributes; + /** + * @readonly + */ + public int $startTimestamp; + /** + * @readonly + */ + public int $timestamp; + /** + * @readonly + */ + public iterable $exemplars = []; + /** + * @param float|int $value + */ + public function __construct($value, AttributesInterface $attributes, int $startTimestamp, int $timestamp, iterable $exemplars = []) + { + $this->value = $value; + $this->attributes = $attributes; + $this->startTimestamp = $startTimestamp; + $this->timestamp = $timestamp; + $this->exemplars = $exemplars; + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/Data/Sum.php b/vendor/open-telemetry/sdk/Metrics/Data/Sum.php new file mode 100644 index 000000000..77c4c1021 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/Data/Sum.php @@ -0,0 +1,34 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\Data; + +final class Sum implements DataInterface +{ + + /** + * @var iterable<NumberDataPoint> + * @readonly + */ + public iterable $dataPoints; + /** + * @var string|Temporality + * @readonly + */ + public $temporality; + /** + * @readonly + */ + public bool $monotonic; + /** + * @param iterable<NumberDataPoint> $dataPoints + * @param string|Temporality $temporality + */ + public function __construct(iterable $dataPoints, $temporality, bool $monotonic) + { + $this->dataPoints = $dataPoints; + $this->temporality = $temporality; + $this->monotonic = $monotonic; + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/Data/Temporality.php b/vendor/open-telemetry/sdk/Metrics/Data/Temporality.php new file mode 100644 index 000000000..b6642ebd0 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/Data/Temporality.php @@ -0,0 +1,20 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\Data; + +/** + * Metric aggregation temporality. + * + * Has to be type-hinted as `string|Temporality` to be forward compatible. + */ +final class Temporality +{ + public const DELTA = 'Delta'; + public const CUMULATIVE = 'Cumulative'; + + private function __construct() + { + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/DefaultAggregationProviderInterface.php b/vendor/open-telemetry/sdk/Metrics/DefaultAggregationProviderInterface.php new file mode 100644 index 000000000..e5c2fcc0c --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/DefaultAggregationProviderInterface.php @@ -0,0 +1,13 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics; + +interface DefaultAggregationProviderInterface +{ + /** + * @param string|InstrumentType $instrumentType + */ + public function defaultAggregation($instrumentType): ?AggregationInterface; +} diff --git a/vendor/open-telemetry/sdk/Metrics/DefaultAggregationProviderTrait.php b/vendor/open-telemetry/sdk/Metrics/DefaultAggregationProviderTrait.php new file mode 100644 index 000000000..37c5cb110 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/DefaultAggregationProviderTrait.php @@ -0,0 +1,28 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics; + +trait DefaultAggregationProviderTrait +{ + public function defaultAggregation($instrumentType): ?AggregationInterface + { + switch ($instrumentType) { + case InstrumentType::COUNTER: + case InstrumentType::ASYNCHRONOUS_COUNTER: + return new Aggregation\SumAggregation(true); + case InstrumentType::UP_DOWN_COUNTER: + case InstrumentType::ASYNCHRONOUS_UP_DOWN_COUNTER: + return new Aggregation\SumAggregation(); + case InstrumentType::HISTOGRAM: + return new Aggregation\ExplicitBucketHistogramAggregation([0, 5, 10, 25, 50, 75, 100, 250, 500, 1000]); + case InstrumentType::ASYNCHRONOUS_GAUGE: + return new Aggregation\LastValueAggregation(); + } + + // @codeCoverageIgnoreStart + return null; + // @codeCoverageIgnoreEnd + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/Exemplar/BucketEntry.php b/vendor/open-telemetry/sdk/Metrics/Exemplar/BucketEntry.php new file mode 100644 index 000000000..3a50430ed --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/Exemplar/BucketEntry.php @@ -0,0 +1,26 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\Exemplar; + +use OpenTelemetry\SDK\Common\Attribute\AttributesInterface; + +/** + * @internal + */ +final class BucketEntry +{ + /** + * @var int|string + */ + public $index; + /** + * @var float|int + */ + public $value; + public int $timestamp; + public AttributesInterface $attributes; + public ?string $traceId = null; + public ?string $spanId = null; +} diff --git a/vendor/open-telemetry/sdk/Metrics/Exemplar/BucketStorage.php b/vendor/open-telemetry/sdk/Metrics/Exemplar/BucketStorage.php new file mode 100644 index 000000000..574ce92af --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/Exemplar/BucketStorage.php @@ -0,0 +1,92 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\Exemplar; + +use function array_fill; +use function assert; +use function count; +use OpenTelemetry\API\Trace\Span; +use OpenTelemetry\Context\ContextInterface; +use OpenTelemetry\SDK\Common\Attribute\Attributes; +use OpenTelemetry\SDK\Common\Attribute\AttributesInterface; +use OpenTelemetry\SDK\Metrics\Data\Exemplar; + +/** + * @internal + */ +final class BucketStorage +{ + /** @var array<int, BucketEntry|null> */ + private array $buckets; + + public function __construct(int $size = 0) + { + $this->buckets = array_fill(0, $size, null); + } + + /** + * @param int|string $index + * @param float|int $value + */ + public function store(int $bucket, $index, $value, AttributesInterface $attributes, ContextInterface $context, int $timestamp): void + { + assert($bucket <= count($this->buckets)); + + $exemplar = $this->buckets[$bucket] ??= new BucketEntry(); + $exemplar->index = $index; + $exemplar->value = $value; + $exemplar->timestamp = $timestamp; + $exemplar->attributes = $attributes; + + if (($spanContext = Span::fromContext($context)->getContext())->isValid()) { + $exemplar->traceId = $spanContext->getTraceId(); + $exemplar->spanId = $spanContext->getSpanId(); + } else { + $exemplar->traceId = null; + $exemplar->spanId = null; + } + } + + /** + * @param array<AttributesInterface> $dataPointAttributes + * @return array<Exemplar> + */ + public function collect(array $dataPointAttributes): array + { + $exemplars = []; + foreach ($this->buckets as $index => &$exemplar) { + if (!$exemplar) { + continue; + } + + $exemplars[$index] = new Exemplar( + $exemplar->index, + $exemplar->value, + $exemplar->timestamp, + $this->filterExemplarAttributes( + $dataPointAttributes[$exemplar->index], + $exemplar->attributes, + ), + $exemplar->traceId, + $exemplar->spanId, + ); + $exemplar = null; + } + + return $exemplars; + } + + private function filterExemplarAttributes(AttributesInterface $dataPointAttributes, AttributesInterface $exemplarAttributes): AttributesInterface + { + $attributes = []; + foreach ($exemplarAttributes as $key => $value) { + if ($dataPointAttributes->get($key) === null) { + $attributes[$key] = $value; + } + } + + return new Attributes($attributes, $exemplarAttributes->getDroppedAttributesCount()); + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/Exemplar/ExemplarFilter/AllExemplarFilter.php b/vendor/open-telemetry/sdk/Metrics/Exemplar/ExemplarFilter/AllExemplarFilter.php new file mode 100644 index 000000000..b74e738aa --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/Exemplar/ExemplarFilter/AllExemplarFilter.php @@ -0,0 +1,21 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\Exemplar\ExemplarFilter; + +use OpenTelemetry\Context\ContextInterface; +use OpenTelemetry\SDK\Common\Attribute\AttributesInterface; +use OpenTelemetry\SDK\Metrics\Exemplar\ExemplarFilterInterface; + +/** + * The exemplar spec is not yet stable, and can change at any time. + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/sdk.md#exemplar + */ +final class AllExemplarFilter implements ExemplarFilterInterface +{ + public function accepts($value, AttributesInterface $attributes, ContextInterface $context, int $timestamp): bool + { + return true; + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/Exemplar/ExemplarFilter/NoneExemplarFilter.php b/vendor/open-telemetry/sdk/Metrics/Exemplar/ExemplarFilter/NoneExemplarFilter.php new file mode 100644 index 000000000..91fdf3b55 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/Exemplar/ExemplarFilter/NoneExemplarFilter.php @@ -0,0 +1,21 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\Exemplar\ExemplarFilter; + +use OpenTelemetry\Context\ContextInterface; +use OpenTelemetry\SDK\Common\Attribute\AttributesInterface; +use OpenTelemetry\SDK\Metrics\Exemplar\ExemplarFilterInterface; + +/** + * The exemplar spec is not yet stable, and can change at any time. + * see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/sdk.md#exemplar + */ +final class NoneExemplarFilter implements ExemplarFilterInterface +{ + public function accepts($value, AttributesInterface $attributes, ContextInterface $context, int $timestamp): bool + { + return false; + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/Exemplar/ExemplarFilter/WithSampledTraceExemplarFilter.php b/vendor/open-telemetry/sdk/Metrics/Exemplar/ExemplarFilter/WithSampledTraceExemplarFilter.php new file mode 100644 index 000000000..3e800b416 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/Exemplar/ExemplarFilter/WithSampledTraceExemplarFilter.php @@ -0,0 +1,22 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\Exemplar\ExemplarFilter; + +use OpenTelemetry\API\Trace\Span; +use OpenTelemetry\Context\ContextInterface; +use OpenTelemetry\SDK\Common\Attribute\AttributesInterface; +use OpenTelemetry\SDK\Metrics\Exemplar\ExemplarFilterInterface; + +/** + * The exemplar spec is not yet stable, and can change at any time. + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/sdk.md#exemplar + */ +final class WithSampledTraceExemplarFilter implements ExemplarFilterInterface +{ + public function accepts($value, AttributesInterface $attributes, ContextInterface $context, int $timestamp): bool + { + return Span::fromContext($context)->getContext()->isSampled(); + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/Exemplar/ExemplarFilterInterface.php b/vendor/open-telemetry/sdk/Metrics/Exemplar/ExemplarFilterInterface.php new file mode 100644 index 000000000..1d5dec7b8 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/Exemplar/ExemplarFilterInterface.php @@ -0,0 +1,20 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\Exemplar; + +use OpenTelemetry\Context\ContextInterface; +use OpenTelemetry\SDK\Common\Attribute\AttributesInterface; + +/** + * The exemplar spec is not yet stable, and can change at any time. + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/sdk.md#exemplar + */ +interface ExemplarFilterInterface +{ + /** + * @param float|int $value + */ + public function accepts($value, AttributesInterface $attributes, ContextInterface $context, int $timestamp): bool; +} diff --git a/vendor/open-telemetry/sdk/Metrics/Exemplar/ExemplarReservoirInterface.php b/vendor/open-telemetry/sdk/Metrics/Exemplar/ExemplarReservoirInterface.php new file mode 100644 index 000000000..70648b919 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/Exemplar/ExemplarReservoirInterface.php @@ -0,0 +1,24 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\Exemplar; + +use OpenTelemetry\Context\ContextInterface; +use OpenTelemetry\SDK\Common\Attribute\AttributesInterface; +use OpenTelemetry\SDK\Metrics\Data\Exemplar; + +interface ExemplarReservoirInterface +{ + /** + * @param int|string $index + * @param float|int $value + */ + public function offer($index, $value, AttributesInterface $attributes, ContextInterface $context, int $timestamp): void; + + /** + * @param array<AttributesInterface> $dataPointAttributes + * @return array<Exemplar> + */ + public function collect(array $dataPointAttributes): array; +} diff --git a/vendor/open-telemetry/sdk/Metrics/Exemplar/FilteredReservoir.php b/vendor/open-telemetry/sdk/Metrics/Exemplar/FilteredReservoir.php new file mode 100644 index 000000000..0e4f24357 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/Exemplar/FilteredReservoir.php @@ -0,0 +1,36 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\Exemplar; + +use OpenTelemetry\Context\ContextInterface; +use OpenTelemetry\SDK\Common\Attribute\AttributesInterface; + +/** + * The exemplar spec is not yet stable, and can change at any time. + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/sdk.md#exemplar + */ +final class FilteredReservoir implements ExemplarReservoirInterface +{ + private ExemplarReservoirInterface $reservoir; + private ExemplarFilterInterface $filter; + + public function __construct(ExemplarReservoirInterface $reservoir, ExemplarFilterInterface $filter) + { + $this->reservoir = $reservoir; + $this->filter = $filter; + } + + public function offer($index, $value, AttributesInterface $attributes, ContextInterface $context, int $timestamp): void + { + if ($this->filter->accepts($value, $attributes, $context, $timestamp)) { + $this->reservoir->offer($index, $value, $attributes, $context, $timestamp); + } + } + + public function collect(array $dataPointAttributes): array + { + return $this->reservoir->collect($dataPointAttributes); + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/Exemplar/FixedSizeReservoir.php b/vendor/open-telemetry/sdk/Metrics/Exemplar/FixedSizeReservoir.php new file mode 100644 index 000000000..479292a4c --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/Exemplar/FixedSizeReservoir.php @@ -0,0 +1,38 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\Exemplar; + +use OpenTelemetry\Context\ContextInterface; +use OpenTelemetry\SDK\Common\Attribute\AttributesInterface; +use function random_int; + +final class FixedSizeReservoir implements ExemplarReservoirInterface +{ + private BucketStorage $storage; + private int $size; + private int $measurements = 0; + + public function __construct(int $size = 4) + { + $this->storage = new BucketStorage($size); + $this->size = $size; + } + + public function offer($index, $value, AttributesInterface $attributes, ContextInterface $context, int $timestamp): void + { + $bucket = random_int(0, $this->measurements); + $this->measurements++; + if ($bucket < $this->size) { + $this->storage->store($bucket, $index, $value, $attributes, $context, $timestamp); + } + } + + public function collect(array $dataPointAttributes): array + { + $this->measurements = 0; + + return $this->storage->collect($dataPointAttributes); + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/Exemplar/HistogramBucketReservoir.php b/vendor/open-telemetry/sdk/Metrics/Exemplar/HistogramBucketReservoir.php new file mode 100644 index 000000000..b56a1b2be --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/Exemplar/HistogramBucketReservoir.php @@ -0,0 +1,40 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\Exemplar; + +use function count; +use OpenTelemetry\Context\ContextInterface; +use OpenTelemetry\SDK\Common\Attribute\AttributesInterface; + +final class HistogramBucketReservoir implements ExemplarReservoirInterface +{ + private BucketStorage $storage; + /** + * @var list<float|int> + */ + private array $boundaries; + + /** + * @param list<float|int> $boundaries + */ + public function __construct(array $boundaries) + { + $this->storage = new BucketStorage(count($boundaries) + 1); + $this->boundaries = $boundaries; + } + + public function offer($index, $value, AttributesInterface $attributes, ContextInterface $context, int $timestamp): void + { + $boundariesCount = count($this->boundaries); + for ($i = 0; $i < $boundariesCount && $this->boundaries[$i] < $value; $i++) { + } + $this->storage->store($i, $index, $value, $attributes, $context, $timestamp); + } + + public function collect(array $dataPointAttributes): array + { + return $this->storage->collect($dataPointAttributes); + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/Exemplar/NoopReservoir.php b/vendor/open-telemetry/sdk/Metrics/Exemplar/NoopReservoir.php new file mode 100644 index 000000000..010aeff20 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/Exemplar/NoopReservoir.php @@ -0,0 +1,21 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\Exemplar; + +use OpenTelemetry\Context\ContextInterface; +use OpenTelemetry\SDK\Common\Attribute\AttributesInterface; + +final class NoopReservoir implements ExemplarReservoirInterface +{ + public function offer($index, $value, AttributesInterface $attributes, ContextInterface $context, int $timestamp): void + { + // no-op + } + + public function collect(array $dataPointAttributes): array + { + return []; + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/Histogram.php b/vendor/open-telemetry/sdk/Metrics/Histogram.php new file mode 100644 index 000000000..532b1b4bf --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/Histogram.php @@ -0,0 +1,37 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics; + +use OpenTelemetry\API\Metrics\HistogramInterface; +use OpenTelemetry\SDK\Metrics\MetricRegistry\MetricWriterInterface; + +/** + * @internal + */ +final class Histogram implements HistogramInterface +{ + private MetricWriterInterface $writer; + private Instrument $instrument; + private ReferenceCounterInterface $referenceCounter; + + public function __construct(MetricWriterInterface $writer, Instrument $instrument, ReferenceCounterInterface $referenceCounter) + { + $this->writer = $writer; + $this->instrument = $instrument; + $this->referenceCounter = $referenceCounter; + + $this->referenceCounter->acquire(); + } + + public function __destruct() + { + $this->referenceCounter->release(); + } + + public function record($amount, iterable $attributes = [], $context = null): void + { + $this->writer->record($this->instrument, $amount, $attributes, $context); + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/Instrument.php b/vendor/open-telemetry/sdk/Metrics/Instrument.php new file mode 100644 index 000000000..3543604c0 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/Instrument.php @@ -0,0 +1,36 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics; + +final class Instrument +{ + /** + * @var string|InstrumentType + * @readonly + */ + public $type; + /** + * @readonly + */ + public string $name; + /** + * @readonly + */ + public ?string $unit; + /** + * @readonly + */ + public ?string $description; + /** + * @param string|InstrumentType $type + */ + public function __construct($type, string $name, ?string $unit, ?string $description) + { + $this->type = $type; + $this->name = $name; + $this->unit = $unit; + $this->description = $description; + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/InstrumentType.php b/vendor/open-telemetry/sdk/Metrics/InstrumentType.php new file mode 100644 index 000000000..ae603b2fe --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/InstrumentType.php @@ -0,0 +1,25 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics; + +/** + * Instrument type. + * + * Has to be type-hinted as `string|InstrumentType` to be forward compatible. + */ +final class InstrumentType +{ + public const COUNTER = 'Counter'; + public const UP_DOWN_COUNTER = 'UpDownCounter'; + public const HISTOGRAM = 'Histogram'; + + public const ASYNCHRONOUS_COUNTER = 'AsynchronousCounter'; + public const ASYNCHRONOUS_UP_DOWN_COUNTER = 'AsynchronousUpDownCounter'; + public const ASYNCHRONOUS_GAUGE = 'AsynchronousGauge'; + + private function __construct() + { + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/Meter.php b/vendor/open-telemetry/sdk/Metrics/Meter.php new file mode 100644 index 000000000..902284839 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/Meter.php @@ -0,0 +1,314 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics; + +use ArrayAccess; +use OpenTelemetry\API\Metrics\CounterInterface; +use OpenTelemetry\API\Metrics\HistogramInterface; +use OpenTelemetry\API\Metrics\MeterInterface; +use OpenTelemetry\API\Metrics\ObservableCounterInterface; +use OpenTelemetry\API\Metrics\ObservableGaugeInterface; +use OpenTelemetry\API\Metrics\ObservableUpDownCounterInterface; +use OpenTelemetry\API\Metrics\UpDownCounterInterface; +use OpenTelemetry\SDK\Common\Instrumentation\InstrumentationScopeInterface; +use OpenTelemetry\SDK\Common\Time\ClockInterface; +use function OpenTelemetry\SDK\Common\Util\closure; +use OpenTelemetry\SDK\Common\Util\WeakMap; +use OpenTelemetry\SDK\Metrics\Exemplar\ExemplarFilterInterface; +use OpenTelemetry\SDK\Metrics\MetricRegistration\MultiRegistryRegistration; +use OpenTelemetry\SDK\Metrics\MetricRegistration\RegistryRegistration; +use OpenTelemetry\SDK\Metrics\MetricRegistry\MetricRegistryInterface; +use OpenTelemetry\SDK\Metrics\MetricRegistry\MetricWriterInterface; +use OpenTelemetry\SDK\Resource\ResourceInfo; +use const PHP_VERSION_ID; +use function serialize; + +/** + * @internal + */ +final class Meter implements MeterInterface +{ + private MetricFactoryInterface $metricFactory; + private ResourceInfo $resource; + private ClockInterface $clock; + private StalenessHandlerFactoryInterface $stalenessHandlerFactory; + /** @var iterable<MetricSourceRegistryInterface&DefaultAggregationProviderInterface> */ + private iterable $metricRegistries; + private ViewRegistryInterface $viewRegistry; + private ?ExemplarFilterInterface $exemplarFilter; + private MeterInstruments $instruments; + private InstrumentationScopeInterface $instrumentationScope; + + private MetricRegistryInterface $registry; + private MetricWriterInterface $writer; + + private ?string $instrumentationScopeId = null; + + /** + * @param iterable<MetricSourceRegistryInterface&DefaultAggregationProviderInterface> $metricRegistries + */ + public function __construct( + MetricFactoryInterface $metricFactory, + ResourceInfo $resource, + ClockInterface $clock, + StalenessHandlerFactoryInterface $stalenessHandlerFactory, + iterable $metricRegistries, + ViewRegistryInterface $viewRegistry, + ?ExemplarFilterInterface $exemplarFilter, + MeterInstruments $instruments, + InstrumentationScopeInterface $instrumentationScope, + MetricRegistryInterface $registry, + MetricWriterInterface $writer + ) { + $this->metricFactory = $metricFactory; + $this->resource = $resource; + $this->clock = $clock; + $this->stalenessHandlerFactory = $stalenessHandlerFactory; + $this->metricRegistries = $metricRegistries; + $this->viewRegistry = $viewRegistry; + $this->exemplarFilter = $exemplarFilter; + $this->instruments = $instruments; + $this->instrumentationScope = $instrumentationScope; + $this->registry = $registry; + $this->writer = $writer; + } + + public function createCounter(string $name, ?string $unit = null, ?string $description = null): CounterInterface + { + [$instrument, $referenceCounter] = $this->createSynchronousWriter( + InstrumentType::COUNTER, + $name, + $unit, + $description, + ); + + return new Counter($this->writer, $instrument, $referenceCounter); + } + + public function createObservableCounter(string $name, ?string $unit = null, ?string $description = null, callable ...$callbacks): ObservableCounterInterface + { + [$instrument, $referenceCounter, $destructors] = $this->createAsynchronousObserver( + InstrumentType::ASYNCHRONOUS_COUNTER, + $name, + $unit, + $description, + ); + + foreach ($callbacks as $callback) { + $this->writer->registerCallback(closure($callback), $instrument); + $referenceCounter->acquire(true); + } + + return new ObservableCounter($this->writer, $instrument, $referenceCounter, $destructors); + } + + public function createHistogram(string $name, ?string $unit = null, ?string $description = null): HistogramInterface + { + [$instrument, $referenceCounter] = $this->createSynchronousWriter( + InstrumentType::HISTOGRAM, + $name, + $unit, + $description, + ); + + return new Histogram($this->writer, $instrument, $referenceCounter); + } + + public function createObservableGauge(string $name, ?string $unit = null, ?string $description = null, callable ...$callbacks): ObservableGaugeInterface + { + [$instrument, $referenceCounter, $destructors] = $this->createAsynchronousObserver( + InstrumentType::ASYNCHRONOUS_GAUGE, + $name, + $unit, + $description, + ); + + foreach ($callbacks as $callback) { + $this->writer->registerCallback(closure($callback), $instrument); + $referenceCounter->acquire(true); + } + + return new ObservableGauge($this->writer, $instrument, $referenceCounter, $destructors); + } + + public function createUpDownCounter(string $name, ?string $unit = null, ?string $description = null): UpDownCounterInterface + { + [$instrument, $referenceCounter] = $this->createSynchronousWriter( + InstrumentType::UP_DOWN_COUNTER, + $name, + $unit, + $description, + ); + + return new UpDownCounter($this->writer, $instrument, $referenceCounter); + } + + public function createObservableUpDownCounter(string $name, ?string $unit = null, ?string $description = null, callable ...$callbacks): ObservableUpDownCounterInterface + { + [$instrument, $referenceCounter, $destructors] = $this->createAsynchronousObserver( + InstrumentType::ASYNCHRONOUS_UP_DOWN_COUNTER, + $name, + $unit, + $description, + ); + + foreach ($callbacks as $callback) { + $this->writer->registerCallback(closure($callback), $instrument); + $referenceCounter->acquire(true); + } + + return new ObservableUpDownCounter($this->writer, $instrument, $referenceCounter, $destructors); + } + + /** + * @param string|InstrumentType $instrumentType + * @return array{Instrument, ReferenceCounterInterface} + */ + private function createSynchronousWriter($instrumentType, string $name, ?string $unit, ?string $description): array + { + $instrument = new Instrument($instrumentType, $name, $unit, $description); + + $instrumentationScopeId = $this->instrumentationScopeId($this->instrumentationScope); + $instrumentId = $this->instrumentId($instrument); + + $instruments = $this->instruments; + if ($writer = $instruments->writers[$instrumentationScopeId][$instrumentId] ?? null) { + return $writer; + } + + $stalenessHandler = $this->stalenessHandlerFactory->create(); + $instruments->startTimestamp ??= $this->clock->now(); + $streamIds = $this->metricFactory->createSynchronousWriter( + $this->registry, + $this->resource, + $this->instrumentationScope, + $instrument, + $instruments->startTimestamp, + $this->viewRegistrationRequests($instrument, $stalenessHandler), + $this->exemplarFilter, + ); + + $registry = $this->registry; + $stalenessHandler->onStale(static function () use ($instruments, $instrumentationScopeId, $instrumentId, $registry, $streamIds): void { + unset($instruments->writers[$instrumentationScopeId][$instrumentId]); + if (!$instruments->writers[$instrumentationScopeId]) { + unset($instruments->writers[$instrumentationScopeId]); + } + foreach ($streamIds as $streamId) { + $registry->unregisterStream($streamId); + } + + $instruments->startTimestamp = null; + }); + + return $instruments->writers[$instrumentationScopeId][$instrumentId] = [ + $instrument, + $stalenessHandler, + ]; + } + + /** + * @param string|InstrumentType $instrumentType + * @return array{Instrument, ReferenceCounterInterface, ArrayAccess<object, ObservableCallbackDestructor>} + */ + private function createAsynchronousObserver($instrumentType, string $name, ?string $unit, ?string $description): array + { + $instrument = new Instrument($instrumentType, $name, $unit, $description); + + $instrumentationScopeId = $this->instrumentationScopeId($this->instrumentationScope); + $instrumentId = $this->instrumentId($instrument); + + $instruments = $this->instruments; + /** @phan-suppress-next-line PhanDeprecatedProperty */ + $instruments->staleObservers = []; + if ($observer = $instruments->observers[$instrumentationScopeId][$instrumentId] ?? null) { + return $observer; + } + + $stalenessHandler = $this->stalenessHandlerFactory->create(); + $instruments->startTimestamp ??= $this->clock->now(); + $streamIds = $this->metricFactory->createAsynchronousObserver( + $this->registry, + $this->resource, + $this->instrumentationScope, + $instrument, + $instruments->startTimestamp, + $this->viewRegistrationRequests($instrument, $stalenessHandler), + ); + + $registry = $this->registry; + $stalenessHandler->onStale(static function () use ($instruments, $instrumentationScopeId, $instrumentId, $registry, $streamIds): void { + if (PHP_VERSION_ID < 80000) { + /** @phan-suppress-next-line PhanDeprecatedProperty */ + $instruments->staleObservers[] = $instruments->observers[$instrumentationScopeId][$instrumentId][2]; + } + + unset($instruments->observers[$instrumentationScopeId][$instrumentId]); + if (!$instruments->observers[$instrumentationScopeId]) { + unset($instruments->observers[$instrumentationScopeId]); + } + foreach ($streamIds as $streamId) { + $registry->unregisterStream($streamId); + } + + $instruments->startTimestamp = null; + }); + + /** @var ArrayAccess<object, ObservableCallbackDestructor> $destructors */ + $destructors = WeakMap::create(); + + return $instruments->observers[$instrumentationScopeId][$instrumentId] = [ + $instrument, + $stalenessHandler, + $destructors, + ]; + } + + /** + * @return iterable<array{ViewProjection, MetricRegistrationInterface}> + */ + private function viewRegistrationRequests(Instrument $instrument, StalenessHandlerInterface $stalenessHandler): iterable + { + $views = $this->viewRegistry->find($instrument, $this->instrumentationScope) ?? [ + new ViewProjection( + $instrument->name, + $instrument->unit, + $instrument->description, + null, + null, + ), + ]; + + $compositeRegistration = new MultiRegistryRegistration($this->metricRegistries, $stalenessHandler); + foreach ($views as $view) { + if ($view->aggregation !== null) { + yield [$view, $compositeRegistration]; + } else { + foreach ($this->metricRegistries as $metricRegistry) { + yield [ + new ViewProjection( + $view->name, + $view->unit, + $view->description, + $view->attributeKeys, + $metricRegistry->defaultAggregation($instrument->type), + ), + new RegistryRegistration($metricRegistry, $stalenessHandler), + ]; + } + } + } + } + + private function instrumentationScopeId(InstrumentationScopeInterface $instrumentationScope): string + { + return $this->instrumentationScopeId ??= serialize($instrumentationScope); + } + + private function instrumentId(Instrument $instrument): string + { + return serialize($instrument); + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/MeterInstruments.php b/vendor/open-telemetry/sdk/Metrics/MeterInstruments.php new file mode 100644 index 000000000..c331cb608 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/MeterInstruments.php @@ -0,0 +1,29 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics; + +use ArrayAccess; + +/** + * @internal + */ +final class MeterInstruments +{ + public ?int $startTimestamp = null; + /** + * @var array<string, array<string, array{Instrument, ReferenceCounterInterface, ArrayAccess<object, ObservableCallbackDestructor>}>> + */ + public array $observers = []; + /** + * @var array<string, array<string, array{Instrument, ReferenceCounterInterface}>> + */ + public array $writers = []; + + /** + * @var list<ArrayAccess<object, ObservableCallbackDestructor>> + * @deprecated + */ + public array $staleObservers = []; +} diff --git a/vendor/open-telemetry/sdk/Metrics/MeterProvider.php b/vendor/open-telemetry/sdk/Metrics/MeterProvider.php new file mode 100644 index 000000000..36c17cf81 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/MeterProvider.php @@ -0,0 +1,130 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics; + +use OpenTelemetry\API\Metrics\MeterInterface; +use OpenTelemetry\API\Metrics\Noop\NoopMeter; +use OpenTelemetry\Context\ContextStorageInterface; +use OpenTelemetry\SDK\Common\Attribute\AttributesFactoryInterface; +use OpenTelemetry\SDK\Common\Instrumentation\InstrumentationScopeFactoryInterface; +use OpenTelemetry\SDK\Common\Time\ClockInterface; +use OpenTelemetry\SDK\Metrics\Exemplar\ExemplarFilterInterface; +use OpenTelemetry\SDK\Metrics\MetricFactory\StreamFactory; +use OpenTelemetry\SDK\Metrics\MetricRegistry\MetricRegistry; +use OpenTelemetry\SDK\Metrics\MetricRegistry\MetricRegistryInterface; +use OpenTelemetry\SDK\Metrics\MetricRegistry\MetricWriterInterface; +use OpenTelemetry\SDK\Resource\ResourceInfo; +use OpenTelemetry\SDK\Sdk; + +final class MeterProvider implements MeterProviderInterface +{ + private MetricFactoryInterface $metricFactory; + private ResourceInfo $resource; + private ClockInterface $clock; + private InstrumentationScopeFactoryInterface $instrumentationScopeFactory; + private iterable $metricReaders; + private ViewRegistryInterface $viewRegistry; + private ?ExemplarFilterInterface $exemplarFilter; + private StalenessHandlerFactoryInterface $stalenessHandlerFactory; + private MeterInstruments $instruments; + private MetricRegistryInterface $registry; + private MetricWriterInterface $writer; + + private bool $closed = false; + + /** + * @param iterable<MetricReaderInterface&MetricSourceRegistryInterface&DefaultAggregationProviderInterface> $metricReaders + */ + public function __construct( + ?ContextStorageInterface $contextStorage, + ResourceInfo $resource, + ClockInterface $clock, + AttributesFactoryInterface $attributesFactory, + InstrumentationScopeFactoryInterface $instrumentationScopeFactory, + iterable $metricReaders, + ViewRegistryInterface $viewRegistry, + ?ExemplarFilterInterface $exemplarFilter, + StalenessHandlerFactoryInterface $stalenessHandlerFactory, + MetricFactoryInterface $metricFactory = null + ) { + $this->metricFactory = $metricFactory ?? new StreamFactory(); + $this->resource = $resource; + $this->clock = $clock; + $this->instrumentationScopeFactory = $instrumentationScopeFactory; + $this->metricReaders = $metricReaders; + $this->viewRegistry = $viewRegistry; + $this->exemplarFilter = $exemplarFilter; + $this->stalenessHandlerFactory = $stalenessHandlerFactory; + $this->instruments = new MeterInstruments(); + + $registry = new MetricRegistry($contextStorage, $attributesFactory, $clock); + $this->registry = $registry; + $this->writer = $registry; + } + + public function getMeter( + string $name, + ?string $version = null, + ?string $schemaUrl = null, + iterable $attributes = [] + ): MeterInterface { + if ($this->closed || Sdk::isDisabled()) { //@todo create meter provider from factory, and move Sdk::isDisabled() there + return new NoopMeter(); + } + + return new Meter( + $this->metricFactory, + $this->resource, + $this->clock, + $this->stalenessHandlerFactory, + $this->metricReaders, + $this->viewRegistry, + $this->exemplarFilter, + $this->instruments, + $this->instrumentationScopeFactory->create($name, $version, $schemaUrl, $attributes), + $this->registry, + $this->writer, + ); + } + + public function shutdown(): bool + { + if ($this->closed) { + return false; + } + + $this->closed = true; + + $success = true; + foreach ($this->metricReaders as $metricReader) { + if (!$metricReader->shutdown()) { + $success = false; + } + } + + return $success; + } + + public function forceFlush(): bool + { + if ($this->closed) { + return false; + } + + $success = true; + foreach ($this->metricReaders as $metricReader) { + if (!$metricReader->forceFlush()) { + $success = false; + } + } + + return $success; + } + + public static function builder(): MeterProviderBuilder + { + return new MeterProviderBuilder(); + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/MeterProviderBuilder.php b/vendor/open-telemetry/sdk/Metrics/MeterProviderBuilder.php new file mode 100644 index 000000000..17f0be895 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/MeterProviderBuilder.php @@ -0,0 +1,62 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics; + +use OpenTelemetry\SDK\Common\Attribute\Attributes; +use OpenTelemetry\SDK\Common\Instrumentation\InstrumentationScopeFactory; +use OpenTelemetry\SDK\Common\Time\ClockFactory; +use OpenTelemetry\SDK\Metrics\Exemplar\ExemplarFilter\WithSampledTraceExemplarFilter; +use OpenTelemetry\SDK\Metrics\Exemplar\ExemplarFilterInterface; +use OpenTelemetry\SDK\Metrics\StalenessHandler\NoopStalenessHandlerFactory; +use OpenTelemetry\SDK\Metrics\View\CriteriaViewRegistry; +use OpenTelemetry\SDK\Resource\ResourceInfo; +use OpenTelemetry\SDK\Resource\ResourceInfoFactory; + +class MeterProviderBuilder +{ + // @var array<MetricReaderInterface> + private array $metricReaders = []; + private ?ResourceInfo $resource = null; + private ?ExemplarFilterInterface $exemplarFilter = null; + + public function setResource(ResourceInfo $resource): self + { + $this->resource = $resource; + + return $this; + } + + public function setExemplarFilter(ExemplarFilterInterface $exemplarFilter): self + { + $this->exemplarFilter = $exemplarFilter; + + return $this; + } + + public function addReader(MetricReaderInterface $reader): self + { + $this->metricReaders[] = $reader; + + return $this; + } + + /** + * @psalm-suppress PossiblyInvalidArgument + */ + public function build(): MeterProviderInterface + { + return new MeterProvider( + null, + $this->resource ?? ResourceInfoFactory::emptyResource(), + ClockFactory::getDefault(), + Attributes::factory(), + new InstrumentationScopeFactory(Attributes::factory()), + $this->metricReaders, + new CriteriaViewRegistry(), + $this->exemplarFilter ?? new WithSampledTraceExemplarFilter(), + new NoopStalenessHandlerFactory(), + ); + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/MeterProviderFactory.php b/vendor/open-telemetry/sdk/Metrics/MeterProviderFactory.php new file mode 100644 index 000000000..5f7f9988d --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/MeterProviderFactory.php @@ -0,0 +1,78 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics; + +use InvalidArgumentException; +use OpenTelemetry\API\Behavior\LogsMessagesTrait; +use OpenTelemetry\SDK\Common\Configuration\Configuration; +use OpenTelemetry\SDK\Common\Configuration\KnownValues; +use OpenTelemetry\SDK\Common\Configuration\Variables; +use OpenTelemetry\SDK\Metrics\Exemplar\ExemplarFilter\AllExemplarFilter; +use OpenTelemetry\SDK\Metrics\Exemplar\ExemplarFilter\NoneExemplarFilter; +use OpenTelemetry\SDK\Metrics\Exemplar\ExemplarFilter\WithSampledTraceExemplarFilter; +use OpenTelemetry\SDK\Metrics\Exemplar\ExemplarFilterInterface; +use OpenTelemetry\SDK\Metrics\MetricExporter\NoopMetricExporter; +use OpenTelemetry\SDK\Metrics\MetricReader\ExportingReader; +use OpenTelemetry\SDK\Registry; +use OpenTelemetry\SDK\Resource\ResourceInfoFactory; +use OpenTelemetry\SDK\Sdk; + +class MeterProviderFactory +{ + use LogsMessagesTrait; + + /** + * @todo https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/sdk_exporters/otlp.md#general + * - "The exporter MUST configure the default aggregation on the basis of instrument kind using the + * OTEL_EXPORTER_OTLP_METRICS_DEFAULT_HISTOGRAM_AGGREGATION variable as described below if it is implemented." + */ + public function create(): MeterProviderInterface + { + if (Sdk::isDisabled()) { + return new NoopMeterProvider(); + } + $exporters = Configuration::getList(Variables::OTEL_METRICS_EXPORTER); + //TODO "The SDK MAY accept a comma-separated list to enable setting multiple exporters" + if (count($exporters) !== 1) { + throw new InvalidArgumentException(sprintf('Configuration %s requires exactly 1 exporter', Variables::OTEL_METRICS_EXPORTER)); + } + $exporterName = $exporters[0]; + + try { + $factory = Registry::metricExporterFactory($exporterName); + $exporter = $factory->create(); + } catch (\Throwable $t) { + self::logWarning(sprintf('Unable to create %s meter provider: %s', $exporterName, $t->getMessage())); + $exporter = new NoopMetricExporter(); + } + + // @todo "The exporter MUST be paired with a periodic exporting MetricReader" + $reader = new ExportingReader($exporter); + $resource = ResourceInfoFactory::defaultResource(); + $exemplarFilter = $this->createExemplarFilter(Configuration::getEnum(Variables::OTEL_METRICS_EXEMPLAR_FILTER)); + + return MeterProvider::builder() + ->setResource($resource) + ->addReader($reader) + ->setExemplarFilter($exemplarFilter) + ->build(); + } + + private function createExemplarFilter(string $name): ExemplarFilterInterface + { + switch ($name) { + case KnownValues::VALUE_WITH_SAMPLED_TRACE: + return new WithSampledTraceExemplarFilter(); + case KnownValues::VALUE_ALL: + return new AllExemplarFilter(); + case KnownValues::VALUE_NONE: + return new NoneExemplarFilter(); + default: + self::logWarning('Unknown exemplar filter: ' . $name); + + return new NoneExemplarFilter(); + } + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/MeterProviderInterface.php b/vendor/open-telemetry/sdk/Metrics/MeterProviderInterface.php new file mode 100644 index 000000000..fcb951106 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/MeterProviderInterface.php @@ -0,0 +1,12 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics; + +interface MeterProviderInterface extends \OpenTelemetry\API\Metrics\MeterProviderInterface +{ + public function shutdown(): bool; + + public function forceFlush(): bool; +} diff --git a/vendor/open-telemetry/sdk/Metrics/MetricExporter/ConsoleMetricExporter.php b/vendor/open-telemetry/sdk/Metrics/MetricExporter/ConsoleMetricExporter.php new file mode 100644 index 000000000..62ea7b535 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/MetricExporter/ConsoleMetricExporter.php @@ -0,0 +1,105 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\MetricExporter; + +use OpenTelemetry\SDK\Common\Instrumentation\InstrumentationScopeInterface; +use OpenTelemetry\SDK\Metrics\AggregationTemporalitySelectorInterface; +use OpenTelemetry\SDK\Metrics\Data\Metric; +use OpenTelemetry\SDK\Metrics\Data\Temporality; +use OpenTelemetry\SDK\Metrics\MetricMetadataInterface; +use OpenTelemetry\SDK\Metrics\PushMetricExporterInterface; +use OpenTelemetry\SDK\Resource\ResourceInfo; + +/** + * Console metrics exporter. + * Note that the output is human-readable JSON, not compatible with OTLP. + */ +class ConsoleMetricExporter implements PushMetricExporterInterface, AggregationTemporalitySelectorInterface +{ + /** + * @var string|Temporality|null + */ + private $temporality; + + /** + * @param string|Temporality|null $temporality + */ + public function __construct($temporality = null) + { + $this->temporality = $temporality; + } + /** + * @inheritDoc + */ + public function temporality(MetricMetadataInterface $metric) + { + return $this->temporality ?? $metric->temporality(); + } + + /** + * @inheritDoc + */ + public function export(iterable $batch): bool + { + $resource = null; + $scope = null; + foreach ($batch as $metric) { + /** @var Metric $metric */ + if (!$resource) { + $resource = $this->convertResource($metric->resource); + } + if (!$scope) { + $scope = $this->convertInstrumentationScope($metric->instrumentationScope); + $scope['metrics'] = []; + } + $scope['metrics'][] = $this->convertMetric($metric); + } + $output = [ + 'resource' => $resource, + 'scope' => $scope, + ]; + echo json_encode($output, JSON_PRETTY_PRINT) . PHP_EOL; + + return true; + } + + public function shutdown(): bool + { + return true; + } + + public function forceFlush(): bool + { + return true; + } + + private function convertMetric(Metric $metric): array + { + return [ + 'name' => $metric->name, + 'description' => $metric->description, + 'unit' => $metric->unit, + 'data' => $metric->data, + ]; + } + + private function convertResource(ResourceInfo $resource): array + { + return [ + 'attributes' => $resource->getAttributes()->toArray(), + 'dropped_attributes_count' => $resource->getAttributes()->getDroppedAttributesCount(), + ]; + } + private function convertInstrumentationScope(InstrumentationScopeInterface $scope): array + { + return [ + 'name' => $scope->getName(), + 'version' => $scope->getVersion(), + 'attributes' => $scope->getAttributes()->toArray(), + 'dropped_attributes_count' => $scope->getAttributes()->getDroppedAttributesCount(), + 'schema_url' => $scope->getSchemaUrl(), + ]; + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/MetricExporter/ConsoleMetricExporterFactory.php b/vendor/open-telemetry/sdk/Metrics/MetricExporter/ConsoleMetricExporterFactory.php new file mode 100644 index 000000000..19088738d --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/MetricExporter/ConsoleMetricExporterFactory.php @@ -0,0 +1,16 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\MetricExporter; + +use OpenTelemetry\SDK\Metrics\MetricExporterFactoryInterface; +use OpenTelemetry\SDK\Metrics\MetricExporterInterface; + +class ConsoleMetricExporterFactory implements MetricExporterFactoryInterface +{ + public function create(): MetricExporterInterface + { + return new ConsoleMetricExporter(); + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/MetricExporter/InMemoryExporter.php b/vendor/open-telemetry/sdk/Metrics/MetricExporter/InMemoryExporter.php new file mode 100644 index 000000000..6bbab8b79 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/MetricExporter/InMemoryExporter.php @@ -0,0 +1,78 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\MetricExporter; + +use function array_push; +use OpenTelemetry\SDK\Metrics\AggregationTemporalitySelectorInterface; +use OpenTelemetry\SDK\Metrics\Data\Metric; +use OpenTelemetry\SDK\Metrics\Data\Temporality; +use OpenTelemetry\SDK\Metrics\MetricExporterInterface; +use OpenTelemetry\SDK\Metrics\MetricMetadataInterface; + +/** + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/sdk_exporters/in-memory.md + */ +final class InMemoryExporter implements MetricExporterInterface, AggregationTemporalitySelectorInterface +{ + /** + * @var list<Metric> + */ + private array $metrics = []; + /** + * @var string|Temporality|null + */ + private $temporality; + + private bool $closed = false; + + /** + * @param string|Temporality|null $temporality + */ + public function __construct($temporality = null) + { + $this->temporality = $temporality; + } + + public function temporality(MetricMetadataInterface $metric) + { + return $this->temporality ?? $metric->temporality(); + } + + /** + * @return list<Metric> + */ + public function collect(bool $reset = false): array + { + $metrics = $this->metrics; + if ($reset) { + $this->metrics = []; + } + + return $metrics; + } + + public function export(iterable $batch): bool + { + if ($this->closed) { + return false; + } + + /** @psalm-suppress InvalidPropertyAssignmentValue */ + array_push($this->metrics, ...$batch); + + return true; + } + + public function shutdown(): bool + { + if ($this->closed) { + return false; + } + + $this->closed = true; + + return true; + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/MetricExporter/InMemoryExporterFactory.php b/vendor/open-telemetry/sdk/Metrics/MetricExporter/InMemoryExporterFactory.php new file mode 100644 index 000000000..c72c7b169 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/MetricExporter/InMemoryExporterFactory.php @@ -0,0 +1,16 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\MetricExporter; + +use OpenTelemetry\SDK\Metrics\MetricExporterFactoryInterface; +use OpenTelemetry\SDK\Metrics\MetricExporterInterface; + +class InMemoryExporterFactory implements MetricExporterFactoryInterface +{ + public function create(): MetricExporterInterface + { + return new InMemoryExporter(); + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/MetricExporter/NoopMetricExporter.php b/vendor/open-telemetry/sdk/Metrics/MetricExporter/NoopMetricExporter.php new file mode 100644 index 000000000..0cac12fae --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/MetricExporter/NoopMetricExporter.php @@ -0,0 +1,23 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\MetricExporter; + +use OpenTelemetry\SDK\Metrics\MetricExporterInterface; + +class NoopMetricExporter implements MetricExporterInterface +{ + /** + * @inheritDoc + */ + public function export(iterable $batch): bool + { + return true; + } + + public function shutdown(): bool + { + return true; + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/MetricExporter/NoopMetricExporterFactory.php b/vendor/open-telemetry/sdk/Metrics/MetricExporter/NoopMetricExporterFactory.php new file mode 100644 index 000000000..ab2ab2af3 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/MetricExporter/NoopMetricExporterFactory.php @@ -0,0 +1,16 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\MetricExporter; + +use OpenTelemetry\SDK\Metrics\MetricExporterFactoryInterface; +use OpenTelemetry\SDK\Metrics\MetricExporterInterface; + +class NoopMetricExporterFactory implements MetricExporterFactoryInterface +{ + public function create(): MetricExporterInterface + { + return new NoopMetricExporter(); + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/MetricExporter/_register.php b/vendor/open-telemetry/sdk/Metrics/MetricExporter/_register.php new file mode 100644 index 000000000..fba543d02 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/MetricExporter/_register.php @@ -0,0 +1,7 @@ +<?php + +declare(strict_types=1); + +\OpenTelemetry\SDK\Registry::registerMetricExporterFactory('memory', \OpenTelemetry\SDK\Metrics\MetricExporter\InMemoryExporterFactory::class); +\OpenTelemetry\SDK\Registry::registerMetricExporterFactory('console', \OpenTelemetry\SDK\Metrics\MetricExporter\ConsoleMetricExporterFactory::class); +\OpenTelemetry\SDK\Registry::registerMetricExporterFactory('none', \OpenTelemetry\SDK\Metrics\MetricExporter\NoopMetricExporterFactory::class); diff --git a/vendor/open-telemetry/sdk/Metrics/MetricExporterFactoryInterface.php b/vendor/open-telemetry/sdk/Metrics/MetricExporterFactoryInterface.php new file mode 100644 index 000000000..0d2541821 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/MetricExporterFactoryInterface.php @@ -0,0 +1,10 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics; + +interface MetricExporterFactoryInterface +{ + public function create(): MetricExporterInterface; +} diff --git a/vendor/open-telemetry/sdk/Metrics/MetricExporterInterface.php b/vendor/open-telemetry/sdk/Metrics/MetricExporterInterface.php new file mode 100644 index 000000000..fa47fbf9e --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/MetricExporterInterface.php @@ -0,0 +1,17 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics; + +use OpenTelemetry\SDK\Metrics\Data\Metric; + +interface MetricExporterInterface +{ + /** + * @param iterable<int, Metric> $batch + */ + public function export(iterable $batch): bool; + + public function shutdown(): bool; +} diff --git a/vendor/open-telemetry/sdk/Metrics/MetricFactory/StreamFactory.php b/vendor/open-telemetry/sdk/Metrics/MetricFactory/StreamFactory.php new file mode 100644 index 000000000..2c3af4c06 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/MetricFactory/StreamFactory.php @@ -0,0 +1,187 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\MetricFactory; + +use function array_keys; +use OpenTelemetry\SDK\Common\Instrumentation\InstrumentationScopeInterface; +use OpenTelemetry\SDK\Metrics\Aggregation\ExplicitBucketHistogramAggregation; +use OpenTelemetry\SDK\Metrics\AggregationInterface; +use OpenTelemetry\SDK\Metrics\AttributeProcessor\FilteredAttributeProcessor; +use OpenTelemetry\SDK\Metrics\AttributeProcessorInterface; +use OpenTelemetry\SDK\Metrics\Exemplar\ExemplarFilterInterface; +use OpenTelemetry\SDK\Metrics\Exemplar\ExemplarReservoirInterface; +use OpenTelemetry\SDK\Metrics\Exemplar\FilteredReservoir; +use OpenTelemetry\SDK\Metrics\Exemplar\FixedSizeReservoir; +use OpenTelemetry\SDK\Metrics\Exemplar\HistogramBucketReservoir; +use OpenTelemetry\SDK\Metrics\Instrument; +use OpenTelemetry\SDK\Metrics\MetricFactoryInterface; +use OpenTelemetry\SDK\Metrics\MetricRegistrationInterface; +use OpenTelemetry\SDK\Metrics\MetricRegistry\MetricCollectorInterface; +use OpenTelemetry\SDK\Metrics\MetricRegistry\MetricRegistryInterface; +use OpenTelemetry\SDK\Metrics\Stream\AsynchronousMetricStream; +use OpenTelemetry\SDK\Metrics\Stream\MetricAggregator; +use OpenTelemetry\SDK\Metrics\Stream\MetricAggregatorFactory; +use OpenTelemetry\SDK\Metrics\Stream\MetricStreamInterface; +use OpenTelemetry\SDK\Metrics\Stream\SynchronousMetricStream; +use OpenTelemetry\SDK\Metrics\ViewProjection; +use OpenTelemetry\SDK\Resource\ResourceInfo; +use function serialize; +use function spl_object_id; +use Throwable; + +/** + * @internal + */ +final class StreamFactory implements MetricFactoryInterface +{ + public function createAsynchronousObserver( + MetricRegistryInterface $registry, + ResourceInfo $resource, + InstrumentationScopeInterface $instrumentationScope, + Instrument $instrument, + int $timestamp, + iterable $views + ): array { + $streams = []; + $dedup = []; + foreach ($views as [$view, $registration]) { + if ($view->aggregation === null) { + continue; + } + + $dedupId = $this->streamId($view->aggregation, $view->attributeKeys); + if (($streamId = $dedup[$dedupId] ?? null) === null) { + $stream = new AsynchronousMetricStream($view->aggregation, $timestamp); + $streamId = $registry->registerAsynchronousStream($instrument, $stream, new MetricAggregatorFactory( + $this->attributeProcessor($view->attributeKeys), + $view->aggregation, + )); + + $streams[$streamId] = $stream; + $dedup[$dedupId] = $streamId; + } + + $this->registerSource( + $view, + $instrument, + $instrumentationScope, + $resource, + $streams[$streamId], + $registry, + $registration, + $streamId, + ); + } + + return array_keys($streams); + } + + public function createSynchronousWriter( + MetricRegistryInterface $registry, + ResourceInfo $resource, + InstrumentationScopeInterface $instrumentationScope, + Instrument $instrument, + int $timestamp, + iterable $views, + ?ExemplarFilterInterface $exemplarFilter = null + ): array { + $streams = []; + $dedup = []; + foreach ($views as [$view, $registration]) { + if ($view->aggregation === null) { + continue; + } + + $dedupId = $this->streamId($view->aggregation, $view->attributeKeys); + if (($streamId = $dedup[$dedupId] ?? null) === null) { + $stream = new SynchronousMetricStream($view->aggregation, $timestamp); + $streamId = $registry->registerSynchronousStream($instrument, $stream, new MetricAggregator( + $this->attributeProcessor($view->attributeKeys), + $view->aggregation, + $this->createExemplarReservoir($view->aggregation, $exemplarFilter), + )); + + $streams[$streamId] = $stream; + $dedup[$dedupId] = $streamId; + } + + $this->registerSource( + $view, + $instrument, + $instrumentationScope, + $resource, + $streams[$streamId], + $registry, + $registration, + $streamId, + ); + } + + return array_keys($streams); + } + + private function attributeProcessor( + ?array $attributeKeys + ): ?AttributeProcessorInterface { + return $attributeKeys !== null + ? new FilteredAttributeProcessor($attributeKeys) + : null; + } + + private function createExemplarReservoir( + AggregationInterface $aggregation, + ?ExemplarFilterInterface $exemplarFilter + ): ?ExemplarReservoirInterface { + if (!$exemplarFilter) { + return null; + } + + if ($aggregation instanceof ExplicitBucketHistogramAggregation && $aggregation->boundaries) { + $exemplarReservoir = new HistogramBucketReservoir($aggregation->boundaries); + } else { + $exemplarReservoir = new FixedSizeReservoir(); + } + + return new FilteredReservoir($exemplarReservoir, $exemplarFilter); + } + + private function registerSource( + ViewProjection $view, + Instrument $instrument, + InstrumentationScopeInterface $instrumentationScope, + ResourceInfo $resource, + MetricStreamInterface $stream, + MetricCollectorInterface $metricCollector, + MetricRegistrationInterface $metricRegistration, + int $streamId + ): void { + $provider = new StreamMetricSourceProvider( + $view, + $instrument, + $instrumentationScope, + $resource, + $stream, + $metricCollector, + $streamId, + ); + + $metricRegistration->register($provider, $provider); + } + + private function streamId(AggregationInterface $aggregation, ?array $attributeKeys): string + { + return $this->trySerialize($aggregation) . serialize($attributeKeys); + } + + private function trySerialize(object $object) + { + try { + return serialize($object); + } catch (Throwable $e) { + } + + return spl_object_id($object); + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/MetricFactory/StreamMetricSource.php b/vendor/open-telemetry/sdk/Metrics/MetricFactory/StreamMetricSource.php new file mode 100644 index 000000000..4939a5341 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/MetricFactory/StreamMetricSource.php @@ -0,0 +1,44 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\MetricFactory; + +use OpenTelemetry\SDK\Metrics\Data\Metric; +use OpenTelemetry\SDK\Metrics\MetricSourceInterface; + +/** + * @internal + */ +final class StreamMetricSource implements MetricSourceInterface +{ + private StreamMetricSourceProvider $provider; + private int $reader; + public function __construct(StreamMetricSourceProvider $provider, int $reader) + { + $this->provider = $provider; + $this->reader = $reader; + } + + public function collectionTimestamp(): int + { + return $this->provider->stream->timestamp(); + } + + public function collect(): Metric + { + return new Metric( + $this->provider->instrumentationLibrary, + $this->provider->resource, + $this->provider->view->name, + $this->provider->view->unit, + $this->provider->view->description, + $this->provider->stream->collect($this->reader), + ); + } + + public function __destruct() + { + $this->provider->stream->unregister($this->reader); + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/MetricFactory/StreamMetricSourceProvider.php b/vendor/open-telemetry/sdk/Metrics/MetricFactory/StreamMetricSourceProvider.php new file mode 100644 index 000000000..657c3ce62 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/MetricFactory/StreamMetricSourceProvider.php @@ -0,0 +1,98 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\MetricFactory; + +use OpenTelemetry\SDK\Common\Instrumentation\InstrumentationScopeInterface; +use OpenTelemetry\SDK\Metrics\Instrument; +use OpenTelemetry\SDK\Metrics\MetricMetadataInterface; +use OpenTelemetry\SDK\Metrics\MetricRegistry\MetricCollectorInterface; +use OpenTelemetry\SDK\Metrics\MetricSourceInterface; +use OpenTelemetry\SDK\Metrics\MetricSourceProviderInterface; +use OpenTelemetry\SDK\Metrics\Stream\MetricStreamInterface; +use OpenTelemetry\SDK\Metrics\ViewProjection; +use OpenTelemetry\SDK\Resource\ResourceInfo; + +/** + * @internal + */ +final class StreamMetricSourceProvider implements MetricSourceProviderInterface, MetricMetadataInterface +{ + /** + * @readonly + */ + public ViewProjection $view; + /** + * @readonly + */ + public Instrument $instrument; + /** + * @readonly + */ + public InstrumentationScopeInterface $instrumentationLibrary; + /** + * @readonly + */ + public ResourceInfo $resource; + /** + * @readonly + */ + public MetricStreamInterface $stream; + /** + * @readonly + */ + public MetricCollectorInterface $metricCollector; + /** + * @readonly + */ + public int $streamId; + + public function __construct( + ViewProjection $view, + Instrument $instrument, + InstrumentationScopeInterface $instrumentationLibrary, + ResourceInfo $resource, + MetricStreamInterface $stream, + MetricCollectorInterface $metricCollector, + int $streamId + ) { + $this->view = $view; + $this->instrument = $instrument; + $this->instrumentationLibrary = $instrumentationLibrary; + $this->resource = $resource; + $this->stream = $stream; + $this->metricCollector = $metricCollector; + $this->streamId = $streamId; + } + + public function create($temporality): MetricSourceInterface + { + return new StreamMetricSource($this, $this->stream->register($temporality)); + } + + public function instrumentType() + { + return $this->instrument->type; + } + + public function name(): string + { + return $this->view->name; + } + + public function unit(): ?string + { + return $this->view->unit; + } + + public function description(): ?string + { + return $this->view->description; + } + + public function temporality() + { + return $this->stream->temporality(); + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/MetricFactoryInterface.php b/vendor/open-telemetry/sdk/Metrics/MetricFactoryInterface.php new file mode 100644 index 000000000..a1e228eef --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/MetricFactoryInterface.php @@ -0,0 +1,41 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics; + +use OpenTelemetry\SDK\Common\Instrumentation\InstrumentationScopeInterface; +use OpenTelemetry\SDK\Metrics\Exemplar\ExemplarFilterInterface; +use OpenTelemetry\SDK\Metrics\MetricRegistry\MetricRegistryInterface; +use OpenTelemetry\SDK\Resource\ResourceInfo; + +/** + * @internal + */ +interface MetricFactoryInterface +{ + /** + * @param iterable<array{ViewProjection, MetricRegistrationInterface}> $views + */ + public function createAsynchronousObserver( + MetricRegistryInterface $registry, + ResourceInfo $resource, + InstrumentationScopeInterface $instrumentationScope, + Instrument $instrument, + int $timestamp, + iterable $views + ): array; + + /** + * @param iterable<array{ViewProjection, MetricRegistrationInterface}> $views + */ + public function createSynchronousWriter( + MetricRegistryInterface $registry, + ResourceInfo $resource, + InstrumentationScopeInterface $instrumentationScope, + Instrument $instrument, + int $timestamp, + iterable $views, + ?ExemplarFilterInterface $exemplarFilter = null + ): array; +} diff --git a/vendor/open-telemetry/sdk/Metrics/MetricMetadataInterface.php b/vendor/open-telemetry/sdk/Metrics/MetricMetadataInterface.php new file mode 100644 index 000000000..aa1a02d60 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/MetricMetadataInterface.php @@ -0,0 +1,28 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics; + +use OpenTelemetry\SDK\Metrics\Data\Temporality; + +interface MetricMetadataInterface +{ + /** + * @return string|InstrumentType + */ + public function instrumentType(); + + public function name(): string; + + public function unit(): ?string; + + public function description(): ?string; + + /** + * Returns the underlying temporality of this metric. + * + * @return string|Temporality internal temporality + */ + public function temporality(); +} diff --git a/vendor/open-telemetry/sdk/Metrics/MetricReader/ExportingReader.php b/vendor/open-telemetry/sdk/Metrics/MetricReader/ExportingReader.php new file mode 100644 index 000000000..3c2eff9f1 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/MetricReader/ExportingReader.php @@ -0,0 +1,156 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\MetricReader; + +use function array_keys; +use OpenTelemetry\SDK\Metrics\AggregationInterface; +use OpenTelemetry\SDK\Metrics\AggregationTemporalitySelectorInterface; +use OpenTelemetry\SDK\Metrics\DefaultAggregationProviderInterface; +use OpenTelemetry\SDK\Metrics\DefaultAggregationProviderTrait; +use OpenTelemetry\SDK\Metrics\MetricExporterInterface; +use OpenTelemetry\SDK\Metrics\MetricFactory\StreamMetricSourceProvider; +use OpenTelemetry\SDK\Metrics\MetricMetadataInterface; +use OpenTelemetry\SDK\Metrics\MetricReaderInterface; +use OpenTelemetry\SDK\Metrics\MetricRegistry\MetricCollectorInterface; +use OpenTelemetry\SDK\Metrics\MetricSourceInterface; +use OpenTelemetry\SDK\Metrics\MetricSourceProviderInterface; +use OpenTelemetry\SDK\Metrics\MetricSourceRegistryInterface; +use OpenTelemetry\SDK\Metrics\PushMetricExporterInterface; +use OpenTelemetry\SDK\Metrics\StalenessHandlerInterface; +use function spl_object_id; + +final class ExportingReader implements MetricReaderInterface, MetricSourceRegistryInterface, DefaultAggregationProviderInterface +{ + use DefaultAggregationProviderTrait { defaultAggregation as private _defaultAggregation; } + + private MetricExporterInterface $exporter; + /** @var array<int, MetricSourceInterface> */ + private array $sources = []; + + /** @var array<int, MetricCollectorInterface> */ + private array $registries = []; + /** @var array<int, array<int, int>> */ + private array $streamIds = []; + + private bool $closed = false; + + public function __construct(MetricExporterInterface $exporter) + { + $this->exporter = $exporter; + } + + public function defaultAggregation($instrumentType): ?AggregationInterface + { + if ($this->exporter instanceof DefaultAggregationProviderInterface) { + return $this->exporter->defaultAggregation($instrumentType); + } + + return $this->_defaultAggregation($instrumentType); + } + + public function add(MetricSourceProviderInterface $provider, MetricMetadataInterface $metadata, StalenessHandlerInterface $stalenessHandler): void + { + if ($this->closed) { + return; + } + if (!$this->exporter instanceof AggregationTemporalitySelectorInterface) { + return; + } + if (!$temporality = $this->exporter->temporality($metadata)) { + return; + } + + $source = $provider->create($temporality); + $sourceId = spl_object_id($source); + + $this->sources[$sourceId] = $source; + $stalenessHandler->onStale(function () use ($sourceId): void { + unset($this->sources[$sourceId]); + }); + + if (!$provider instanceof StreamMetricSourceProvider) { + return; + } + + $streamId = $provider->streamId; + $registry = $provider->metricCollector; + $registryId = spl_object_id($registry); + + $this->registries[$registryId] = $registry; + $this->streamIds[$registryId][$streamId] ??= 0; + $this->streamIds[$registryId][$streamId]++; + + $stalenessHandler->onStale(function () use ($streamId, $registryId): void { + if (!--$this->streamIds[$registryId][$streamId]) { + unset($this->streamIds[$registryId][$streamId]); + if (!$this->streamIds[$registryId]) { + unset( + $this->registries[$registryId], + $this->streamIds[$registryId], + ); + } + } + }); + } + + private function doCollect(): bool + { + foreach ($this->registries as $registryId => $registry) { + $streamIds = $this->streamIds[$registryId] ?? []; + $registry->collectAndPush(array_keys($streamIds)); + } + + $metrics = []; + foreach ($this->sources as $source) { + $metrics[] = $source->collect(); + } + + if ($metrics === []) { + return true; + } + + return $this->exporter->export($metrics); + } + + public function collect(): bool + { + if ($this->closed) { + return false; + } + + return $this->doCollect(); + } + + public function shutdown(): bool + { + if ($this->closed) { + return false; + } + + $this->closed = true; + + $collect = $this->doCollect(); + $shutdown = $this->exporter->shutdown(); + + $this->sources = []; + + return $collect && $shutdown; + } + + public function forceFlush(): bool + { + if ($this->closed) { + return false; + } + if ($this->exporter instanceof PushMetricExporterInterface) { + $collect = $this->doCollect(); + $forceFlush = $this->exporter->forceFlush(); + + return $collect && $forceFlush; + } + + return true; + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/MetricReaderInterface.php b/vendor/open-telemetry/sdk/Metrics/MetricReaderInterface.php new file mode 100644 index 000000000..f5900eef5 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/MetricReaderInterface.php @@ -0,0 +1,14 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics; + +interface MetricReaderInterface +{ + public function collect(): bool; + + public function shutdown(): bool; + + public function forceFlush(): bool; +} diff --git a/vendor/open-telemetry/sdk/Metrics/MetricRegistration/MultiRegistryRegistration.php b/vendor/open-telemetry/sdk/Metrics/MetricRegistration/MultiRegistryRegistration.php new file mode 100644 index 000000000..2472c096f --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/MetricRegistration/MultiRegistryRegistration.php @@ -0,0 +1,36 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\MetricRegistration; + +use OpenTelemetry\SDK\Metrics\MetricMetadataInterface; +use OpenTelemetry\SDK\Metrics\MetricRegistrationInterface; +use OpenTelemetry\SDK\Metrics\MetricSourceProviderInterface; +use OpenTelemetry\SDK\Metrics\MetricSourceRegistryInterface; +use OpenTelemetry\SDK\Metrics\StalenessHandlerInterface; + +/** + * @internal + */ +final class MultiRegistryRegistration implements MetricRegistrationInterface +{ + private iterable $registries; + private StalenessHandlerInterface $stalenessHandler; + + /** + * @param iterable<MetricSourceRegistryInterface> $registries + */ + public function __construct(iterable $registries, StalenessHandlerInterface $stalenessHandler) + { + $this->registries = $registries; + $this->stalenessHandler = $stalenessHandler; + } + + public function register(MetricSourceProviderInterface $provider, MetricMetadataInterface $metadata): void + { + foreach ($this->registries as $registry) { + $registry->add($provider, $metadata, $this->stalenessHandler); + } + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/MetricRegistration/RegistryRegistration.php b/vendor/open-telemetry/sdk/Metrics/MetricRegistration/RegistryRegistration.php new file mode 100644 index 000000000..3c1108902 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/MetricRegistration/RegistryRegistration.php @@ -0,0 +1,31 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\MetricRegistration; + +use OpenTelemetry\SDK\Metrics\MetricMetadataInterface; +use OpenTelemetry\SDK\Metrics\MetricRegistrationInterface; +use OpenTelemetry\SDK\Metrics\MetricSourceProviderInterface; +use OpenTelemetry\SDK\Metrics\MetricSourceRegistryInterface; +use OpenTelemetry\SDK\Metrics\StalenessHandlerInterface; + +/** + * @internal + */ +final class RegistryRegistration implements MetricRegistrationInterface +{ + private MetricSourceRegistryInterface $registry; + private StalenessHandlerInterface $stalenessHandler; + + public function __construct(MetricSourceRegistryInterface $registry, StalenessHandlerInterface $stalenessHandler) + { + $this->registry = $registry; + $this->stalenessHandler = $stalenessHandler; + } + + public function register(MetricSourceProviderInterface $provider, MetricMetadataInterface $metadata): void + { + $this->registry->add($provider, $metadata, $this->stalenessHandler); + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/MetricRegistrationInterface.php b/vendor/open-telemetry/sdk/Metrics/MetricRegistrationInterface.php new file mode 100644 index 000000000..b0cc2484e --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/MetricRegistrationInterface.php @@ -0,0 +1,13 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics; + +/** + * @internal + */ +interface MetricRegistrationInterface +{ + public function register(MetricSourceProviderInterface $provider, MetricMetadataInterface $metadata): void; +} diff --git a/vendor/open-telemetry/sdk/Metrics/MetricRegistry/MetricCollectorInterface.php b/vendor/open-telemetry/sdk/Metrics/MetricRegistry/MetricCollectorInterface.php new file mode 100644 index 000000000..4e8e91ced --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/MetricRegistry/MetricCollectorInterface.php @@ -0,0 +1,13 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\MetricRegistry; + +/** + * @internal + */ +interface MetricCollectorInterface +{ + public function collectAndPush(iterable $streamIds): void; +} diff --git a/vendor/open-telemetry/sdk/Metrics/MetricRegistry/MetricRegistry.php b/vendor/open-telemetry/sdk/Metrics/MetricRegistry/MetricRegistry.php new file mode 100644 index 000000000..9a18d2a84 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/MetricRegistry/MetricRegistry.php @@ -0,0 +1,184 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\MetricRegistry; + +use function array_key_last; +use Closure; +use OpenTelemetry\Context\Context; +use OpenTelemetry\Context\ContextStorageInterface; +use OpenTelemetry\SDK\Common\Attribute\AttributesFactoryInterface; +use OpenTelemetry\SDK\Common\Time\ClockInterface; +use OpenTelemetry\SDK\Metrics\Instrument; +use OpenTelemetry\SDK\Metrics\Stream\MetricAggregatorFactoryInterface; +use OpenTelemetry\SDK\Metrics\Stream\MetricAggregatorInterface; +use OpenTelemetry\SDK\Metrics\Stream\MetricStreamInterface; +use function spl_object_id; + +/** + * @internal + */ +final class MetricRegistry implements MetricRegistryInterface, MetricWriterInterface +{ + private ?ContextStorageInterface $contextStorage; + private AttributesFactoryInterface $attributesFactory; + private ClockInterface $clock; + + /** @var array<int, MetricStreamInterface> */ + private array $streams = []; + /** @var array<int, MetricAggregatorInterface> */ + private array $synchronousAggregators = []; + /** @var array<int, MetricAggregatorFactoryInterface> */ + private array $asynchronousAggregatorFactories = []; + + /** @var array<int, array<int, int>> */ + private array $instrumentToStreams = []; + /** @var array<int, int> */ + private array $streamToInstrument = []; + /** @var array<int, array<int, int>> */ + private array $instrumentToCallbacks = []; + /** @var array<int, Closure> */ + private array $asynchronousCallbacks = []; + /** @var array<int, list<int>> */ + private array $asynchronousCallbackArguments = []; + + public function __construct( + ?ContextStorageInterface $contextStorage, + AttributesFactoryInterface $attributesFactory, + ClockInterface $clock + ) { + $this->contextStorage = $contextStorage; + $this->attributesFactory = $attributesFactory; + $this->clock = $clock; + } + + public function registerSynchronousStream(Instrument $instrument, MetricStreamInterface $stream, MetricAggregatorInterface $aggregator): int + { + $this->streams[] = $stream; + $streamId = array_key_last($this->streams); + $instrumentId = spl_object_id($instrument); + + $this->synchronousAggregators[$streamId] = $aggregator; + $this->instrumentToStreams[$instrumentId][$streamId] = $streamId; + $this->streamToInstrument[$streamId] = $instrumentId; + + return $streamId; + } + + public function registerAsynchronousStream(Instrument $instrument, MetricStreamInterface $stream, MetricAggregatorFactoryInterface $aggregatorFactory): int + { + $this->streams[] = $stream; + $streamId = array_key_last($this->streams); + $instrumentId = spl_object_id($instrument); + + $this->asynchronousAggregatorFactories[$streamId] = $aggregatorFactory; + $this->instrumentToStreams[$instrumentId][$streamId] = $streamId; + $this->streamToInstrument[$streamId] = $instrumentId; + + return $streamId; + } + + public function unregisterStream(int $streamId): void + { + $instrumentId = $this->streamToInstrument[$streamId]; + unset( + $this->streams[$streamId], + $this->synchronousAggregators[$streamId], + $this->asynchronousAggregatorFactories[$streamId], + $this->instrumentToStreams[$instrumentId][$streamId], + $this->streamToInstrument[$streamId], + ); + if (!$this->instrumentToStreams[$instrumentId]) { + unset($this->instrumentToStreams[$instrumentId]); + } + } + + public function record(Instrument $instrument, $value, iterable $attributes = [], $context = null): void + { + $context = Context::resolve($context, $this->contextStorage); + $attributes = $this->attributesFactory->builder($attributes)->build(); + $timestamp = $this->clock->now(); + $instrumentId = spl_object_id($instrument); + foreach ($this->instrumentToStreams[$instrumentId] ?? [] as $streamId) { + if ($aggregator = $this->synchronousAggregators[$streamId] ?? null) { + $aggregator->record($value, $attributes, $context, $timestamp); + } + } + } + + public function registerCallback(Closure $callback, Instrument $instrument, Instrument ...$instruments): int + { + $callbackId = array_key_last($this->asynchronousCallbacks) + 1; + $this->asynchronousCallbacks[$callbackId] = $callback; + + $instrumentId = spl_object_id($instrument); + $this->asynchronousCallbackArguments[$callbackId] = [$instrumentId]; + $this->instrumentToCallbacks[$instrumentId][$callbackId] = $callbackId; + foreach ($instruments as $instrument) { + $instrumentId = spl_object_id($instrument); + $this->asynchronousCallbackArguments[$callbackId][] = $instrumentId; + $this->instrumentToCallbacks[$instrumentId][$callbackId] = $callbackId; + } + + return $callbackId; + } + + public function unregisterCallback(int $callbackId): void + { + $instrumentIds = $this->asynchronousCallbackArguments[$callbackId]; + unset( + $this->asynchronousCallbacks[$callbackId], + $this->asynchronousCallbackArguments[$callbackId], + ); + foreach ($instrumentIds as $instrumentId) { + unset($this->instrumentToCallbacks[$instrumentId][$callbackId]); + if (!$this->instrumentToCallbacks[$instrumentId]) { + unset($this->instrumentToCallbacks[$instrumentId]); + } + } + } + + public function collectAndPush(iterable $streamIds): void + { + $timestamp = $this->clock->now(); + $aggregators = []; + $observers = []; + $callbackIds = []; + foreach ($streamIds as $streamId) { + if (!$aggregator = $this->synchronousAggregators[$streamId] ?? null) { + $aggregator = $this->asynchronousAggregatorFactories[$streamId]->create(); + + $instrumentId = $this->streamToInstrument[$streamId]; + $observers[$instrumentId] ??= new MultiObserver($this->attributesFactory, $timestamp); + $observers[$instrumentId]->writers[] = $aggregator; + foreach ($this->instrumentToCallbacks[$instrumentId] ?? [] as $callbackId) { + $callbackIds[$callbackId] = $callbackId; + } + } + + $aggregators[$streamId] = $aggregator; + } + + $noopObserver = new NoopObserver(); + $callbacks = []; + foreach ($callbackIds as $callbackId) { + $args = []; + foreach ($this->asynchronousCallbackArguments[$callbackId] as $instrumentId) { + $args[] = $observers[$instrumentId] ?? $noopObserver; + } + $callback = $this->asynchronousCallbacks[$callbackId]; + $callbacks[] = static fn () => $callback(...$args); + } + foreach ($callbacks as $callback) { + $callback(); + } + + $timestamp = $this->clock->now(); + foreach ($aggregators as $streamId => $aggregator) { + if ($stream = $this->streams[$streamId] ?? null) { + $stream->push($aggregator->collect($timestamp)); + } + } + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/MetricRegistry/MetricRegistryInterface.php b/vendor/open-telemetry/sdk/Metrics/MetricRegistry/MetricRegistryInterface.php new file mode 100644 index 000000000..e86731138 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/MetricRegistry/MetricRegistryInterface.php @@ -0,0 +1,22 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\MetricRegistry; + +use OpenTelemetry\SDK\Metrics\Instrument; +use OpenTelemetry\SDK\Metrics\Stream\MetricAggregatorFactoryInterface; +use OpenTelemetry\SDK\Metrics\Stream\MetricAggregatorInterface; +use OpenTelemetry\SDK\Metrics\Stream\MetricStreamInterface; + +/** + * @internal + */ +interface MetricRegistryInterface extends MetricCollectorInterface +{ + public function registerSynchronousStream(Instrument $instrument, MetricStreamInterface $stream, MetricAggregatorInterface $aggregator): int; + + public function registerAsynchronousStream(Instrument $instrument, MetricStreamInterface $stream, MetricAggregatorFactoryInterface $aggregatorFactory): int; + + public function unregisterStream(int $streamId): void; +} diff --git a/vendor/open-telemetry/sdk/Metrics/MetricRegistry/MetricWriterInterface.php b/vendor/open-telemetry/sdk/Metrics/MetricRegistry/MetricWriterInterface.php new file mode 100644 index 000000000..e5ff7eb5c --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/MetricRegistry/MetricWriterInterface.php @@ -0,0 +1,20 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\MetricRegistry; + +use Closure; +use OpenTelemetry\SDK\Metrics\Instrument; + +/** + * @internal + */ +interface MetricWriterInterface +{ + public function record(Instrument $instrument, $value, iterable $attributes = [], $context = null): void; + + public function registerCallback(Closure $callback, Instrument $instrument, Instrument ...$instruments): int; + + public function unregisterCallback(int $callbackId): void; +} diff --git a/vendor/open-telemetry/sdk/Metrics/MetricRegistry/MultiObserver.php b/vendor/open-telemetry/sdk/Metrics/MetricRegistry/MultiObserver.php new file mode 100644 index 000000000..f36f74a2a --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/MetricRegistry/MultiObserver.php @@ -0,0 +1,37 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\MetricRegistry; + +use OpenTelemetry\API\Metrics\ObserverInterface; +use OpenTelemetry\Context\Context; +use OpenTelemetry\SDK\Common\Attribute\AttributesFactoryInterface; +use OpenTelemetry\SDK\Metrics\Stream\WritableMetricStreamInterface; + +/** + * @internal + */ +final class MultiObserver implements ObserverInterface +{ + private AttributesFactoryInterface $attributesFactory; + private int $timestamp; + + /** @var list<WritableMetricStreamInterface> */ + public array $writers = []; + + public function __construct(AttributesFactoryInterface $attributesFactory, int $timestamp) + { + $this->attributesFactory = $attributesFactory; + $this->timestamp = $timestamp; + } + + public function observe($amount, iterable $attributes = []): void + { + $context = Context::getRoot(); + $attributes = $this->attributesFactory->builder($attributes)->build(); + foreach ($this->writers as $writer) { + $writer->record($amount, $attributes, $context, $this->timestamp); + } + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/MetricRegistry/NoopObserver.php b/vendor/open-telemetry/sdk/Metrics/MetricRegistry/NoopObserver.php new file mode 100644 index 000000000..efbd94dac --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/MetricRegistry/NoopObserver.php @@ -0,0 +1,18 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\MetricRegistry; + +use OpenTelemetry\API\Metrics\ObserverInterface; + +/** + * @internal + */ +final class NoopObserver implements ObserverInterface +{ + public function observe($amount, iterable $attributes = []): void + { + // no-op + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/MetricSourceInterface.php b/vendor/open-telemetry/sdk/Metrics/MetricSourceInterface.php new file mode 100644 index 000000000..5f00a0717 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/MetricSourceInterface.php @@ -0,0 +1,24 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics; + +use OpenTelemetry\SDK\Metrics\Data\Metric; + +interface MetricSourceInterface +{ + /** + * Returns the last metric collection timestamp. + * + * @return int last collection timestamp + */ + public function collectionTimestamp(): int; + + /** + * Collects metric data from the underlying provider. + * + * @return Metric collected metric + */ + public function collect(): Metric; +} diff --git a/vendor/open-telemetry/sdk/Metrics/MetricSourceProviderInterface.php b/vendor/open-telemetry/sdk/Metrics/MetricSourceProviderInterface.php new file mode 100644 index 000000000..f8b6ea438 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/MetricSourceProviderInterface.php @@ -0,0 +1,15 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics; + +use OpenTelemetry\SDK\Metrics\Data\Temporality; + +interface MetricSourceProviderInterface +{ + /** + * @param string|Temporality $temporality + */ + public function create($temporality): MetricSourceInterface; +} diff --git a/vendor/open-telemetry/sdk/Metrics/MetricSourceRegistryInterface.php b/vendor/open-telemetry/sdk/Metrics/MetricSourceRegistryInterface.php new file mode 100644 index 000000000..dd7ff53ac --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/MetricSourceRegistryInterface.php @@ -0,0 +1,10 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics; + +interface MetricSourceRegistryInterface +{ + public function add(MetricSourceProviderInterface $provider, MetricMetadataInterface $metadata, StalenessHandlerInterface $stalenessHandler): void; +} diff --git a/vendor/open-telemetry/sdk/Metrics/NoopMeterProvider.php b/vendor/open-telemetry/sdk/Metrics/NoopMeterProvider.php new file mode 100644 index 000000000..2efb484d3 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/NoopMeterProvider.php @@ -0,0 +1,26 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics; + +use OpenTelemetry\API\Metrics\MeterInterface; +use OpenTelemetry\API\Metrics\Noop\NoopMeter; + +class NoopMeterProvider implements MeterProviderInterface +{ + public function shutdown(): bool + { + return true; + } + + public function forceFlush(): bool + { + return true; + } + + public function getMeter(string $name, ?string $version = null, ?string $schemaUrl = null, iterable $attributes = []): MeterInterface + { + return new NoopMeter(); + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/ObservableCallback.php b/vendor/open-telemetry/sdk/Metrics/ObservableCallback.php new file mode 100644 index 000000000..ffe5ead87 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/ObservableCallback.php @@ -0,0 +1,58 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics; + +use OpenTelemetry\API\Metrics\ObservableCallbackInterface; +use OpenTelemetry\SDK\Metrics\MetricRegistry\MetricWriterInterface; + +/** + * @internal + */ +final class ObservableCallback implements ObservableCallbackInterface +{ + private MetricWriterInterface $writer; + private ReferenceCounterInterface $referenceCounter; + private ?int $callbackId; + private ?ObservableCallbackDestructor $callbackDestructor; + /** @phpstan-ignore-next-line */ + private ?object $target; + + public function __construct(MetricWriterInterface $writer, ReferenceCounterInterface $referenceCounter, int $callbackId, ?ObservableCallbackDestructor $callbackDestructor, ?object $target) + { + $this->writer = $writer; + $this->referenceCounter = $referenceCounter; + $this->callbackId = $callbackId; + $this->callbackDestructor = $callbackDestructor; + $this->target = $target; + } + + public function detach(): void + { + if ($this->callbackId === null) { + return; + } + + $this->writer->unregisterCallback($this->callbackId); + $this->referenceCounter->release(); + if ($this->callbackDestructor !== null) { + unset($this->callbackDestructor->callbackIds[$this->callbackId]); + } + + $this->callbackId = null; + } + + public function __destruct() + { + if ($this->callbackDestructor !== null) { + return; + } + if ($this->callbackId === null) { + return; + } + + $this->referenceCounter->acquire(true); + $this->referenceCounter->release(); + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/ObservableCallbackDestructor.php b/vendor/open-telemetry/sdk/Metrics/ObservableCallbackDestructor.php new file mode 100644 index 000000000..0dfea3907 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/ObservableCallbackDestructor.php @@ -0,0 +1,32 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics; + +use OpenTelemetry\SDK\Metrics\MetricRegistry\MetricWriterInterface; + +/** + * @internal + */ +final class ObservableCallbackDestructor +{ + /** @var array<int, int> */ + public array $callbackIds = []; + private MetricWriterInterface $writer; + private ReferenceCounterInterface $referenceCounter; + + public function __construct(MetricWriterInterface $writer, ReferenceCounterInterface $referenceCounter) + { + $this->writer = $writer; + $this->referenceCounter = $referenceCounter; + } + + public function __destruct() + { + foreach ($this->callbackIds as $callbackId) { + $this->writer->unregisterCallback($callbackId); + $this->referenceCounter->release(); + } + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/ObservableCounter.php b/vendor/open-telemetry/sdk/Metrics/ObservableCounter.php new file mode 100644 index 000000000..99ae43eee --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/ObservableCounter.php @@ -0,0 +1,15 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics; + +use OpenTelemetry\API\Metrics\ObservableCounterInterface; + +/** + * @internal + */ +final class ObservableCounter implements ObservableCounterInterface +{ + use ObservableInstrumentTrait; +} diff --git a/vendor/open-telemetry/sdk/Metrics/ObservableGauge.php b/vendor/open-telemetry/sdk/Metrics/ObservableGauge.php new file mode 100644 index 000000000..88c1a546c --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/ObservableGauge.php @@ -0,0 +1,15 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics; + +use OpenTelemetry\API\Metrics\ObservableGaugeInterface; + +/** + * @internal + */ +final class ObservableGauge implements ObservableGaugeInterface +{ + use ObservableInstrumentTrait; +} diff --git a/vendor/open-telemetry/sdk/Metrics/ObservableInstrumentTrait.php b/vendor/open-telemetry/sdk/Metrics/ObservableInstrumentTrait.php new file mode 100644 index 000000000..b7fdcf5f8 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/ObservableInstrumentTrait.php @@ -0,0 +1,61 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics; + +use ArrayAccess; +use OpenTelemetry\API\Metrics\ObservableCallbackInterface; +use OpenTelemetry\API\Metrics\ObserverInterface; +use function OpenTelemetry\SDK\Common\Util\closure; +use function OpenTelemetry\SDK\Common\Util\weaken; +use OpenTelemetry\SDK\Metrics\MetricRegistry\MetricWriterInterface; + +/** + * @internal + */ +trait ObservableInstrumentTrait +{ + private MetricWriterInterface $writer; + private Instrument $instrument; + private ReferenceCounterInterface $referenceCounter; + private ArrayAccess $destructors; + + public function __construct( + MetricWriterInterface $writer, + Instrument $instrument, + ReferenceCounterInterface $referenceCounter, + ArrayAccess $destructors + ) { + $this->writer = $writer; + $this->instrument = $instrument; + $this->referenceCounter = $referenceCounter; + $this->destructors = $destructors; + + $this->referenceCounter->acquire(); + } + + public function __destruct() + { + $this->referenceCounter->release(); + } + + /** + * @param callable(ObserverInterface): void $callback + */ + public function observe(callable $callback): ObservableCallbackInterface + { + $callback = weaken(closure($callback), $target); + + $callbackId = $this->writer->registerCallback($callback, $this->instrument); + $this->referenceCounter->acquire(); + + $destructor = null; + if ($target) { + $destructor = $this->destructors[$target] ??= new ObservableCallbackDestructor($this->writer, $this->referenceCounter); + $destructor->callbackIds[$callbackId] = $callbackId; + } + + return new ObservableCallback($this->writer, $this->referenceCounter, $callbackId, $destructor, $target); + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/ObservableUpDownCounter.php b/vendor/open-telemetry/sdk/Metrics/ObservableUpDownCounter.php new file mode 100644 index 000000000..8d21be734 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/ObservableUpDownCounter.php @@ -0,0 +1,15 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics; + +use OpenTelemetry\API\Metrics\ObservableUpDownCounterInterface; + +/** + * @internal + */ +final class ObservableUpDownCounter implements ObservableUpDownCounterInterface +{ + use ObservableInstrumentTrait; +} diff --git a/vendor/open-telemetry/sdk/Metrics/PushMetricExporterInterface.php b/vendor/open-telemetry/sdk/Metrics/PushMetricExporterInterface.php new file mode 100644 index 000000000..d24b0e396 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/PushMetricExporterInterface.php @@ -0,0 +1,12 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics; + +use OpenTelemetry\SDK\Metrics; + +interface PushMetricExporterInterface extends Metrics\MetricExporterInterface +{ + public function forceFlush(): bool; +} diff --git a/vendor/open-telemetry/sdk/Metrics/ReferenceCounterInterface.php b/vendor/open-telemetry/sdk/Metrics/ReferenceCounterInterface.php new file mode 100644 index 000000000..f7e70b644 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/ReferenceCounterInterface.php @@ -0,0 +1,15 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics; + +/** + * @internal + */ +interface ReferenceCounterInterface +{ + public function acquire(bool $persistent = false): void; + + public function release(): void; +} diff --git a/vendor/open-telemetry/sdk/Metrics/StalenessHandler/DelayedStalenessHandler.php b/vendor/open-telemetry/sdk/Metrics/StalenessHandler/DelayedStalenessHandler.php new file mode 100644 index 000000000..66b271018 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/StalenessHandler/DelayedStalenessHandler.php @@ -0,0 +1,71 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\StalenessHandler; + +use function assert; +use Closure; +use OpenTelemetry\SDK\Metrics\ReferenceCounterInterface; +use OpenTelemetry\SDK\Metrics\StalenessHandlerInterface; + +/** + * @internal + */ +final class DelayedStalenessHandler implements StalenessHandlerInterface, ReferenceCounterInterface +{ + private Closure $stale; + private Closure $freshen; + + /** @var Closure[]|null */ + private ?array $onStale = []; + private int $count = 0; + + public function __construct(Closure $stale, Closure $freshen) + { + $this->stale = $stale; + $this->freshen = $freshen; + } + + public function acquire(bool $persistent = false): void + { + if ($this->count === 0) { + ($this->freshen)($this); + } + + $this->count++; + + if ($persistent) { + $this->onStale = null; + } + } + + public function release(): void + { + if (--$this->count || $this->onStale === null) { + return; + } + + ($this->stale)($this); + } + + public function onStale(Closure $callback): void + { + if ($this->onStale === null) { + return; + } + + $this->onStale[] = $callback; + } + + public function triggerStale(): void + { + assert($this->onStale !== null); + + $callbacks = $this->onStale; + $this->onStale = []; + foreach ($callbacks as $callback) { + $callback(); + } + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/StalenessHandler/DelayedStalenessHandlerFactory.php b/vendor/open-telemetry/sdk/Metrics/StalenessHandler/DelayedStalenessHandlerFactory.php new file mode 100644 index 000000000..0d719c74f --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/StalenessHandler/DelayedStalenessHandlerFactory.php @@ -0,0 +1,64 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\StalenessHandler; + +use ArrayAccess; +use Closure; +use OpenTelemetry\SDK\Common\Time\ClockInterface; +use OpenTelemetry\SDK\Common\Util\WeakMap; +use OpenTelemetry\SDK\Metrics\StalenessHandlerFactoryInterface; +use OpenTelemetry\SDK\Metrics\StalenessHandlerInterface; +use Traversable; + +final class DelayedStalenessHandlerFactory implements StalenessHandlerFactoryInterface +{ + private ClockInterface $clock; + private int $nanoDelay; + + private Closure $stale; + private Closure $freshen; + + /** @var ArrayAccess<DelayedStalenessHandler, int>&Traversable<DelayedStalenessHandler, int> */ + private $staleHandlers; + + /** + * @param float $delay delay in seconds + */ + public function __construct(ClockInterface $clock, float $delay) + { + $this->clock = $clock; + $this->nanoDelay = (int) ($delay * 1e9); + + $this->stale = function (DelayedStalenessHandler $handler): void { + $this->staleHandlers[$handler] = $this->clock->now(); + }; + $this->freshen = function (DelayedStalenessHandler $handler): void { + unset($this->staleHandlers[$handler]); + }; + + $this->staleHandlers = WeakMap::create(); + } + + public function create(): StalenessHandlerInterface + { + $this->triggerStaleHandlers(); + + return new DelayedStalenessHandler($this->stale, $this->freshen); + } + + private function triggerStaleHandlers(): void + { + $expired = $this->clock->now() - $this->nanoDelay; + foreach ($this->staleHandlers as $handler => $timestamp) { + if ($timestamp > $expired) { + break; + } + + /** @var DelayedStalenessHandler $handler */ + unset($this->staleHandlers[$handler]); + $handler->triggerStale(); + } + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/StalenessHandler/ImmediateStalenessHandler.php b/vendor/open-telemetry/sdk/Metrics/StalenessHandler/ImmediateStalenessHandler.php new file mode 100644 index 000000000..a5b32d5c4 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/StalenessHandler/ImmediateStalenessHandler.php @@ -0,0 +1,50 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\StalenessHandler; + +use Closure; +use OpenTelemetry\SDK\Metrics\ReferenceCounterInterface; +use OpenTelemetry\SDK\Metrics\StalenessHandlerInterface; + +/** + * @internal + */ +final class ImmediateStalenessHandler implements StalenessHandlerInterface, ReferenceCounterInterface +{ + /** @var Closure[]|null */ + private ?array $onStale = []; + private int $count = 0; + + public function acquire(bool $persistent = false): void + { + $this->count++; + + if ($persistent) { + $this->onStale = null; + } + } + + public function release(): void + { + if (--$this->count !== 0 || !$this->onStale) { + return; + } + + $callbacks = $this->onStale; + $this->onStale = []; + foreach ($callbacks as $callback) { + $callback(); + } + } + + public function onStale(Closure $callback): void + { + if ($this->onStale === null) { + return; + } + + $this->onStale[] = $callback; + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/StalenessHandler/ImmediateStalenessHandlerFactory.php b/vendor/open-telemetry/sdk/Metrics/StalenessHandler/ImmediateStalenessHandlerFactory.php new file mode 100644 index 000000000..899615dea --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/StalenessHandler/ImmediateStalenessHandlerFactory.php @@ -0,0 +1,16 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\StalenessHandler; + +use OpenTelemetry\SDK\Metrics\StalenessHandlerFactoryInterface; +use OpenTelemetry\SDK\Metrics\StalenessHandlerInterface; + +final class ImmediateStalenessHandlerFactory implements StalenessHandlerFactoryInterface +{ + public function create(): StalenessHandlerInterface + { + return new ImmediateStalenessHandler(); + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/StalenessHandler/NoopStalenessHandler.php b/vendor/open-telemetry/sdk/Metrics/StalenessHandler/NoopStalenessHandler.php new file mode 100644 index 000000000..00d432b6b --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/StalenessHandler/NoopStalenessHandler.php @@ -0,0 +1,30 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\StalenessHandler; + +use Closure; +use OpenTelemetry\SDK\Metrics\ReferenceCounterInterface; +use OpenTelemetry\SDK\Metrics\StalenessHandlerInterface; + +/** + * @internal + */ +final class NoopStalenessHandler implements StalenessHandlerInterface, ReferenceCounterInterface +{ + public function acquire(bool $persistent = false): void + { + // no-op + } + + public function release(): void + { + // no-op + } + + public function onStale(Closure $callback): void + { + // no-op + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/StalenessHandler/NoopStalenessHandlerFactory.php b/vendor/open-telemetry/sdk/Metrics/StalenessHandler/NoopStalenessHandlerFactory.php new file mode 100644 index 000000000..07f34e3b0 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/StalenessHandler/NoopStalenessHandlerFactory.php @@ -0,0 +1,18 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\StalenessHandler; + +use OpenTelemetry\SDK\Metrics\StalenessHandlerFactoryInterface; +use OpenTelemetry\SDK\Metrics\StalenessHandlerInterface; + +final class NoopStalenessHandlerFactory implements StalenessHandlerFactoryInterface +{ + public function create(): StalenessHandlerInterface + { + static $instance; + + return $instance ??= new NoopStalenessHandler(); + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/StalenessHandlerFactoryInterface.php b/vendor/open-telemetry/sdk/Metrics/StalenessHandlerFactoryInterface.php new file mode 100644 index 000000000..e22385420 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/StalenessHandlerFactoryInterface.php @@ -0,0 +1,13 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics; + +interface StalenessHandlerFactoryInterface +{ + /** + * @return StalenessHandlerInterface&ReferenceCounterInterface + */ + public function create(): StalenessHandlerInterface; +} diff --git a/vendor/open-telemetry/sdk/Metrics/StalenessHandlerInterface.php b/vendor/open-telemetry/sdk/Metrics/StalenessHandlerInterface.php new file mode 100644 index 000000000..c85d86f8e --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/StalenessHandlerInterface.php @@ -0,0 +1,12 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics; + +use Closure; + +interface StalenessHandlerInterface +{ + public function onStale(Closure $callback): void; +} diff --git a/vendor/open-telemetry/sdk/Metrics/Stream/AsynchronousMetricStream.php b/vendor/open-telemetry/sdk/Metrics/Stream/AsynchronousMetricStream.php new file mode 100644 index 000000000..cb32f94df --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/Stream/AsynchronousMetricStream.php @@ -0,0 +1,111 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\Stream; + +use function array_search; +use function count; +use OpenTelemetry\SDK\Metrics\AggregationInterface; +use OpenTelemetry\SDK\Metrics\Data\DataInterface; +use OpenTelemetry\SDK\Metrics\Data\Exemplar; +use OpenTelemetry\SDK\Metrics\Data\Temporality; + +/** + * @internal + */ +final class AsynchronousMetricStream implements MetricStreamInterface +{ + private AggregationInterface $aggregation; + + private int $startTimestamp; + private Metric $metric; + + /** @var array<int, Metric|null> */ + private array $lastReads = []; + + public function __construct(AggregationInterface $aggregation, int $startTimestamp) + { + $this->aggregation = $aggregation; + $this->startTimestamp = $startTimestamp; + $this->metric = new Metric([], [], $startTimestamp); + } + + public function temporality() + { + return Temporality::CUMULATIVE; + } + + public function timestamp(): int + { + return $this->metric->timestamp; + } + + public function push(Metric $metric): void + { + $this->metric = $metric; + } + + public function register($temporality): int + { + if ($temporality === Temporality::CUMULATIVE) { + return -1; + } + + if (($reader = array_search(null, $this->lastReads, true)) === false) { + $reader = count($this->lastReads); + } + + $this->lastReads[$reader] = $this->metric; + + return $reader; + } + + public function unregister(int $reader): void + { + if (!isset($this->lastReads[$reader])) { + return; + } + + $this->lastReads[$reader] = null; + } + + public function collect(int $reader): DataInterface + { + $metric = $this->metric; + + if (($lastRead = $this->lastReads[$reader] ?? null) === null) { + $temporality = Temporality::CUMULATIVE; + $startTimestamp = $this->startTimestamp; + } else { + $temporality = Temporality::DELTA; + $startTimestamp = $lastRead->timestamp; + + $this->lastReads[$reader] = $metric; + $metric = $this->diff($lastRead, $metric); + } + + return $this->aggregation->toData( + $metric->attributes, + $metric->summaries, + Exemplar::groupByIndex($metric->exemplars), + $startTimestamp, + $metric->timestamp, + $temporality, + ); + } + + private function diff(Metric $lastRead, Metric $metric): Metric + { + $diff = clone $metric; + foreach ($metric->summaries as $k => $summary) { + if (!isset($lastRead->summaries[$k])) { + continue; + } + + $diff->summaries[$k] = $this->aggregation->diff($lastRead->summaries[$k], $summary); + } + + return $diff; + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/Stream/Delta.php b/vendor/open-telemetry/sdk/Metrics/Stream/Delta.php new file mode 100644 index 000000000..a4ff56d71 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/Stream/Delta.php @@ -0,0 +1,33 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\Stream; + +use GMP; + +/** + * @internal + */ +final class Delta +{ + public Metric $metric; + /** + * @psalm-suppress UndefinedDocblockClass + * @phan-suppress PhanUndeclaredTypeProperty + * @var int|GMP + */ + public $readers; + public ?self $prev; + /** + * @psalm-suppress UndefinedDocblockClass + * @phan-suppress PhanUndeclaredTypeParameter + * @param int|GMP $readers + */ + public function __construct(Metric $metric, $readers, ?self $prev = null) + { + $this->metric = $metric; + $this->readers = $readers; + $this->prev = $prev; + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/Stream/DeltaStorage.php b/vendor/open-telemetry/sdk/Metrics/Stream/DeltaStorage.php new file mode 100644 index 000000000..b46a28d65 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/Stream/DeltaStorage.php @@ -0,0 +1,110 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\Stream; + +use function assert; +use GMP; +use OpenTelemetry\SDK\Metrics\AggregationInterface; + +/** + * @internal + */ +final class DeltaStorage +{ + private AggregationInterface $aggregation; + private Delta $head; + + public function __construct(AggregationInterface $aggregation) + { + $this->aggregation = $aggregation; + $this->head = new Delta(new Metric([], [], 0), 0); + + /** @phan-suppress-next-line PhanTypeObjectUnsetDeclaredProperty */ + unset($this->head->metric); + } + + /** + * @psalm-suppress UndefinedDocblockClass + * @phan-suppress PhanUndeclaredTypeParameter + * @param int|GMP $readers + */ + public function add(Metric $metric, $readers): void + { + /** @phpstan-ignore-next-line */ + if ($readers == 0) { + return; + } + + if (($this->head->prev->readers ?? null) != $readers) { + $this->head->prev = new Delta($metric, $readers, $this->head->prev); + } else { + assert($this->head->prev !== null); + $this->mergeInto($this->head->prev->metric, $metric); + } + } + + public function collect(int $reader, bool $retain = false): ?Metric + { + $n = null; + for ($d = $this->head; $d->prev; $d = $d->prev) { + if (($d->prev->readers >> $reader & 1) != 0) { + if ($n !== null) { + assert($n->prev !== null); + $n->prev->readers ^= $d->prev->readers; + $this->mergeInto($d->prev->metric, $n->prev->metric); + $this->tryUnlink($n); + + if ($n->prev === $d->prev) { + continue; + } + } + + $n = $d; + } + } + + $metric = $n->prev->metric ?? null; + + if (!$retain && $n) { + assert($n->prev !== null); + $n->prev->readers ^= ($n->prev->readers & 1 | 1) << $reader; + $this->tryUnlink($n); + } + + return $metric; + } + + private function tryUnlink(Delta $n): void + { + assert($n->prev !== null); + /** @phpstan-ignore-next-line */ + if ($n->prev->readers == 0) { + $n->prev = $n->prev->prev; + + return; + } + + for ($c = $n->prev->prev; + $c && ($n->prev->readers & $c->readers) == 0; + $c = $c->prev) { + } + + if ($c && $n->prev->readers === $c->readers) { + $this->mergeInto($c->metric, $n->prev->metric); + $n->prev = $n->prev->prev; + } + } + + private function mergeInto(Metric $into, Metric $metric): void + { + foreach ($metric->summaries as $k => $summary) { + $into->attributes[$k] ??= $metric->attributes[$k]; + $into->summaries[$k] = isset($into->summaries[$k]) + ? $this->aggregation->merge($into->summaries[$k], $summary) + : $summary; + } + $into->exemplars += $metric->exemplars; + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/Stream/Metric.php b/vendor/open-telemetry/sdk/Metrics/Stream/Metric.php new file mode 100644 index 000000000..6b1db9eef --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/Stream/Metric.php @@ -0,0 +1,44 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\Stream; + +use OpenTelemetry\SDK\Common\Attribute\AttributesInterface; +use OpenTelemetry\SDK\Metrics\Data\Exemplar; + +/** + * @internal + * + * @template T + */ +final class Metric +{ + + /** + * @var array<AttributesInterface> + */ + public array $attributes; + /** + * @var array<T> + */ + public array $summaries; + public int $timestamp; + /** + * @var array<Exemplar> + */ + public array $exemplars; + + /** + * @param array<AttributesInterface> $attributes + * @param array<T> $summaries + * @param array<Exemplar> $exemplars + */ + public function __construct(array $attributes, array $summaries, int $timestamp, array $exemplars = []) + { + $this->attributes = $attributes; + $this->summaries = $summaries; + $this->timestamp = $timestamp; + $this->exemplars = $exemplars; + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/Stream/MetricAggregator.php b/vendor/open-telemetry/sdk/Metrics/Stream/MetricAggregator.php new file mode 100644 index 000000000..b1328eb07 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/Stream/MetricAggregator.php @@ -0,0 +1,73 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\Stream; + +use OpenTelemetry\Context\ContextInterface; +use OpenTelemetry\SDK\Common\Attribute\AttributesInterface; +use OpenTelemetry\SDK\Metrics\AggregationInterface; +use OpenTelemetry\SDK\Metrics\AttributeProcessorInterface; +use OpenTelemetry\SDK\Metrics\Exemplar\ExemplarReservoirInterface; +use function serialize; + +/** + * @internal + */ +final class MetricAggregator implements MetricAggregatorInterface +{ + private ?AttributeProcessorInterface $attributeProcessor; + private AggregationInterface $aggregation; + private ?ExemplarReservoirInterface $exemplarReservoir; + + /** @var array<AttributesInterface> */ + private array $attributes = []; + private array $summaries = []; + + public function __construct( + ?AttributeProcessorInterface $attributeProcessor, + AggregationInterface $aggregation, + ?ExemplarReservoirInterface $exemplarReservoir = null + ) { + $this->attributeProcessor = $attributeProcessor; + $this->aggregation = $aggregation; + $this->exemplarReservoir = $exemplarReservoir; + } + + /** + * @param float|int $value + */ + public function record($value, AttributesInterface $attributes, ContextInterface $context, int $timestamp): void + { + $filteredAttributes = $this->attributeProcessor !== null + ? $this->attributeProcessor->process($attributes, $context) + : $attributes; + $raw = $filteredAttributes->toArray(); + $index = $raw !== [] ? serialize($raw) : 0; + $this->attributes[$index] ??= $filteredAttributes; + $this->aggregation->record( + $this->summaries[$index] ??= $this->aggregation->initialize(), + $value, + $attributes, + $context, + $timestamp, + ); + + if ($this->exemplarReservoir !== null) { + $this->exemplarReservoir->offer($index, $value, $attributes, $context, $timestamp); + } + } + + public function collect(int $timestamp): Metric + { + $exemplars = $this->exemplarReservoir + ? $this->exemplarReservoir->collect($this->attributes) + : []; + $metric = new Metric($this->attributes, $this->summaries, $timestamp, $exemplars); + + $this->attributes = []; + $this->summaries = []; + + return $metric; + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/Stream/MetricAggregatorFactory.php b/vendor/open-telemetry/sdk/Metrics/Stream/MetricAggregatorFactory.php new file mode 100644 index 000000000..5866a72b7 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/Stream/MetricAggregatorFactory.php @@ -0,0 +1,28 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\Stream; + +use OpenTelemetry\SDK\Metrics\AggregationInterface; +use OpenTelemetry\SDK\Metrics\AttributeProcessorInterface; + +/** + * @internal + */ +final class MetricAggregatorFactory implements MetricAggregatorFactoryInterface +{ + private ?AttributeProcessorInterface $attributeProcessor; + private AggregationInterface $aggregation; + + public function __construct(?AttributeProcessorInterface $attributeProcessor, AggregationInterface $aggregation) + { + $this->attributeProcessor = $attributeProcessor; + $this->aggregation = $aggregation; + } + + public function create(): MetricAggregatorInterface + { + return new MetricAggregator($this->attributeProcessor, $this->aggregation); + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/Stream/MetricAggregatorFactoryInterface.php b/vendor/open-telemetry/sdk/Metrics/Stream/MetricAggregatorFactoryInterface.php new file mode 100644 index 000000000..356f682f2 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/Stream/MetricAggregatorFactoryInterface.php @@ -0,0 +1,13 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\Stream; + +/** + * @internal + */ +interface MetricAggregatorFactoryInterface +{ + public function create(): MetricAggregatorInterface; +} diff --git a/vendor/open-telemetry/sdk/Metrics/Stream/MetricAggregatorInterface.php b/vendor/open-telemetry/sdk/Metrics/Stream/MetricAggregatorInterface.php new file mode 100644 index 000000000..2f5cfbf15 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/Stream/MetricAggregatorInterface.php @@ -0,0 +1,12 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\Stream; + +/** + * @internal + */ +interface MetricAggregatorInterface extends WritableMetricStreamInterface, MetricCollectorInterface +{ +} diff --git a/vendor/open-telemetry/sdk/Metrics/Stream/MetricCollectorInterface.php b/vendor/open-telemetry/sdk/Metrics/Stream/MetricCollectorInterface.php new file mode 100644 index 000000000..51a728df7 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/Stream/MetricCollectorInterface.php @@ -0,0 +1,13 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\Stream; + +/** + * @internal + */ +interface MetricCollectorInterface +{ + public function collect(int $timestamp): Metric; +} diff --git a/vendor/open-telemetry/sdk/Metrics/Stream/MetricStreamInterface.php b/vendor/open-telemetry/sdk/Metrics/Stream/MetricStreamInterface.php new file mode 100644 index 000000000..1373a1c93 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/Stream/MetricStreamInterface.php @@ -0,0 +1,58 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\Stream; + +use OpenTelemetry\SDK\Metrics\Data\DataInterface; +use OpenTelemetry\SDK\Metrics\Data\Temporality; + +/** + * @internal + */ +interface MetricStreamInterface +{ + /** + * Returns the internal temporality of this stream. + * + * @return string|Temporality internal temporality + */ + public function temporality(); + + /** + * Returns the last metric timestamp. + * + * @return int metric timestamp + */ + public function timestamp(): int; + + /** + * Pushes metric data to the stream. + * + * @param Metric $metric metric data to push + */ + public function push(Metric $metric): void; + + /** + * Registers a new reader with the given temporality. + * + * @param string|Temporality $temporality temporality to use + * @return int reader id + */ + public function register($temporality): int; + + /** + * Unregisters the given reader. + * + * @param int $reader reader id + */ + public function unregister(int $reader): void; + + /** + * Collects metric data for the given reader. + * + * @param int $reader reader id + * @return DataInterface metric data + */ + public function collect(int $reader): DataInterface; +} diff --git a/vendor/open-telemetry/sdk/Metrics/Stream/SynchronousMetricStream.php b/vendor/open-telemetry/sdk/Metrics/Stream/SynchronousMetricStream.php new file mode 100644 index 000000000..52645504c --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/Stream/SynchronousMetricStream.php @@ -0,0 +1,126 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\Stream; + +use function assert; +use const E_USER_WARNING; +use function extension_loaded; +use GMP; +use function gmp_init; +use function is_int; +use OpenTelemetry\SDK\Metrics\AggregationInterface; +use OpenTelemetry\SDK\Metrics\Data\DataInterface; +use OpenTelemetry\SDK\Metrics\Data\Exemplar; +use OpenTelemetry\SDK\Metrics\Data\Temporality; +use const PHP_INT_SIZE; +use function sprintf; +use function trigger_error; + +/** + * @internal + */ +final class SynchronousMetricStream implements MetricStreamInterface +{ + private AggregationInterface $aggregation; + + private int $timestamp; + + private DeltaStorage $delta; + /** + * @psalm-suppress UndefinedDocblockClass + * @phan-suppress PhanUndeclaredTypeProperty + * @var int|GMP + */ + private $readers = 0; + /** + * @psalm-suppress UndefinedDocblockClass + * @phan-suppress PhanUndeclaredTypeProperty + * @var int|GMP + */ + private $cumulative = 0; + + public function __construct(AggregationInterface $aggregation, int $startTimestamp) + { + $this->aggregation = $aggregation; + $this->timestamp = $startTimestamp; + $this->delta = new DeltaStorage($aggregation); + } + + public function temporality() + { + return Temporality::DELTA; + } + + public function timestamp(): int + { + return $this->timestamp; + } + + public function push(Metric $metric): void + { + [$this->timestamp, $metric->timestamp] = [$metric->timestamp, $this->timestamp]; + $this->delta->add($metric, $this->readers); + } + + public function register($temporality): int + { + $reader = 0; + for ($r = $this->readers; ($r & 1) != 0; $r >>= 1, $reader++) { + } + + if ($reader === (PHP_INT_SIZE << 3) - 1 && is_int($this->readers)) { + if (!extension_loaded('gmp')) { + trigger_error(sprintf('GMP extension required to register over %d readers', (PHP_INT_SIZE << 3) - 1), E_USER_WARNING); + $reader = PHP_INT_SIZE << 3; + } else { + assert(is_int($this->cumulative)); + $this->readers = gmp_init($this->readers); + $this->cumulative = gmp_init($this->cumulative); + } + } + + $readerMask = ($this->readers & 1 | 1) << $reader; + $this->readers ^= $readerMask; + if ($temporality === Temporality::CUMULATIVE) { + $this->cumulative ^= $readerMask; + } + + return $reader; + } + + public function unregister(int $reader): void + { + $readerMask = ($this->readers & 1 | 1) << $reader; + if (($this->readers & $readerMask) == 0) { + return; + } + + $this->delta->collect($reader); + + $this->readers ^= $readerMask; + if (($this->cumulative & $readerMask) != 0) { + $this->cumulative ^= $readerMask; + } + } + + public function collect(int $reader): DataInterface + { + $cumulative = ($this->cumulative >> $reader & 1) != 0; + $metric = $this->delta->collect($reader, $cumulative) ?? new Metric([], [], $this->timestamp); + + $temporality = $cumulative + ? Temporality::CUMULATIVE + : Temporality::DELTA; + + return $this->aggregation->toData( + $metric->attributes, + $metric->summaries, + Exemplar::groupByIndex($metric->exemplars), + $metric->timestamp, + $this->timestamp, + $temporality, + ); + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/Stream/WritableMetricStreamInterface.php b/vendor/open-telemetry/sdk/Metrics/Stream/WritableMetricStreamInterface.php new file mode 100644 index 000000000..9fd425a44 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/Stream/WritableMetricStreamInterface.php @@ -0,0 +1,19 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\Stream; + +use OpenTelemetry\Context\ContextInterface; +use OpenTelemetry\SDK\Common\Attribute\AttributesInterface; + +/** + * @internal + */ +interface WritableMetricStreamInterface +{ + /** + * @param float|int $value + */ + public function record($value, AttributesInterface $attributes, ContextInterface $context, int $timestamp): void; +} diff --git a/vendor/open-telemetry/sdk/Metrics/UpDownCounter.php b/vendor/open-telemetry/sdk/Metrics/UpDownCounter.php new file mode 100644 index 000000000..1adf67f8a --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/UpDownCounter.php @@ -0,0 +1,37 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics; + +use OpenTelemetry\API\Metrics\UpDownCounterInterface; +use OpenTelemetry\SDK\Metrics\MetricRegistry\MetricWriterInterface; + +/** + * @internal + */ +final class UpDownCounter implements UpDownCounterInterface +{ + private MetricWriterInterface $writer; + private Instrument $instrument; + private ReferenceCounterInterface $referenceCounter; + + public function __construct(MetricWriterInterface $writer, Instrument $instrument, ReferenceCounterInterface $referenceCounter) + { + $this->writer = $writer; + $this->instrument = $instrument; + $this->referenceCounter = $referenceCounter; + + $this->referenceCounter->acquire(); + } + + public function __destruct() + { + $this->referenceCounter->release(); + } + + public function add($amount, iterable $attributes = [], $context = null): void + { + $this->writer->record($this->instrument, $amount, $attributes, $context); + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/View/CriteriaViewRegistry.php b/vendor/open-telemetry/sdk/Metrics/View/CriteriaViewRegistry.php new file mode 100644 index 000000000..f387abf9c --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/View/CriteriaViewRegistry.php @@ -0,0 +1,40 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\View; + +use Generator; +use OpenTelemetry\SDK\Common\Instrumentation\InstrumentationScopeInterface; +use OpenTelemetry\SDK\Metrics\Instrument; +use OpenTelemetry\SDK\Metrics\ViewRegistryInterface; + +final class CriteriaViewRegistry implements ViewRegistryInterface +{ + /** @var list<SelectionCriteriaInterface> */ + private array $criteria = []; + /** @var list<ViewTemplate> */ + private array $views = []; + + public function register(SelectionCriteriaInterface $criteria, ViewTemplate $view): void + { + $this->criteria[] = $criteria; + $this->views[] = $view; + } + + public function find(Instrument $instrument, InstrumentationScopeInterface $instrumentationScope): ?iterable + { + $views = $this->generateViews($instrument, $instrumentationScope); + + return $views->valid() ? $views : null; + } + + private function generateViews(Instrument $instrument, InstrumentationScopeInterface $instrumentationScope): Generator + { + foreach ($this->criteria as $i => $criteria) { + if ($criteria->accepts($instrument, $instrumentationScope)) { + yield $this->views[$i]->project($instrument); + } + } + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/View/SelectionCriteria/AllCriteria.php b/vendor/open-telemetry/sdk/Metrics/View/SelectionCriteria/AllCriteria.php new file mode 100644 index 000000000..438297324 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/View/SelectionCriteria/AllCriteria.php @@ -0,0 +1,33 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\View\SelectionCriteria; + +use OpenTelemetry\SDK\Common\Instrumentation\InstrumentationScopeInterface; +use OpenTelemetry\SDK\Metrics\Instrument; +use OpenTelemetry\SDK\Metrics\View\SelectionCriteriaInterface; + +final class AllCriteria implements SelectionCriteriaInterface +{ + private iterable $criteria; + + /** + * @param iterable<SelectionCriteriaInterface> $criteria + */ + public function __construct(iterable $criteria) + { + $this->criteria = $criteria; + } + + public function accepts(Instrument $instrument, InstrumentationScopeInterface $instrumentationScope): bool + { + foreach ($this->criteria as $criterion) { + if (!$criterion->accepts($instrument, $instrumentationScope)) { + return false; + } + } + + return true; + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/View/SelectionCriteria/InstrumentNameCriteria.php b/vendor/open-telemetry/sdk/Metrics/View/SelectionCriteria/InstrumentNameCriteria.php new file mode 100644 index 000000000..ed6034755 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/View/SelectionCriteria/InstrumentNameCriteria.php @@ -0,0 +1,28 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\View\SelectionCriteria; + +use OpenTelemetry\SDK\Common\Instrumentation\InstrumentationScopeInterface; +use OpenTelemetry\SDK\Metrics\Instrument; +use OpenTelemetry\SDK\Metrics\View\SelectionCriteriaInterface; +use function preg_match; +use function preg_quote; +use function sprintf; +use function strtr; + +final class InstrumentNameCriteria implements SelectionCriteriaInterface +{ + private string $pattern; + + public function __construct(string $name) + { + $this->pattern = sprintf('/^%s$/', strtr(preg_quote($name, '/'), ['\\?' => '.', '\\*' => '.*'])); + } + + public function accepts(Instrument $instrument, InstrumentationScopeInterface $instrumentationScope): bool + { + return (bool) preg_match($this->pattern, $instrument->name); + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/View/SelectionCriteria/InstrumentTypeCriteria.php b/vendor/open-telemetry/sdk/Metrics/View/SelectionCriteria/InstrumentTypeCriteria.php new file mode 100644 index 000000000..46a88def0 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/View/SelectionCriteria/InstrumentTypeCriteria.php @@ -0,0 +1,29 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\View\SelectionCriteria; + +use function in_array; +use OpenTelemetry\SDK\Common\Instrumentation\InstrumentationScopeInterface; +use OpenTelemetry\SDK\Metrics\Instrument; +use OpenTelemetry\SDK\Metrics\InstrumentType; +use OpenTelemetry\SDK\Metrics\View\SelectionCriteriaInterface; + +final class InstrumentTypeCriteria implements SelectionCriteriaInterface +{ + private array $instrumentTypes; + + /** + * @param string|InstrumentType|string[]|InstrumentType[] $instrumentType + */ + public function __construct($instrumentType) + { + $this->instrumentTypes = (array) $instrumentType; + } + + public function accepts(Instrument $instrument, InstrumentationScopeInterface $instrumentationScope): bool + { + return in_array($instrument->type, $this->instrumentTypes, true); + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/View/SelectionCriteria/InstrumentationScopeNameCriteria.php b/vendor/open-telemetry/sdk/Metrics/View/SelectionCriteria/InstrumentationScopeNameCriteria.php new file mode 100644 index 000000000..201d1a7b2 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/View/SelectionCriteria/InstrumentationScopeNameCriteria.php @@ -0,0 +1,24 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\View\SelectionCriteria; + +use OpenTelemetry\SDK\Common\Instrumentation\InstrumentationScopeInterface; +use OpenTelemetry\SDK\Metrics\Instrument; +use OpenTelemetry\SDK\Metrics\View\SelectionCriteriaInterface; + +final class InstrumentationScopeNameCriteria implements SelectionCriteriaInterface +{ + private string $name; + + public function __construct(string $name) + { + $this->name = $name; + } + + public function accepts(Instrument $instrument, InstrumentationScopeInterface $instrumentationScope): bool + { + return $this->name === $instrumentationScope->getName(); + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/View/SelectionCriteria/InstrumentationScopeSchemaUrlCriteria.php b/vendor/open-telemetry/sdk/Metrics/View/SelectionCriteria/InstrumentationScopeSchemaUrlCriteria.php new file mode 100644 index 000000000..a11a1d589 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/View/SelectionCriteria/InstrumentationScopeSchemaUrlCriteria.php @@ -0,0 +1,24 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\View\SelectionCriteria; + +use OpenTelemetry\SDK\Common\Instrumentation\InstrumentationScopeInterface; +use OpenTelemetry\SDK\Metrics\Instrument; +use OpenTelemetry\SDK\Metrics\View\SelectionCriteriaInterface; + +final class InstrumentationScopeSchemaUrlCriteria implements SelectionCriteriaInterface +{ + private ?string $schemaUrl; + + public function __construct(?string $schemaUrl) + { + $this->schemaUrl = $schemaUrl; + } + + public function accepts(Instrument $instrument, InstrumentationScopeInterface $instrumentationScope): bool + { + return $this->schemaUrl === $instrumentationScope->getSchemaUrl(); + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/View/SelectionCriteria/InstrumentationScopeVersionCriteria.php b/vendor/open-telemetry/sdk/Metrics/View/SelectionCriteria/InstrumentationScopeVersionCriteria.php new file mode 100644 index 000000000..37d180f99 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/View/SelectionCriteria/InstrumentationScopeVersionCriteria.php @@ -0,0 +1,24 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\View\SelectionCriteria; + +use OpenTelemetry\SDK\Common\Instrumentation\InstrumentationScopeInterface; +use OpenTelemetry\SDK\Metrics\Instrument; +use OpenTelemetry\SDK\Metrics\View\SelectionCriteriaInterface; + +final class InstrumentationScopeVersionCriteria implements SelectionCriteriaInterface +{ + private ?string $version; + + public function __construct(?string $version) + { + $this->version = $version; + } + + public function accepts(Instrument $instrument, InstrumentationScopeInterface $instrumentationScope): bool + { + return $this->version === $instrumentationScope->getVersion(); + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/View/SelectionCriteriaInterface.php b/vendor/open-telemetry/sdk/Metrics/View/SelectionCriteriaInterface.php new file mode 100644 index 000000000..8abd6fa69 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/View/SelectionCriteriaInterface.php @@ -0,0 +1,13 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\View; + +use OpenTelemetry\SDK\Common\Instrumentation\InstrumentationScopeInterface; +use OpenTelemetry\SDK\Metrics\Instrument; + +interface SelectionCriteriaInterface +{ + public function accepts(Instrument $instrument, InstrumentationScopeInterface $instrumentationScope): bool; +} diff --git a/vendor/open-telemetry/sdk/Metrics/View/ViewTemplate.php b/vendor/open-telemetry/sdk/Metrics/View/ViewTemplate.php new file mode 100644 index 000000000..302ed83ae --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/View/ViewTemplate.php @@ -0,0 +1,77 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\View; + +use OpenTelemetry\SDK\Metrics\AggregationInterface; +use OpenTelemetry\SDK\Metrics\Instrument; +use OpenTelemetry\SDK\Metrics\ViewProjection; + +final class ViewTemplate +{ + private ?string $name = null; + private ?string $description = null; + /** + * @var list<string> + */ + private ?array $attributeKeys = null; + private ?AggregationInterface $aggregation = null; + + private function __construct() + { + } + + public static function create(): self + { + static $instance; + + return $instance ??= new self(); + } + + public function withName(string $name): self + { + $self = clone $this; + $self->name = $name; + + return $self; + } + + public function withDescription(string $description): self + { + $self = clone $this; + $self->description = $description; + + return $self; + } + + /** + * @param list<string> $attributeKeys + */ + public function withAttributeKeys(array $attributeKeys): self + { + $self = clone $this; + $self->attributeKeys = $attributeKeys; + + return $self; + } + + public function withAggregation(?AggregationInterface $aggregation): self + { + $self = clone $this; + $self->aggregation = $aggregation; + + return $self; + } + + public function project(Instrument $instrument): ViewProjection + { + return new ViewProjection( + $this->name ?? $instrument->name, + $instrument->unit, + $this->description ?? $instrument->description, + $this->attributeKeys, + $this->aggregation, + ); + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/ViewProjection.php b/vendor/open-telemetry/sdk/Metrics/ViewProjection.php new file mode 100644 index 000000000..046bd6bb1 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/ViewProjection.php @@ -0,0 +1,47 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics; + +final class ViewProjection +{ + /** + * @readonly + */ + public string $name; + /** + * @readonly + */ + public ?string $unit; + /** + * @readonly + */ + public ?string $description; + /** + * @readonly + * @var list<string>|null + */ + public ?array $attributeKeys; + /** + * @readonly + */ + public ?AggregationInterface $aggregation; + + /** + * @param list<string>|null $attributeKeys + */ + public function __construct( + string $name, + ?string $unit, + ?string $description, + ?array $attributeKeys, + ?AggregationInterface $aggregation + ) { + $this->name = $name; + $this->unit = $unit; + $this->description = $description; + $this->attributeKeys = $attributeKeys; + $this->aggregation = $aggregation; + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/ViewRegistryInterface.php b/vendor/open-telemetry/sdk/Metrics/ViewRegistryInterface.php new file mode 100644 index 000000000..19d8f9ffd --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/ViewRegistryInterface.php @@ -0,0 +1,15 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics; + +use OpenTelemetry\SDK\Common\Instrumentation\InstrumentationScopeInterface; + +interface ViewRegistryInterface +{ + /** + * @return iterable<ViewProjection>|null + */ + public function find(Instrument $instrument, InstrumentationScopeInterface $instrumentationScope): ?iterable; +} |