diff options
Diffstat (limited to 'vendor/open-telemetry/sdk/Trace')
55 files changed, 3539 insertions, 0 deletions
diff --git a/vendor/open-telemetry/sdk/Trace/Behavior/LoggerAwareTrait.php b/vendor/open-telemetry/sdk/Trace/Behavior/LoggerAwareTrait.php new file mode 100644 index 000000000..24f5e56a8 --- /dev/null +++ b/vendor/open-telemetry/sdk/Trace/Behavior/LoggerAwareTrait.php @@ -0,0 +1,48 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Trace\Behavior; + +use Psr\Log\LoggerAwareTrait as PsrTrait; +use Psr\Log\LoggerInterface; +use Psr\Log\LogLevel; +use Psr\Log\NullLogger; + +trait LoggerAwareTrait +{ + use PsrTrait; + + private string $defaultLogLevel = LogLevel::INFO; + + /** + * @param string $logLevel + */ + public function setDefaultLogLevel(string $logLevel): void + { + $this->defaultLogLevel = $logLevel; + } + + /** + * @param string $message + * @param array $context + * @param string|null $level + */ + protected function log(string $message, array $context = [], ?string $level = null): void + { + $this->getLogger()->log( + $level ?? $this->defaultLogLevel, + $message, + $context + ); + } + + protected function getLogger(): LoggerInterface + { + if ($this->logger !== null) { + return $this->logger; + } + + return new NullLogger(); + } +} diff --git a/vendor/open-telemetry/sdk/Trace/Behavior/SpanExporterDecoratorTrait.php b/vendor/open-telemetry/sdk/Trace/Behavior/SpanExporterDecoratorTrait.php new file mode 100644 index 000000000..97839ec5b --- /dev/null +++ b/vendor/open-telemetry/sdk/Trace/Behavior/SpanExporterDecoratorTrait.php @@ -0,0 +1,47 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Trace\Behavior; + +use OpenTelemetry\SDK\Common\Future\CancellationInterface; +use OpenTelemetry\SDK\Common\Future\FutureInterface; +use OpenTelemetry\SDK\Trace\SpanDataInterface; +use OpenTelemetry\SDK\Trace\SpanExporterInterface; + +trait SpanExporterDecoratorTrait +{ + protected SpanExporterInterface $decorated; + + /** + * @param iterable<SpanDataInterface> $batch + * @return FutureInterface<bool> + */ + public function export(iterable $batch, ?CancellationInterface $cancellation = null): FutureInterface + { + $batch = $this->beforeExport($batch); + $response = $this->decorated->export($batch, $cancellation); + $response->map(fn (bool $result) => $this->afterExport($batch, $result)); + + return $response; + } + + abstract protected function beforeExport(iterable $spans): iterable; + + abstract protected function afterExport(iterable $spans, bool $exportSuccess): void; + + public function shutdown(?CancellationInterface $cancellation = null): bool + { + return $this->decorated->shutdown($cancellation); + } + + public function forceFlush(?CancellationInterface $cancellation = null): bool + { + return $this->decorated->forceFlush($cancellation); + } + + public function setDecorated(SpanExporterInterface $decorated): void + { + $this->decorated = $decorated; + } +} diff --git a/vendor/open-telemetry/sdk/Trace/Behavior/SpanExporterTrait.php b/vendor/open-telemetry/sdk/Trace/Behavior/SpanExporterTrait.php new file mode 100644 index 000000000..339fecc1d --- /dev/null +++ b/vendor/open-telemetry/sdk/Trace/Behavior/SpanExporterTrait.php @@ -0,0 +1,47 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Trace\Behavior; + +use OpenTelemetry\SDK\Common\Future\CancellationInterface; +use OpenTelemetry\SDK\Common\Future\CompletedFuture; +use OpenTelemetry\SDK\Common\Future\FutureInterface; +use OpenTelemetry\SDK\Trace\SpanDataInterface; + +trait SpanExporterTrait +{ + private bool $running = true; + + /** @see https://github.com/open-telemetry/opentelemetry-specification/blob/v1.7.0/specification/trace/sdk.md#shutdown-2 */ + public function shutdown(?CancellationInterface $cancellation = null): bool + { + $this->running = false; + + return true; + } + + /** @see https://github.com/open-telemetry/opentelemetry-specification/blob/v1.7.0/specification/trace/sdk.md#forceflush-2 */ + public function forceFlush(?CancellationInterface $cancellation = null): bool + { + return true; + } + + /** + * @param iterable<SpanDataInterface> $batch + * @return FutureInterface<bool> + */ + public function export(iterable $batch, ?CancellationInterface $cancellation = null): FutureInterface + { + if (!$this->running) { + return new CompletedFuture(false); + } + + return new CompletedFuture($this->doExport($batch)); /** @phpstan-ignore-line */ + } + + /** + * @param iterable<SpanDataInterface> $spans Batch of spans to export + */ + abstract protected function doExport(iterable $spans): bool; /** @phpstan-ignore-line */ +} diff --git a/vendor/open-telemetry/sdk/Trace/Behavior/UsesSpanConverterTrait.php b/vendor/open-telemetry/sdk/Trace/Behavior/UsesSpanConverterTrait.php new file mode 100644 index 000000000..4802cd15b --- /dev/null +++ b/vendor/open-telemetry/sdk/Trace/Behavior/UsesSpanConverterTrait.php @@ -0,0 +1,41 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Trace\Behavior; + +use OpenTelemetry\SDK\Trace\SpanConverterInterface; +use OpenTelemetry\SDK\Trace\SpanDataInterface; +use OpenTelemetry\SDK\Trace\SpanExporter\NullSpanConverter; + +trait UsesSpanConverterTrait +{ + private ?SpanConverterInterface $converter = null; + + /** + * @param SpanConverterInterface $converter + */ + protected function setSpanConverter(SpanConverterInterface $converter): void + { + $this->converter = $converter; + } + + public function getSpanConverter(): SpanConverterInterface + { + if (null === $this->converter) { + $this->converter = new NullSpanConverter(); + } + + return $this->converter; + } + + /** + * @param SpanDataInterface $span + * @return array + * @psalm-suppress PossiblyNullReference + */ + protected function convertSpan(SpanDataInterface $span): array + { + return $this->getSpanConverter()->convert([$span]); + } +} diff --git a/vendor/open-telemetry/sdk/Trace/Event.php b/vendor/open-telemetry/sdk/Trace/Event.php new file mode 100644 index 000000000..28cb39bb1 --- /dev/null +++ b/vendor/open-telemetry/sdk/Trace/Event.php @@ -0,0 +1,47 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Trace; + +use function count; +use OpenTelemetry\SDK\Common\Attribute\AttributesInterface; + +final class Event implements EventInterface +{ + private string $name; + private int $timestamp; + private AttributesInterface $attributes; + + public function __construct(string $name, int $timestamp, AttributesInterface $attributes) + { + $this->name = $name; + $this->timestamp = $timestamp; + $this->attributes = $attributes; + } + + public function getAttributes(): AttributesInterface + { + return $this->attributes; + } + + public function getName(): string + { + return $this->name; + } + + public function getEpochNanos(): int + { + return $this->timestamp; + } + + public function getTotalAttributeCount(): int + { + return count($this->attributes); + } + + public function getDroppedAttributesCount(): int + { + return $this->attributes->getDroppedAttributesCount(); + } +} diff --git a/vendor/open-telemetry/sdk/Trace/EventInterface.php b/vendor/open-telemetry/sdk/Trace/EventInterface.php new file mode 100644 index 000000000..8b5ee2af6 --- /dev/null +++ b/vendor/open-telemetry/sdk/Trace/EventInterface.php @@ -0,0 +1,15 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Trace; + +use OpenTelemetry\SDK\Common\Attribute\AttributesInterface; + +interface EventInterface +{ + public function getName(): string; + public function getAttributes(): AttributesInterface; + public function getEpochNanos(): int; + public function getTotalAttributeCount(): int; +} diff --git a/vendor/open-telemetry/sdk/Trace/ExporterFactory.php b/vendor/open-telemetry/sdk/Trace/ExporterFactory.php new file mode 100644 index 000000000..9b652cc2f --- /dev/null +++ b/vendor/open-telemetry/sdk/Trace/ExporterFactory.php @@ -0,0 +1,32 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Trace; + +use InvalidArgumentException; +use OpenTelemetry\SDK\Common\Configuration\Configuration; +use OpenTelemetry\SDK\Common\Configuration\Variables; +use OpenTelemetry\SDK\Registry; +use RuntimeException; + +class ExporterFactory +{ + /** + * @throws RuntimeException + */ + public function create(): ?SpanExporterInterface + { + $exporters = Configuration::getList(Variables::OTEL_TRACES_EXPORTER); + if (1 !== count($exporters)) { + throw new InvalidArgumentException(sprintf('Configuration %s requires exactly 1 exporter', Variables::OTEL_TRACES_EXPORTER)); + } + $exporter = $exporters[0]; + if ($exporter === 'none') { + return null; + } + $factory = Registry::spanExporterFactory($exporter); + + return $factory->create(); + } +} diff --git a/vendor/open-telemetry/sdk/Trace/IdGeneratorInterface.php b/vendor/open-telemetry/sdk/Trace/IdGeneratorInterface.php new file mode 100644 index 000000000..ad622dccc --- /dev/null +++ b/vendor/open-telemetry/sdk/Trace/IdGeneratorInterface.php @@ -0,0 +1,12 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Trace; + +interface IdGeneratorInterface +{ + public function generateTraceId(): string; + + public function generateSpanId(): string; +} diff --git a/vendor/open-telemetry/sdk/Trace/ImmutableSpan.php b/vendor/open-telemetry/sdk/Trace/ImmutableSpan.php new file mode 100644 index 000000000..57836d4c3 --- /dev/null +++ b/vendor/open-telemetry/sdk/Trace/ImmutableSpan.php @@ -0,0 +1,153 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Trace; + +use function max; +use OpenTelemetry\API\Trace as API; +use OpenTelemetry\SDK\Common\Attribute\AttributesInterface; +use OpenTelemetry\SDK\Common\Instrumentation\InstrumentationScopeInterface; +use OpenTelemetry\SDK\Resource\ResourceInfo; + +/** + * @psalm-immutable + */ +final class ImmutableSpan implements SpanDataInterface +{ + private Span $span; + + /** @var non-empty-string */ + private string $name; + + /** @var list<EventInterface> */ + private array $events; + + /** @var list<LinkInterface> */ + private array $links; + + private AttributesInterface $attributes; + private int $totalRecordedEvents; + private StatusDataInterface $status; + private int $endEpochNanos; + private bool $hasEnded; + + /** + * @param non-empty-string $name + * @param list<LinkInterface> $links + * @param list<EventInterface> $events + */ + public function __construct( + Span $span, + string $name, + array $links, + array $events, + AttributesInterface $attributes, + int $totalRecordedEvents, + StatusDataInterface $status, + int $endEpochNanos, + bool $hasEnded + ) { + $this->span = $span; + $this->name = $name; + $this->links = $links; + $this->events = $events; + $this->attributes = $attributes; + $this->totalRecordedEvents = $totalRecordedEvents; + $this->status = $status; + $this->endEpochNanos = $endEpochNanos; + $this->hasEnded = $hasEnded; + } + + public function getKind(): int + { + return $this->span->getKind(); + } + + public function getContext(): API\SpanContextInterface + { + return $this->span->getContext(); + } + + public function getParentContext(): API\SpanContextInterface + { + return $this->span->getParentContext(); + } + + public function getTraceId(): string + { + return $this->getContext()->getTraceId(); + } + + public function getSpanId(): string + { + return $this->getContext()->getSpanId(); + } + + public function getParentSpanId(): string + { + return $this->getParentContext()->getSpanId(); + } + + public function getStartEpochNanos(): int + { + return $this->span->getStartEpochNanos(); + } + + public function getEndEpochNanos(): int + { + return $this->endEpochNanos; + } + + public function getInstrumentationScope(): InstrumentationScopeInterface + { + return $this->span->getInstrumentationScope(); + } + + public function getResource(): ResourceInfo + { + return $this->span->getResource(); + } + + public function getName(): string + { + return $this->name; + } + + /** @inheritDoc */ + public function getLinks(): array + { + return $this->links; + } + + /** @inheritDoc */ + public function getEvents(): array + { + return $this->events; + } + + public function getAttributes(): AttributesInterface + { + return $this->attributes; + } + + public function getTotalDroppedEvents(): int + { + return max(0, $this->totalRecordedEvents - count($this->events)); + } + + public function getTotalDroppedLinks(): int + { + return max(0, $this->span->getTotalRecordedLinks() - count($this->links)); + } + + public function getStatus(): StatusDataInterface + { + return $this->status; + } + + public function hasEnded(): bool + { + return $this->hasEnded; + } +} diff --git a/vendor/open-telemetry/sdk/Trace/Link.php b/vendor/open-telemetry/sdk/Trace/Link.php new file mode 100644 index 000000000..9927839e7 --- /dev/null +++ b/vendor/open-telemetry/sdk/Trace/Link.php @@ -0,0 +1,30 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Trace; + +use OpenTelemetry\API\Trace as API; +use OpenTelemetry\SDK\Common\Attribute\AttributesInterface; + +final class Link implements LinkInterface +{ + private AttributesInterface $attributes; + private API\SpanContextInterface $context; + + public function __construct(API\SpanContextInterface $context, AttributesInterface $attributes) + { + $this->context = $context; + $this->attributes = $attributes; + } + + public function getSpanContext(): API\SpanContextInterface + { + return $this->context; + } + + public function getAttributes(): AttributesInterface + { + return $this->attributes; + } +} diff --git a/vendor/open-telemetry/sdk/Trace/LinkInterface.php b/vendor/open-telemetry/sdk/Trace/LinkInterface.php new file mode 100644 index 000000000..8090fa1a5 --- /dev/null +++ b/vendor/open-telemetry/sdk/Trace/LinkInterface.php @@ -0,0 +1,14 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Trace; + +use OpenTelemetry\API\Trace\SpanContextInterface; +use OpenTelemetry\SDK\Common\Attribute\AttributesInterface; + +interface LinkInterface +{ + public function getSpanContext(): SpanContextInterface; + public function getAttributes(): AttributesInterface; +} diff --git a/vendor/open-telemetry/sdk/Trace/NoopTracerProvider.php b/vendor/open-telemetry/sdk/Trace/NoopTracerProvider.php new file mode 100644 index 000000000..7cd4d4e7d --- /dev/null +++ b/vendor/open-telemetry/sdk/Trace/NoopTracerProvider.php @@ -0,0 +1,21 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Trace; + +use OpenTelemetry\API; +use OpenTelemetry\SDK\Common\Future\CancellationInterface; + +class NoopTracerProvider extends API\Trace\NoopTracerProvider implements TracerProviderInterface +{ + public function forceFlush(?CancellationInterface $cancellation = null): bool + { + return true; + } + + public function shutdown(?CancellationInterface $cancellation = null): bool + { + return true; + } +} diff --git a/vendor/open-telemetry/sdk/Trace/RandomIdGenerator.php b/vendor/open-telemetry/sdk/Trace/RandomIdGenerator.php new file mode 100644 index 000000000..39767fb0f --- /dev/null +++ b/vendor/open-telemetry/sdk/Trace/RandomIdGenerator.php @@ -0,0 +1,49 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Trace; + +use OpenTelemetry\API\Trace\SpanContextValidator; +use Throwable; + +class RandomIdGenerator implements IdGeneratorInterface +{ + private const TRACE_ID_HEX_LENGTH = 32; + private const SPAN_ID_HEX_LENGTH = 16; + + public function generateTraceId(): string + { + do { + $traceId = $this->randomHex(self::TRACE_ID_HEX_LENGTH); + } while (!SpanContextValidator::isValidTraceId($traceId)); + + return $traceId; + } + + public function generateSpanId(): string + { + do { + $spanId = $this->randomHex(self::SPAN_ID_HEX_LENGTH); + } while (!SpanContextValidator::isValidSpanId($spanId)); + + return $spanId; + } + + /** + * @psalm-suppress ArgumentTypeCoercion $hexLength is always a positive integer + */ + private function randomHex(int $hexLength): string + { + try { + return bin2hex(random_bytes(intdiv($hexLength, 2))); + } catch (Throwable $e) { + return $this->fallbackAlgorithm($hexLength); + } + } + + private function fallbackAlgorithm(int $hexLength): string + { + return substr(str_shuffle(str_repeat('0123456789abcdef', $hexLength)), 1, $hexLength); + } +} diff --git a/vendor/open-telemetry/sdk/Trace/ReadWriteSpanInterface.php b/vendor/open-telemetry/sdk/Trace/ReadWriteSpanInterface.php new file mode 100644 index 000000000..60940ac01 --- /dev/null +++ b/vendor/open-telemetry/sdk/Trace/ReadWriteSpanInterface.php @@ -0,0 +1,11 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Trace; + +use OpenTelemetry\API\Trace as API; + +interface ReadWriteSpanInterface extends API\SpanInterface, ReadableSpanInterface +{ +} diff --git a/vendor/open-telemetry/sdk/Trace/ReadableSpanInterface.php b/vendor/open-telemetry/sdk/Trace/ReadableSpanInterface.php new file mode 100644 index 000000000..40704ab4e --- /dev/null +++ b/vendor/open-telemetry/sdk/Trace/ReadableSpanInterface.php @@ -0,0 +1,48 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Trace; + +use OpenTelemetry\API\Trace as API; +use OpenTelemetry\SDK\Common\Instrumentation\InstrumentationScopeInterface; + +/** + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/v1.6.1/specification/trace/sdk.md#additional-span-interfaces + */ +interface ReadableSpanInterface +{ + public function getName(): string; + + public function getContext(): API\SpanContextInterface; + + public function getParentContext(): API\SpanContextInterface; + + public function getInstrumentationScope(): InstrumentationScopeInterface; + + public function hasEnded(): bool; + + /** + * Returns an immutable representation of this instance. + */ + public function toSpanData(): SpanDataInterface; + + /** + * Returns the duration of the {@see API\SpanInterface} in nanoseconds. + * If still active, returns `now() - start`. + */ + public function getDuration(): int; + + /** + * @see API\SpanKind + */ + public function getKind(): int; + + /** + * Returns the value of the attribute with the provided *key*. + * Returns `null` if there are no attributes set, or no attribute with that key exists. + * + * @return mixed + */ + public function getAttribute(string $key); +} diff --git a/vendor/open-telemetry/sdk/Trace/Sampler/AlwaysOffSampler.php b/vendor/open-telemetry/sdk/Trace/Sampler/AlwaysOffSampler.php new file mode 100644 index 000000000..ee7e70a56 --- /dev/null +++ b/vendor/open-telemetry/sdk/Trace/Sampler/AlwaysOffSampler.php @@ -0,0 +1,50 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Trace\Sampler; + +use OpenTelemetry\Context\ContextInterface; +use OpenTelemetry\SDK\Common\Attribute\AttributesInterface; +use OpenTelemetry\SDK\Trace\SamplerInterface; +use OpenTelemetry\SDK\Trace\SamplingResult; +use OpenTelemetry\SDK\Trace\Span; + +/** + * This implementation of the SamplerInterface always skips record. + * Example: + * ``` + * use OpenTelemetry\Sdk\Trace\AlwaysOffSampler; + * $sampler = new AlwaysOffSampler(); + * ``` + */ +class AlwaysOffSampler implements SamplerInterface +{ + /** + * Returns false because we never want to sample. + * {@inheritdoc} + */ + public function shouldSample( + ContextInterface $parentContext, + string $traceId, + string $spanName, + int $spanKind, + AttributesInterface $attributes, + array $links + ): SamplingResult { + $parentSpan = Span::fromContext($parentContext); + $parentSpanContext = $parentSpan->getContext(); + $traceState = $parentSpanContext->getTraceState(); + + return new SamplingResult( + SamplingResult::DROP, + [], + $traceState + ); + } + + public function getDescription(): string + { + return 'AlwaysOffSampler'; + } +} diff --git a/vendor/open-telemetry/sdk/Trace/Sampler/AlwaysOnSampler.php b/vendor/open-telemetry/sdk/Trace/Sampler/AlwaysOnSampler.php new file mode 100644 index 000000000..df61d1aee --- /dev/null +++ b/vendor/open-telemetry/sdk/Trace/Sampler/AlwaysOnSampler.php @@ -0,0 +1,50 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Trace\Sampler; + +use OpenTelemetry\Context\ContextInterface; +use OpenTelemetry\SDK\Common\Attribute\AttributesInterface; +use OpenTelemetry\SDK\Trace\SamplerInterface; +use OpenTelemetry\SDK\Trace\SamplingResult; +use OpenTelemetry\SDK\Trace\Span; + +/** + * This implementation of the SamplerInterface always records. + * Example: + * ``` + * use OpenTelemetry\Sdk\Trace\AlwaysOnSampler; + * $sampler = new AlwaysOnSampler(); + * ``` + */ +class AlwaysOnSampler implements SamplerInterface +{ + /** + * Returns true because we always want to sample. + * {@inheritdoc} + */ + public function shouldSample( + ContextInterface $parentContext, + string $traceId, + string $spanName, + int $spanKind, + AttributesInterface $attributes, + array $links + ): SamplingResult { + $parentSpan = Span::fromContext($parentContext); + $parentSpanContext = $parentSpan->getContext(); + $traceState = $parentSpanContext->getTraceState(); + + return new SamplingResult( + SamplingResult::RECORD_AND_SAMPLE, + [], + $traceState + ); + } + + public function getDescription(): string + { + return 'AlwaysOnSampler'; + } +} diff --git a/vendor/open-telemetry/sdk/Trace/Sampler/ParentBased.php b/vendor/open-telemetry/sdk/Trace/Sampler/ParentBased.php new file mode 100644 index 000000000..db801d3d8 --- /dev/null +++ b/vendor/open-telemetry/sdk/Trace/Sampler/ParentBased.php @@ -0,0 +1,100 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Trace\Sampler; + +use OpenTelemetry\Context\ContextInterface; +use OpenTelemetry\SDK\Common\Attribute\AttributesInterface; +use OpenTelemetry\SDK\Trace\SamplerInterface; +use OpenTelemetry\SDK\Trace\SamplingResult; +use OpenTelemetry\SDK\Trace\Span; + +/** + * Phan seems to struggle with the variadic arguments in the latest version + * @phan-file-suppress PhanParamTooFewUnpack + */ + +/** + * This implementation of the SamplerInterface that respects parent context's sampling decision + * and delegates for the root span. + * Example: + * ``` + * use OpenTelemetry\API\Trace\ParentBased; + * use OpenTelemetry\API\Trace\AlwaysOnSampler + * + * $rootSampler = new AlwaysOnSampler(); + * $sampler = new ParentBased($rootSampler); + * ``` + */ +class ParentBased implements SamplerInterface +{ + private SamplerInterface $root; + + private SamplerInterface $remoteParentSampler; + + private SamplerInterface $remoteParentNotSampler; + + private SamplerInterface $localParentSampler; + + private SamplerInterface $localParentNotSampler; + + /** + * ParentBased sampler delegates the sampling decision based on the parent context. + * + * @param SamplerInterface $root Sampler called for the span with no parent (root span). + * @param SamplerInterface|null $remoteParentSampler Sampler called for the span with the remote sampled parent. When null, `AlwaysOnSampler` is used. + * @param SamplerInterface|null $remoteParentNotSampler Sampler called for the span with the remote not sampled parent. When null, `AlwaysOffSampler` is used. + * @param SamplerInterface|null $localParentSampler Sampler called for the span with local the sampled parent. When null, `AlwaysOnSampler` is used. + * @param SamplerInterface|null $localParentNotSampler Sampler called for the span with the local not sampled parent. When null, `AlwaysOffSampler` is used. + */ + public function __construct( + SamplerInterface $root, + ?SamplerInterface $remoteParentSampler = null, + ?SamplerInterface $remoteParentNotSampler = null, + ?SamplerInterface $localParentSampler = null, + ?SamplerInterface $localParentNotSampler = null + ) { + $this->root = $root; + $this->remoteParentSampler = $remoteParentSampler ?? new AlwaysOnSampler(); + $this->remoteParentNotSampler = $remoteParentNotSampler ?? new AlwaysOffSampler(); + $this->localParentSampler = $localParentSampler ?? new AlwaysOnSampler(); + $this->localParentNotSampler = $localParentNotSampler ?? new AlwaysOffSampler(); + } + + /** + * Invokes the respective delegate sampler when parent is set or uses root sampler for the root span. + * {@inheritdoc} + */ + public function shouldSample( + ContextInterface $parentContext, + string $traceId, + string $spanName, + int $spanKind, + AttributesInterface $attributes, + array $links + ): SamplingResult { + $parentSpan = Span::fromContext($parentContext); + $parentSpanContext = $parentSpan->getContext(); + + // Invalid parent SpanContext indicates root span is being created + if (!$parentSpanContext->isValid()) { + return $this->root->shouldSample(...func_get_args()); + } + + if ($parentSpanContext->isRemote()) { + return $parentSpanContext->isSampled() + ? $this->remoteParentSampler->shouldSample(...func_get_args()) + : $this->remoteParentNotSampler->shouldSample(...func_get_args()); + } + + return $parentSpanContext->isSampled() + ? $this->localParentSampler->shouldSample(...func_get_args()) + : $this->localParentNotSampler->shouldSample(...func_get_args()); + } + + public function getDescription(): string + { + return 'ParentBased+' . $this->root->getDescription(); + } +} diff --git a/vendor/open-telemetry/sdk/Trace/Sampler/TraceIdRatioBasedSampler.php b/vendor/open-telemetry/sdk/Trace/Sampler/TraceIdRatioBasedSampler.php new file mode 100644 index 000000000..c11a90d5d --- /dev/null +++ b/vendor/open-telemetry/sdk/Trace/Sampler/TraceIdRatioBasedSampler.php @@ -0,0 +1,70 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Trace\Sampler; + +use InvalidArgumentException; +use OpenTelemetry\Context\ContextInterface; +use OpenTelemetry\SDK\Common\Attribute\AttributesInterface; +use OpenTelemetry\SDK\Trace\SamplerInterface; +use OpenTelemetry\SDK\Trace\SamplingResult; +use OpenTelemetry\SDK\Trace\Span; + +/** + * This implementation of the SamplerInterface records with given probability. + * Example: + * ``` + * use OpenTelemetry\API\Trace\TraceIdRatioBasedSampler; + * $sampler = new TraceIdRatioBasedSampler(0.01); + * ``` + */ +class TraceIdRatioBasedSampler implements SamplerInterface +{ + private float $probability; + + /** + * TraceIdRatioBasedSampler constructor. + * @param float $probability Probability float value between 0.0 and 1.0. + */ + public function __construct(float $probability) + { + if ($probability < 0.0 || $probability > 1.0) { + throw new InvalidArgumentException('probability should be be between 0.0 and 1.0.'); + } + $this->probability = $probability; + } + + /** + * Returns `SamplingResult` based on probability. Respects the parent `SampleFlag` + * {@inheritdoc} + */ + public function shouldSample( + ContextInterface $parentContext, + string $traceId, + string $spanName, + int $spanKind, + AttributesInterface $attributes, + array $links + ): SamplingResult { + // TODO: Add config to adjust which spans get sampled (only default from specification is implemented) + $parentSpan = Span::fromContext($parentContext); + $parentSpanContext = $parentSpan->getContext(); + $traceState = $parentSpanContext->getTraceState(); + + /** + * Since php can only store up to 63 bit positive integers + */ + $traceIdLimit = (1 << 60) - 1; + $lowerOrderBytes = hexdec(substr($traceId, strlen($traceId) - 15, 15)); + $traceIdCondition = $lowerOrderBytes < round($this->probability * $traceIdLimit); + $decision = $traceIdCondition ? SamplingResult::RECORD_AND_SAMPLE : SamplingResult::DROP; + + return new SamplingResult($decision, [], $traceState); + } + + public function getDescription(): string + { + return sprintf('%s{%.6F}', 'TraceIdRatioBasedSampler', $this->probability); + } +} diff --git a/vendor/open-telemetry/sdk/Trace/SamplerFactory.php b/vendor/open-telemetry/sdk/Trace/SamplerFactory.php new file mode 100644 index 000000000..f99674d79 --- /dev/null +++ b/vendor/open-telemetry/sdk/Trace/SamplerFactory.php @@ -0,0 +1,48 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Trace; + +use InvalidArgumentException; +use OpenTelemetry\SDK\Common\Configuration\Configuration; +use OpenTelemetry\SDK\Common\Configuration\KnownValues as Values; +use OpenTelemetry\SDK\Common\Configuration\Variables as Env; +use OpenTelemetry\SDK\Trace\Sampler\AlwaysOffSampler; +use OpenTelemetry\SDK\Trace\Sampler\AlwaysOnSampler; +use OpenTelemetry\SDK\Trace\Sampler\ParentBased; +use OpenTelemetry\SDK\Trace\Sampler\TraceIdRatioBasedSampler; + +class SamplerFactory +{ + private const TRACEIDRATIO_PREFIX = 'traceidratio'; + + public function create(): SamplerInterface + { + $name = Configuration::getString(Env::OTEL_TRACES_SAMPLER); + + if (strpos($name, self::TRACEIDRATIO_PREFIX) !== false) { + $arg = Configuration::getRatio(Env::OTEL_TRACES_SAMPLER_ARG); + + switch ($name) { + case Values::VALUE_TRACE_ID_RATIO: + return new TraceIdRatioBasedSampler($arg); + case Values::VALUE_PARENT_BASED_TRACE_ID_RATIO: + return new ParentBased(new TraceIdRatioBasedSampler($arg)); + } + } + + switch ($name) { + case Values::VALUE_ALWAYS_ON: + return new AlwaysOnSampler(); + case Values::VALUE_ALWAYS_OFF: + return new AlwaysOffSampler(); + case Values::VALUE_PARENT_BASED_ALWAYS_ON: + return new ParentBased(new AlwaysOnSampler()); + case Values::VALUE_PARENT_BASED_ALWAYS_OFF: + return new ParentBased(new AlwaysOffSampler()); + default: + throw new InvalidArgumentException(sprintf('Unknown sampler: %s', $name)); + } + } +} diff --git a/vendor/open-telemetry/sdk/Trace/SamplerInterface.php b/vendor/open-telemetry/sdk/Trace/SamplerInterface.php new file mode 100644 index 000000000..de1147fa6 --- /dev/null +++ b/vendor/open-telemetry/sdk/Trace/SamplerInterface.php @@ -0,0 +1,46 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Trace; + +use OpenTelemetry\Context\ContextInterface; +use OpenTelemetry\SDK\Common\Attribute\AttributesInterface; + +/** + * This interface is used to organize sampling logic. + * + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/sdk.md#sampler + */ +interface SamplerInterface +{ + /** + * Returns SamplingResult. + * + * @param ContextInterface $parentContext Context with parent Span. The Span's SpanContext may be invalid to indicate a root span. + * @param string $traceId TraceId of the Span to be created. It can be different from the TraceId in the SpanContext. + * Typically in situations when the Span to be created starts a new Trace. + * @param string $spanName Name of the Span to be created. + * @param int $spanKind Span kind. + * @param AttributesInterface $attributes Initial set of Attributes for the Span being constructed. + * @param list<LinkInterface> $links Collection of links that will be associated with the Span to be created. + * Typically, useful for batch operations. + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/overview.md#links-between-spans + * @return SamplingResult + */ + public function shouldSample( + ContextInterface $parentContext, + string $traceId, + string $spanName, + int $spanKind, + AttributesInterface $attributes, + array $links + ): SamplingResult; + + /** + * Returns the sampler name or short description with the configuration. + * This may be displayed on debug pages or in the logs. + * Example: "TraceIdRatioBasedSampler{0.000100}" + */ + public function getDescription(): string; +} diff --git a/vendor/open-telemetry/sdk/Trace/SamplingResult.php b/vendor/open-telemetry/sdk/Trace/SamplingResult.php new file mode 100644 index 000000000..5701b7bc6 --- /dev/null +++ b/vendor/open-telemetry/sdk/Trace/SamplingResult.php @@ -0,0 +1,71 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Trace; + +use OpenTelemetry\API\Trace as API; + +final class SamplingResult +{ + /** + * Span will not be recorded and all events and attributes will be dropped. + */ + public const DROP = 0; + + /** + * Span will be recorded but SpanExporters will not receive this Span. + */ + public const RECORD_ONLY = 1; + + /** + * Span will be recorder and exported. + */ + public const RECORD_AND_SAMPLE = 2; + + /** + * @var int A sampling Decision. + */ + private int $decision; + + /** + * @var iterable A set of span Attributes that will also be added to the Span. + */ + private iterable $attributes; + + /** + * @var ?API\TraceStateInterface A Tracestate that will be associated with the Span through the new SpanContext. + */ + private ?API\TraceStateInterface $traceState; + + public function __construct(int $decision, iterable $attributes = [], ?API\TraceStateInterface $traceState = null) + { + $this->decision = $decision; + $this->attributes = $attributes; + $this->traceState = $traceState; + } + + /** + * Return sampling decision whether span should be recorded or not. + */ + public function getDecision(): int + { + return $this->decision; + } + + /** + * Return attributes which will be attached to the span. + */ + public function getAttributes(): iterable + { + return $this->attributes; + } + + /** + * Return a collection of links that will be associated with the Span to be created. + */ + public function getTraceState(): ?API\TraceStateInterface + { + return $this->traceState; + } +} diff --git a/vendor/open-telemetry/sdk/Trace/Span.php b/vendor/open-telemetry/sdk/Trace/Span.php new file mode 100644 index 000000000..f72ec1bd7 --- /dev/null +++ b/vendor/open-telemetry/sdk/Trace/Span.php @@ -0,0 +1,359 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Trace; + +use function get_class; +use OpenTelemetry\API\Trace as API; +use OpenTelemetry\Context\ContextInterface; +use OpenTelemetry\SDK\Common\Attribute\AttributesBuilderInterface; +use OpenTelemetry\SDK\Common\Dev\Compatibility\Util as BcUtil; +use OpenTelemetry\SDK\Common\Exception\StackTraceFormatter; +use OpenTelemetry\SDK\Common\Instrumentation\InstrumentationScopeInterface; +use OpenTelemetry\SDK\Common\Time\ClockFactory; +use OpenTelemetry\SDK\Resource\ResourceInfo; +use Throwable; + +final class Span extends API\Span implements ReadWriteSpanInterface +{ + + /** @readonly */ + private API\SpanContextInterface $context; + + /** @readonly */ + private API\SpanContextInterface $parentSpanContext; + + /** @readonly */ + private SpanLimits $spanLimits; + + /** @readonly */ + private SpanProcessorInterface $spanProcessor; + + /** + * @readonly + * + * @var list<LinkInterface> + */ + private array $links; + + /** @readonly */ + private int $totalRecordedLinks; + + /** @readonly */ + private int $kind; + + /** @readonly */ + private ResourceInfo $resource; + + /** @readonly */ + private InstrumentationScopeInterface $instrumentationScope; + + /** @readonly */ + private int $startEpochNanos; + + /** @var non-empty-string */ + private string $name; + + /** @var list<EventInterface> */ + private array $events = []; + + private AttributesBuilderInterface $attributesBuilder; + private int $totalRecordedEvents = 0; + private StatusDataInterface $status; + private int $endEpochNanos = 0; + private bool $hasEnded = false; + + /** + * @param non-empty-string $name + * @param list<LinkInterface> $links + */ + private function __construct( + string $name, + API\SpanContextInterface $context, + InstrumentationScopeInterface $instrumentationScope, + int $kind, + API\SpanContextInterface $parentSpanContext, + SpanLimits $spanLimits, + SpanProcessorInterface $spanProcessor, + ResourceInfo $resource, + AttributesBuilderInterface $attributesBuilder, + array $links, + int $totalRecordedLinks, + int $startEpochNanos + ) { + $this->context = $context; + $this->instrumentationScope = $instrumentationScope; + $this->parentSpanContext = $parentSpanContext; + $this->links = $links; + $this->totalRecordedLinks = $totalRecordedLinks; + $this->name = $name; + $this->kind = $kind; + $this->spanProcessor = $spanProcessor; + $this->resource = $resource; + $this->startEpochNanos = $startEpochNanos; + $this->attributesBuilder = $attributesBuilder; + $this->status = StatusData::unset(); + $this->spanLimits = $spanLimits; + } + + /** + * This method _MUST_ not be used directly. + * End users should use a {@see API\TracerInterface} in order to create spans. + * + * @param non-empty-string $name + * @psalm-param API\SpanKind::KIND_* $kind + * @param list<LinkInterface> $links + * + * @internal + * @psalm-internal OpenTelemetry + */ + public static function startSpan( + string $name, + API\SpanContextInterface $context, + InstrumentationScopeInterface $instrumentationScope, + int $kind, + API\SpanInterface $parentSpan, + ContextInterface $parentContext, + SpanLimits $spanLimits, + SpanProcessorInterface $spanProcessor, + ResourceInfo $resource, + AttributesBuilderInterface $attributesBuilder, + array $links, + int $totalRecordedLinks, + int $startEpochNanos + ): self { + $span = new self( + $name, + $context, + $instrumentationScope, + $kind, + $parentSpan->getContext(), + $spanLimits, + $spanProcessor, + $resource, + $attributesBuilder, + $links, + $totalRecordedLinks, + $startEpochNanos !== 0 ? $startEpochNanos : ClockFactory::getDefault()->now() + ); + + // Call onStart here to ensure the span is fully initialized. + $spanProcessor->onStart($span, $parentContext); + + return $span; + } + + /** + * Backward compatibility methods + * + * @codeCoverageIgnore + */ + public static function formatStackTrace(Throwable $e, array &$seen = null): string + { + BcUtil::triggerMethodDeprecationNotice( + __METHOD__, + 'format', + StackTraceFormatter::class + ); + + return StackTraceFormatter::format($e); + } + + /** @inheritDoc */ + public function getContext(): API\SpanContextInterface + { + return $this->context; + } + + /** @inheritDoc */ + public function isRecording(): bool + { + return !$this->hasEnded; + } + + /** @inheritDoc */ + public function setAttribute(string $key, $value): self + { + if ($this->hasEnded) { + return $this; + } + + $this->attributesBuilder[$key] = $value; + + return $this; + } + + /** @inheritDoc */ + public function setAttributes(iterable $attributes): self + { + foreach ($attributes as $key => $value) { + $this->attributesBuilder[$key] = $value; + } + + return $this; + } + + /** @inheritDoc */ + public function addEvent(string $name, iterable $attributes = [], ?int $timestamp = null): self + { + if ($this->hasEnded) { + return $this; + } + if (++$this->totalRecordedEvents > $this->spanLimits->getEventCountLimit()) { + return $this; + } + + $timestamp ??= ClockFactory::getDefault()->now(); + $eventAttributesBuilder = $this->spanLimits->getEventAttributesFactory()->builder($attributes); + + $this->events[] = new Event($name, $timestamp, $eventAttributesBuilder->build()); + + return $this; + } + + /** @inheritDoc */ + public function recordException(Throwable $exception, iterable $attributes = [], ?int $timestamp = null): self + { + if ($this->hasEnded) { + return $this; + } + if (++$this->totalRecordedEvents > $this->spanLimits->getEventCountLimit()) { + return $this; + } + + $timestamp ??= ClockFactory::getDefault()->now(); + $eventAttributesBuilder = $this->spanLimits->getEventAttributesFactory()->builder([ + 'exception.type' => get_class($exception), + 'exception.message' => $exception->getMessage(), + 'exception.stacktrace' => StackTraceFormatter::format($exception), + ]); + + foreach ($attributes as $key => $value) { + $eventAttributesBuilder[$key] = $value; + } + + $this->events[] = new Event('exception', $timestamp, $eventAttributesBuilder->build()); + + return $this; + } + + /** @inheritDoc */ + public function updateName(string $name): self + { + if ($this->hasEnded) { + return $this; + } + $this->name = $name; + + return $this; + } + + /** @inheritDoc */ + public function setStatus(string $code, string $description = null): self + { + if ($this->hasEnded) { + return $this; + } + + // An attempt to set value Unset SHOULD be ignored. + if ($code === API\StatusCode::STATUS_UNSET) { + return $this; + } + + // When span status is set to Ok it SHOULD be considered final and any further attempts to change it SHOULD be ignored. + if ($this->status->getCode() === API\StatusCode::STATUS_OK) { + return $this; + } + $this->status = StatusData::create($code, $description); + + return $this; + } + + /** @inheritDoc */ + public function end(int $endEpochNanos = null): void + { + if ($this->hasEnded) { + return; + } + + $this->endEpochNanos = $endEpochNanos ?? ClockFactory::getDefault()->now(); + $this->hasEnded = true; + + $this->spanProcessor->onEnd($this); + } + + /** @inheritDoc */ + public function getName(): string + { + return $this->name; + } + + public function getParentContext(): API\SpanContextInterface + { + return $this->parentSpanContext; + } + + public function getInstrumentationScope(): InstrumentationScopeInterface + { + return $this->instrumentationScope; + } + + public function hasEnded(): bool + { + return $this->hasEnded; + } + + public function toSpanData(): SpanDataInterface + { + return new ImmutableSpan( + $this, + $this->name, + $this->links, + $this->events, + $this->attributesBuilder->build(), + $this->totalRecordedEvents, + $this->status, + $this->endEpochNanos, + $this->hasEnded + ); + } + + /** @inheritDoc */ + public function getDuration(): int + { + return ($this->hasEnded ? $this->endEpochNanos : ClockFactory::getDefault()->now()) - $this->startEpochNanos; + } + + /** @inheritDoc */ + public function getKind(): int + { + return $this->kind; + } + + /** @inheritDoc */ + public function getAttribute(string $key) + { + return $this->attributesBuilder[$key]; + } + + public function getStartEpochNanos(): int + { + return $this->startEpochNanos; + } + + public function getTotalRecordedLinks(): int + { + return $this->totalRecordedLinks; + } + + public function getTotalRecordedEvents(): int + { + return $this->totalRecordedEvents; + } + + public function getResource(): ResourceInfo + { + return $this->resource; + } +} diff --git a/vendor/open-telemetry/sdk/Trace/SpanBuilder.php b/vendor/open-telemetry/sdk/Trace/SpanBuilder.php new file mode 100644 index 000000000..2867c01c8 --- /dev/null +++ b/vendor/open-telemetry/sdk/Trace/SpanBuilder.php @@ -0,0 +1,191 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Trace; + +use function in_array; +use OpenTelemetry\API\Trace as API; +use OpenTelemetry\Context\Context; +use OpenTelemetry\Context\ContextInterface; +use OpenTelemetry\SDK\Common\Attribute\AttributesBuilderInterface; +use OpenTelemetry\SDK\Common\Instrumentation\InstrumentationScopeInterface; + +final class SpanBuilder implements API\SpanBuilderInterface +{ + /** + * @var non-empty-string + * @readonly + */ + private string $spanName; + + /** @readonly */ + private InstrumentationScopeInterface $instrumentationScope; + + /** @readonly */ + private TracerSharedState $tracerSharedState; + + /** @var ContextInterface|false|null */ + private $parentContext = null; + + /** + * @psalm-var API\SpanKind::KIND_* + */ + private int $spanKind = API\SpanKind::KIND_INTERNAL; + + /** @var list<LinkInterface> */ + private array $links = []; + + private AttributesBuilderInterface $attributesBuilder; + private int $totalNumberOfLinksAdded = 0; + private int $startEpochNanos = 0; + + /** @param non-empty-string $spanName */ + public function __construct( + string $spanName, + InstrumentationScopeInterface $instrumentationScope, + TracerSharedState $tracerSharedState + ) { + $this->spanName = $spanName; + $this->instrumentationScope = $instrumentationScope; + $this->tracerSharedState = $tracerSharedState; + $this->attributesBuilder = $tracerSharedState->getSpanLimits()->getAttributesFactory()->builder(); + } + + /** @inheritDoc */ + public function setParent($context): API\SpanBuilderInterface + { + $this->parentContext = $context; + + return $this; + } + + /** @inheritDoc */ + public function addLink(API\SpanContextInterface $context, iterable $attributes = []): API\SpanBuilderInterface + { + if (!$context->isValid()) { + return $this; + } + + $this->totalNumberOfLinksAdded++; + + if (count($this->links) === $this->tracerSharedState->getSpanLimits()->getLinkCountLimit()) { + return $this; + } + + $this->links[] = new Link( + $context, + $this->tracerSharedState + ->getSpanLimits() + ->getLinkAttributesFactory() + ->builder($attributes) + ->build(), + ); + + return $this; + } + + /** @inheritDoc */ + public function setAttribute(string $key, $value): API\SpanBuilderInterface + { + $this->attributesBuilder[$key] = $value; + + return $this; + } + + /** @inheritDoc */ + public function setAttributes(iterable $attributes): API\SpanBuilderInterface + { + foreach ($attributes as $key => $value) { + $this->attributesBuilder[$key] = $value; + } + + return $this; + } + + /** + * @inheritDoc + * + * @psalm-param API\SpanKind::KIND_* $spanKind + */ + public function setSpanKind(int $spanKind): API\SpanBuilderInterface + { + $this->spanKind = $spanKind; + + return $this; + } + + /** @inheritDoc */ + public function setStartTimestamp(int $timestampNanos): API\SpanBuilderInterface + { + if (0 > $timestampNanos) { + return $this; + } + + $this->startEpochNanos = $timestampNanos; + + return $this; + } + + /** @inheritDoc */ + public function startSpan(): API\SpanInterface + { + $parentContext = Context::resolve($this->parentContext); + $parentSpan = Span::fromContext($parentContext); + $parentSpanContext = $parentSpan->getContext(); + + $spanId = $this->tracerSharedState->getIdGenerator()->generateSpanId(); + + if (!$parentSpanContext->isValid()) { + $traceId = $this->tracerSharedState->getIdGenerator()->generateTraceId(); + } else { + $traceId = $parentSpanContext->getTraceId(); + } + + $samplingResult = $this + ->tracerSharedState + ->getSampler() + ->shouldSample( + $parentContext, + $traceId, + $this->spanName, + $this->spanKind, + $this->attributesBuilder->build(), + $this->links, + ); + $samplingDecision = $samplingResult->getDecision(); + $samplingResultTraceState = $samplingResult->getTraceState(); + + $spanContext = API\SpanContext::create( + $traceId, + $spanId, + SamplingResult::RECORD_AND_SAMPLE === $samplingDecision ? API\TraceFlags::SAMPLED : API\TraceFlags::DEFAULT, + $samplingResultTraceState, + ); + + if (!in_array($samplingDecision, [SamplingResult::RECORD_AND_SAMPLE, SamplingResult::RECORD_ONLY], true)) { + return Span::wrap($spanContext); + } + + $attributesBuilder = clone $this->attributesBuilder; + foreach ($samplingResult->getAttributes() as $key => $value) { + $attributesBuilder[$key] = $value; + } + + return Span::startSpan( + $this->spanName, + $spanContext, + $this->instrumentationScope, + $this->spanKind, + $parentSpan, + $parentContext, + $this->tracerSharedState->getSpanLimits(), + $this->tracerSharedState->getSpanProcessor(), + $this->tracerSharedState->getResource(), + $attributesBuilder, + $this->links, + $this->totalNumberOfLinksAdded, + $this->startEpochNanos + ); + } +} diff --git a/vendor/open-telemetry/sdk/Trace/SpanConverterInterface.php b/vendor/open-telemetry/sdk/Trace/SpanConverterInterface.php new file mode 100644 index 000000000..40552e440 --- /dev/null +++ b/vendor/open-telemetry/sdk/Trace/SpanConverterInterface.php @@ -0,0 +1,10 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Trace; + +interface SpanConverterInterface +{ + public function convert(iterable $spans): array; +} diff --git a/vendor/open-telemetry/sdk/Trace/SpanDataInterface.php b/vendor/open-telemetry/sdk/Trace/SpanDataInterface.php new file mode 100644 index 000000000..37132b9e5 --- /dev/null +++ b/vendor/open-telemetry/sdk/Trace/SpanDataInterface.php @@ -0,0 +1,46 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Trace; + +use OpenTelemetry\API\Trace as API; +use OpenTelemetry\SDK\Common\Attribute\AttributesInterface; +use OpenTelemetry\SDK\Common\Instrumentation\InstrumentationScopeInterface; +use OpenTelemetry\SDK\Resource\ResourceInfo; + +/** + * Represents an immutable snapshot of a {@see API\SpanInterface}. + * + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/v1.6.1/specification/trace/sdk.md#additional-span-interfaces + */ +interface SpanDataInterface +{ + public function getName(): string; + public function getKind(): int; + public function getContext(): API\SpanContextInterface; + public function getParentContext(): API\SpanContextInterface; + public function getTraceId(): string; + public function getSpanId(): string; + public function getParentSpanId(): string; + public function getStatus(): StatusDataInterface; + public function getStartEpochNanos(): int; + public function getAttributes(): AttributesInterface; + + /** @return list<EventInterface> */ + public function getEvents(): array; + + /** @return list<LinkInterface> */ + public function getLinks(): array; + + public function getEndEpochNanos(): int; + public function hasEnded(): bool; + public function getInstrumentationScope(): InstrumentationScopeInterface; + public function getResource(): ResourceInfo; + + /** @see https://github.com/open-telemetry/opentelemetry-specification/blob/v1.6.1/specification/trace/sdk_exporters/non-otlp.md#dropped-events-count */ + public function getTotalDroppedEvents(): int; + + /** @see https://github.com/open-telemetry/opentelemetry-specification/blob/v1.6.1/specification/trace/sdk_exporters/non-otlp.md#dropped-links-count */ + public function getTotalDroppedLinks(): int; +} diff --git a/vendor/open-telemetry/sdk/Trace/SpanExporter/AbstractDecorator.php b/vendor/open-telemetry/sdk/Trace/SpanExporter/AbstractDecorator.php new file mode 100644 index 000000000..42f49e815 --- /dev/null +++ b/vendor/open-telemetry/sdk/Trace/SpanExporter/AbstractDecorator.php @@ -0,0 +1,12 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Trace\SpanExporter; + +use OpenTelemetry\SDK\Trace\Behavior\SpanExporterDecoratorTrait; + +abstract class AbstractDecorator +{ + use SpanExporterDecoratorTrait; +} diff --git a/vendor/open-telemetry/sdk/Trace/SpanExporter/ConsoleSpanExporter.php b/vendor/open-telemetry/sdk/Trace/SpanExporter/ConsoleSpanExporter.php new file mode 100644 index 000000000..482d122cc --- /dev/null +++ b/vendor/open-telemetry/sdk/Trace/SpanExporter/ConsoleSpanExporter.php @@ -0,0 +1,57 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Trace\SpanExporter; + +use JsonException; +use OpenTelemetry\API\Behavior\LogsMessagesTrait; +use OpenTelemetry\SDK\Common\Export\TransportInterface; +use OpenTelemetry\SDK\Common\Future\CancellationInterface; +use OpenTelemetry\SDK\Common\Future\FutureInterface; +use OpenTelemetry\SDK\Trace\Behavior\UsesSpanConverterTrait; +use OpenTelemetry\SDK\Trace\SpanConverterInterface; +use OpenTelemetry\SDK\Trace\SpanExporterInterface; + +class ConsoleSpanExporter implements SpanExporterInterface +{ + use UsesSpanConverterTrait; + use LogsMessagesTrait; + + private TransportInterface $transport; + + public function __construct(TransportInterface $transport, ?SpanConverterInterface $converter = null) + { + $this->transport = $transport; + $this->setSpanConverter($converter ?? new FriendlySpanConverter()); + } + + public function export(iterable $batch, ?CancellationInterface $cancellation = null): FutureInterface + { + $payload = ''; + foreach ($batch as $span) { + try { + $payload .= json_encode( + $this->getSpanConverter()->convert([$span]), + JSON_THROW_ON_ERROR | JSON_PRETTY_PRINT + ) . PHP_EOL; + } catch (JsonException $e) { + self::logWarning('Error converting span: ' . $e->getMessage()); + } + } + + return $this->transport->send($payload) + ->map(fn () => true) + ->catch(fn () => false); + } + + public function shutdown(?CancellationInterface $cancellation = null): bool + { + return $this->transport->shutdown(); + } + + public function forceFlush(?CancellationInterface $cancellation = null): bool + { + return $this->transport->forceFlush(); + } +} diff --git a/vendor/open-telemetry/sdk/Trace/SpanExporter/ConsoleSpanExporterFactory.php b/vendor/open-telemetry/sdk/Trace/SpanExporter/ConsoleSpanExporterFactory.php new file mode 100644 index 000000000..7e45fb549 --- /dev/null +++ b/vendor/open-telemetry/sdk/Trace/SpanExporter/ConsoleSpanExporterFactory.php @@ -0,0 +1,18 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Trace\SpanExporter; + +use OpenTelemetry\SDK\Registry; +use OpenTelemetry\SDK\Trace\SpanExporterInterface; + +class ConsoleSpanExporterFactory implements SpanExporterFactoryInterface +{ + public function create(): SpanExporterInterface + { + $transport = Registry::transportFactory('stream')->create('php://stdout', 'application/json'); + + return new ConsoleSpanExporter($transport); + } +} diff --git a/vendor/open-telemetry/sdk/Trace/SpanExporter/FriendlySpanConverter.php b/vendor/open-telemetry/sdk/Trace/SpanExporter/FriendlySpanConverter.php new file mode 100644 index 000000000..1f8178e10 --- /dev/null +++ b/vendor/open-telemetry/sdk/Trace/SpanExporter/FriendlySpanConverter.php @@ -0,0 +1,173 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Trace\SpanExporter; + +use OpenTelemetry\API\Trace\SpanContextInterface; +use OpenTelemetry\API\Trace\SpanKind; +use OpenTelemetry\SDK\Common\Attribute\AttributesInterface; +use OpenTelemetry\SDK\Resource\ResourceInfo; +use OpenTelemetry\SDK\Trace\EventInterface; +use OpenTelemetry\SDK\Trace\LinkInterface; +use OpenTelemetry\SDK\Trace\SpanConverterInterface; +use OpenTelemetry\SDK\Trace\SpanDataInterface; +use OpenTelemetry\SDK\Trace\StatusDataInterface; +use ReflectionClass; + +class FriendlySpanConverter implements SpanConverterInterface +{ + private const NAME_ATTR = 'name'; + private const CONTEXT_ATTR = 'context'; + private const TRACE_ID_ATTR = 'trace_id'; + private const SPAN_ID_ATTR = 'span_id'; + private const TRACE_STATE_ATTR = 'trace_state'; + private const RESOURCE_ATTR = 'resource'; + private const PARENT_SPAN_ATTR = 'parent_span_id'; + private const KIND_ATTR = 'kind'; + private const START_ATTR = 'start'; + private const END_ATTR = 'end'; + private const ATTRIBUTES_ATTR = 'attributes'; + private const STATUS_ATTR = 'status'; + private const CODE_ATTR = 'code'; + private const DESCRIPTION_ATTR = 'description'; + private const EVENTS_ATTR = 'events'; + private const TIMESTAMP_ATTR = 'timestamp'; + private const LINKS_ATTR = 'links'; + + public function convert(iterable $spans): array + { + $aggregate = []; + foreach ($spans as $span) { + $aggregate[] = $this->convertSpan($span); + } + + return $aggregate; + } + + /** + * friendlySpan does the heavy lifting converting a span into an array + * + * @param SpanDataInterface $span + * @return array + */ + private function convertSpan(SpanDataInterface $span): array + { + return [ + self::NAME_ATTR => $span->getName(), + self::CONTEXT_ATTR => $this->convertContext($span->getContext()), + self::RESOURCE_ATTR => $this->convertResource($span->getResource()), + self::PARENT_SPAN_ATTR => $this->covertParentContext($span->getParentContext()), + self::KIND_ATTR => $this->convertKind($span->getKind()), + self::START_ATTR => $span->getStartEpochNanos(), + self::END_ATTR => $span->getEndEpochNanos(), + self::ATTRIBUTES_ATTR => $this->convertAttributes($span->getAttributes()), + self::STATUS_ATTR => $this->covertStatus($span->getStatus()), + self::EVENTS_ATTR => $this->convertEvents($span->getEvents()), + self::LINKS_ATTR => $this->convertLinks($span->getLinks()), + ]; + } + + /** + * @param SpanContextInterface $context + * @return array + */ + private function convertContext(SpanContextInterface $context): array + { + return [ + self::TRACE_ID_ATTR => $context->getTraceId(), + self::SPAN_ID_ATTR => $context->getSpanId(), + self::TRACE_STATE_ATTR => (string) $context->getTraceState(), + ]; + } + + /** + * @param ResourceInfo $resource + * @return array + */ + private function convertResource(ResourceInfo $resource): array + { + return $resource->getAttributes()->toArray(); + } + + /** + * @param SpanContextInterface $context + * @return string + */ + private function covertParentContext(SpanContextInterface $context): string + { + return $context->isValid() ? $context->getSpanId() : ''; + } + + /** + * Translates SpanKind from its integer representation to a more human friendly string. + * + * @param int $kind + * @return string + */ + private function convertKind(int $kind): string + { + return array_flip( + (new ReflectionClass(SpanKind::class)) + ->getConstants() + )[$kind]; + } + + /** + * @param \OpenTelemetry\SDK\Common\Attribute\AttributesInterface $attributes + * @return array + */ + private function convertAttributes(AttributesInterface $attributes): array + { + return $attributes->toArray(); + } + + /** + * @param StatusDataInterface $status + * @return array + */ + private function covertStatus(StatusDataInterface $status): array + { + return [ + self::CODE_ATTR => $status->getCode(), + self::DESCRIPTION_ATTR => $status->getDescription(), + ]; + } + + /** + * @param array<EventInterface> $events + * @return array + */ + private function convertEvents(array $events): array + { + $result = []; + + foreach ($events as $event) { + $result[] = [ + self::NAME_ATTR => $event->getName(), + self::TIMESTAMP_ATTR => $event->getEpochNanos(), + self::ATTRIBUTES_ATTR => $this->convertAttributes($event->getAttributes()), + ]; + } + + return $result; + } + + /** + * @param array<LinkInterface> $links + * @return array + */ + private function convertLinks(array $links): array + { + $result = []; + + foreach ($links as $link) { + $result[] = [ + self::CONTEXT_ATTR => $this->convertContext($link->getSpanContext()), + self::ATTRIBUTES_ATTR => $this->convertAttributes($link->getAttributes()), + ]; + } + + return $result; + } +} diff --git a/vendor/open-telemetry/sdk/Trace/SpanExporter/InMemoryExporter.php b/vendor/open-telemetry/sdk/Trace/SpanExporter/InMemoryExporter.php new file mode 100644 index 000000000..ebb022595 --- /dev/null +++ b/vendor/open-telemetry/sdk/Trace/SpanExporter/InMemoryExporter.php @@ -0,0 +1,40 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Trace\SpanExporter; + +use ArrayObject; +use OpenTelemetry\SDK\Trace\Behavior\SpanExporterTrait; +use OpenTelemetry\SDK\Trace\SpanExporterInterface; + +class InMemoryExporter implements SpanExporterInterface +{ + use SpanExporterTrait; + + private ArrayObject $storage; + + public function __construct(?ArrayObject $storage = null) + { + $this->storage = $storage ?? new ArrayObject(); + } + + protected function doExport(iterable $spans): bool + { + foreach ($spans as $span) { + $this->storage[] = $span; + } + + return true; + } + + public function getSpans(): array + { + return (array) $this->storage; + } + + public function getStorage(): ArrayObject + { + return $this->storage; + } +} diff --git a/vendor/open-telemetry/sdk/Trace/SpanExporter/InMemorySpanExporterFactory.php b/vendor/open-telemetry/sdk/Trace/SpanExporter/InMemorySpanExporterFactory.php new file mode 100644 index 000000000..c19686fac --- /dev/null +++ b/vendor/open-telemetry/sdk/Trace/SpanExporter/InMemorySpanExporterFactory.php @@ -0,0 +1,15 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Trace\SpanExporter; + +use OpenTelemetry\SDK\Trace\SpanExporterInterface; + +class InMemorySpanExporterFactory implements SpanExporterFactoryInterface +{ + public function create(): SpanExporterInterface + { + return new InMemoryExporter(); + } +} diff --git a/vendor/open-telemetry/sdk/Trace/SpanExporter/LoggerDecorator.php b/vendor/open-telemetry/sdk/Trace/SpanExporter/LoggerDecorator.php new file mode 100644 index 000000000..b7cf511a5 --- /dev/null +++ b/vendor/open-telemetry/sdk/Trace/SpanExporter/LoggerDecorator.php @@ -0,0 +1,58 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Trace\SpanExporter; + +use OpenTelemetry\SDK\Trace\Behavior\LoggerAwareTrait; +use OpenTelemetry\SDK\Trace\Behavior\SpanExporterDecoratorTrait; +use OpenTelemetry\SDK\Trace\Behavior\UsesSpanConverterTrait; +use OpenTelemetry\SDK\Trace\SpanConverterInterface; +use OpenTelemetry\SDK\Trace\SpanExporterInterface; +use Psr\Log\LoggerAwareInterface; +use Psr\Log\LoggerInterface; +use Psr\Log\LogLevel; +use Psr\Log\NullLogger; + +class LoggerDecorator implements SpanExporterInterface, LoggerAwareInterface +{ + use SpanExporterDecoratorTrait; + use UsesSpanConverterTrait; + use LoggerAwareTrait; + + public function __construct( + SpanExporterInterface $decorated, + ?LoggerInterface $logger = null, + ?SpanConverterInterface $converter = null + ) { + $this->setDecorated($decorated); + $this->setLogger($logger ?? new NullLogger()); + $this->setSpanConverter($converter ?? new FriendlySpanConverter()); + } + + protected function beforeExport(iterable $spans): iterable + { + return $spans; + } + + /** + * @param iterable $spans + * @param bool $exportSuccess + */ + protected function afterExport(iterable $spans, bool $exportSuccess): void + { + if ($exportSuccess) { + $this->log( + 'Status Success', + $this->getSpanConverter()->convert($spans), + LogLevel::INFO, + ); + } else { + $this->log( + 'Status Failed Retryable', + $this->getSpanConverter()->convert($spans), + LogLevel::ERROR, + ); + } + } +} diff --git a/vendor/open-telemetry/sdk/Trace/SpanExporter/LoggerExporter.php b/vendor/open-telemetry/sdk/Trace/SpanExporter/LoggerExporter.php new file mode 100644 index 000000000..1969a5426 --- /dev/null +++ b/vendor/open-telemetry/sdk/Trace/SpanExporter/LoggerExporter.php @@ -0,0 +1,96 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Trace\SpanExporter; + +use OpenTelemetry\SDK\Trace\Behavior\LoggerAwareTrait; +use OpenTelemetry\SDK\Trace\Behavior\SpanExporterTrait; +use OpenTelemetry\SDK\Trace\Behavior\UsesSpanConverterTrait; +use OpenTelemetry\SDK\Trace\SpanConverterInterface; +use OpenTelemetry\SDK\Trace\SpanExporterInterface; +use Psr\Log\LoggerAwareInterface; +use Psr\Log\LoggerInterface; +use Psr\Log\LogLevel; +use Psr\Log\NullLogger; +use Throwable; + +class LoggerExporter implements SpanExporterInterface, LoggerAwareInterface +{ + use SpanExporterTrait; + use UsesSpanConverterTrait; + use LoggerAwareTrait; + + public const GRANULARITY_AGGREGATE = 1; + public const GRANULARITY_SPAN = 2; + + private string $serviceName; + private int $granularity = self::GRANULARITY_AGGREGATE; + + /** + * @param string $serviceName + * @param LoggerInterface|null $logger + * @param string|null $defaultLogLevel + * @param SpanConverterInterface|null $converter + * @param int $granularity + */ + public function __construct( + string $serviceName, + ?LoggerInterface $logger = null, + ?string $defaultLogLevel = LogLevel::DEBUG, + ?SpanConverterInterface $converter = null, + int $granularity = 1 + ) { + $this->setServiceName($serviceName); + $this->setLogger($logger ?? new NullLogger()); + $this->setDefaultLogLevel($defaultLogLevel ?? LogLevel::DEBUG); + $this->setSpanConverter($converter ?? new FriendlySpanConverter()); + $this->setGranularity($granularity); + } + + /** @inheritDoc */ + public function doExport(iterable $spans): bool + { + try { + $this->doLog($spans); + } catch (Throwable $t) { + return false; + } + + return true; + } + + /** + * @param string $serviceName + */ + private function setServiceName(string $serviceName): void + { + $this->serviceName = $serviceName; + } + + /** + * @param int $granularity + */ + public function setGranularity(int $granularity): void + { + $this->granularity = $granularity === self::GRANULARITY_SPAN + ? self::GRANULARITY_SPAN + : self::GRANULARITY_AGGREGATE; + } + + /** + * @param iterable $spans + */ + private function doLog(iterable $spans): void + { + if ($this->granularity === self::GRANULARITY_AGGREGATE) { + $this->log($this->serviceName, $this->getSpanConverter()->convert($spans)); + + return; + } + + foreach ($spans as $span) { + $this->log($this->serviceName, $this->getSpanConverter()->convert([$span])); + } + } +} diff --git a/vendor/open-telemetry/sdk/Trace/SpanExporter/NullSpanConverter.php b/vendor/open-telemetry/sdk/Trace/SpanExporter/NullSpanConverter.php new file mode 100644 index 000000000..1e55431a8 --- /dev/null +++ b/vendor/open-telemetry/sdk/Trace/SpanExporter/NullSpanConverter.php @@ -0,0 +1,15 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Trace\SpanExporter; + +use OpenTelemetry\SDK\Trace\SpanConverterInterface; + +class NullSpanConverter implements SpanConverterInterface +{ + public function convert(iterable $spans): array + { + return [[]]; + } +} diff --git a/vendor/open-telemetry/sdk/Trace/SpanExporter/SpanExporterFactoryInterface.php b/vendor/open-telemetry/sdk/Trace/SpanExporter/SpanExporterFactoryInterface.php new file mode 100644 index 000000000..8d44b35eb --- /dev/null +++ b/vendor/open-telemetry/sdk/Trace/SpanExporter/SpanExporterFactoryInterface.php @@ -0,0 +1,12 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Trace\SpanExporter; + +use OpenTelemetry\SDK\Trace\SpanExporterInterface; + +interface SpanExporterFactoryInterface +{ + public function create(): SpanExporterInterface; +} diff --git a/vendor/open-telemetry/sdk/Trace/SpanExporter/_register.php b/vendor/open-telemetry/sdk/Trace/SpanExporter/_register.php new file mode 100644 index 000000000..aad07be42 --- /dev/null +++ b/vendor/open-telemetry/sdk/Trace/SpanExporter/_register.php @@ -0,0 +1,7 @@ +<?php + +declare(strict_types=1); +\OpenTelemetry\SDK\Registry::registerSpanExporterFactory('console', \OpenTelemetry\SDK\Trace\SpanExporter\ConsoleSpanExporterFactory::class); +\OpenTelemetry\SDK\Registry::registerSpanExporterFactory('memory', \OpenTelemetry\SDK\Trace\SpanExporter\InMemorySpanExporterFactory::class); + +\OpenTelemetry\SDK\Registry::registerTransportFactory('stream', \OpenTelemetry\SDK\Common\Export\Stream\StreamTransportFactory::class); diff --git a/vendor/open-telemetry/sdk/Trace/SpanExporterInterface.php b/vendor/open-telemetry/sdk/Trace/SpanExporterInterface.php new file mode 100644 index 000000000..fca336896 --- /dev/null +++ b/vendor/open-telemetry/sdk/Trace/SpanExporterInterface.php @@ -0,0 +1,29 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Trace; + +use OpenTelemetry\SDK\Common\Future\CancellationInterface; +use OpenTelemetry\SDK\Common\Future\FutureInterface; + +/** + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/v1.7.0/specification/trace/sdk.md#span-exporter + */ +interface SpanExporterInterface +{ + /** + * @param iterable<SpanDataInterface> $batch Batch of spans to export + * + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/v1.7.0/specification/trace/sdk.md#exportbatch + * + * @psalm-return FutureInterface<bool> + */ + public function export(iterable $batch, ?CancellationInterface $cancellation = null): FutureInterface; + + /** @see https://github.com/open-telemetry/opentelemetry-specification/blob/v1.7.0/specification/trace/sdk.md#shutdown-2 */ + public function shutdown(?CancellationInterface $cancellation = null): bool; + + /** @see https://github.com/open-telemetry/opentelemetry-specification/blob/v1.7.0/specification/trace/sdk.md#forceflush-2 */ + public function forceFlush(?CancellationInterface $cancellation = null): bool; +} diff --git a/vendor/open-telemetry/sdk/Trace/SpanLimits.php b/vendor/open-telemetry/sdk/Trace/SpanLimits.php new file mode 100644 index 000000000..4b07649fc --- /dev/null +++ b/vendor/open-telemetry/sdk/Trace/SpanLimits.php @@ -0,0 +1,67 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Trace; + +use OpenTelemetry\SDK\Common\Attribute\AttributesFactoryInterface; + +final class SpanLimits +{ + public const DEFAULT_SPAN_ATTRIBUTE_LENGTH_LIMIT = PHP_INT_MAX; + public const DEFAULT_SPAN_ATTRIBUTE_COUNT_LIMIT = 128; + public const DEFAULT_SPAN_EVENT_COUNT_LIMIT = 128; + public const DEFAULT_SPAN_LINK_COUNT_LIMIT = 128; + public const DEFAULT_EVENT_ATTRIBUTE_COUNT_LIMIT = 128; + public const DEFAULT_LINK_ATTRIBUTE_COUNT_LIMIT = 128; + + private AttributesFactoryInterface $attributesFactory; + private AttributesFactoryInterface $eventAttributesFactory; + private AttributesFactoryInterface $linkAttributesFactory; + private int $eventCountLimit; + private int $linkCountLimit; + + public function getAttributesFactory(): AttributesFactoryInterface + { + return $this->attributesFactory; + } + + public function getEventAttributesFactory(): AttributesFactoryInterface + { + return $this->eventAttributesFactory; + } + + public function getLinkAttributesFactory(): AttributesFactoryInterface + { + return $this->linkAttributesFactory; + } + + /** @return int Maximum allowed span event count */ + public function getEventCountLimit(): int + { + return $this->eventCountLimit; + } + + /** @return int Maximum allowed span link count */ + public function getLinkCountLimit(): int + { + return $this->linkCountLimit; + } + + /** + * @internal Use {@see SpanLimitsBuilder} to create {@see SpanLimits} instance. + */ + public function __construct( + AttributesFactoryInterface $attributesFactory, + AttributesFactoryInterface $eventAttributesFactory, + AttributesFactoryInterface $linkAttributesFactory, + int $eventCountLimit, + int $linkCountLimit + ) { + $this->attributesFactory = $attributesFactory; + $this->eventAttributesFactory = $eventAttributesFactory; + $this->linkAttributesFactory = $linkAttributesFactory; + $this->eventCountLimit = $eventCountLimit; + $this->linkCountLimit = $linkCountLimit; + } +} diff --git a/vendor/open-telemetry/sdk/Trace/SpanLimitsBuilder.php b/vendor/open-telemetry/sdk/Trace/SpanLimitsBuilder.php new file mode 100644 index 000000000..11ed5a82b --- /dev/null +++ b/vendor/open-telemetry/sdk/Trace/SpanLimitsBuilder.php @@ -0,0 +1,148 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Trace; + +use OpenTelemetry\SDK\Common\Attribute\Attributes; +use OpenTelemetry\SDK\Common\Attribute\FilteredAttributesFactory; +use OpenTelemetry\SDK\Common\Configuration\Configuration; +use OpenTelemetry\SDK\Common\Configuration\Variables as Env; +use OpenTelemetry\SemConv\TraceAttributes; +use const PHP_INT_MAX; + +class SpanLimitsBuilder +{ + /** @var ?int Maximum allowed attribute count per record */ + private ?int $attributeCountLimit = null; + + /** @var ?int Maximum allowed attribute value length */ + private ?int $attributeValueLengthLimit = null; + + /** @var ?int Maximum allowed span event count */ + private ?int $eventCountLimit = null; + + /** @var ?int Maximum allowed span link count */ + private ?int $linkCountLimit = null; + + /** @var ?int Maximum allowed attribute per span event count */ + private ?int $attributePerEventCountLimit = null; + + /** @var ?int Maximum allowed attribute per span link count */ + private ?int $attributePerLinkCountLimit = null; + + private bool $retainGeneralIdentityAttributes = false; + + /** + * @param int $attributeCountLimit Maximum allowed attribute count per record + */ + public function setAttributeCountLimit(int $attributeCountLimit): SpanLimitsBuilder + { + $this->attributeCountLimit = $attributeCountLimit; + + return $this; + } + + /** + * @param int $attributeValueLengthLimit Maximum allowed attribute value length + */ + public function setAttributeValueLengthLimit(int $attributeValueLengthLimit): SpanLimitsBuilder + { + $this->attributeValueLengthLimit = $attributeValueLengthLimit; + + return $this; + } + + /** + * @param int $eventCountLimit Maximum allowed span event count + */ + public function setEventCountLimit(int $eventCountLimit): SpanLimitsBuilder + { + $this->eventCountLimit = $eventCountLimit; + + return $this; + } + + /** + * @param int $linkCountLimit Maximum allowed span link count + */ + public function setLinkCountLimit(int $linkCountLimit): SpanLimitsBuilder + { + $this->linkCountLimit = $linkCountLimit; + + return $this; + } + + /** + * @param int $attributePerEventCountLimit Maximum allowed attribute per span event count + */ + public function setAttributePerEventCountLimit(int $attributePerEventCountLimit): SpanLimitsBuilder + { + $this->attributePerEventCountLimit = $attributePerEventCountLimit; + + return $this; + } + + /** + * @param int $attributePerLinkCountLimit Maximum allowed attribute per span link count + */ + public function setAttributePerLinkCountLimit(int $attributePerLinkCountLimit): SpanLimitsBuilder + { + $this->attributePerLinkCountLimit = $attributePerLinkCountLimit; + + return $this; + } + + /** + * @param bool $retain whether general identity attributes should be retained + * + * @see https://github.com/open-telemetry/semantic-conventions/blob/main/docs/general/attributes.md#general-identity-attributes + */ + public function retainGeneralIdentityAttributes(bool $retain = true): SpanLimitsBuilder + { + $this->retainGeneralIdentityAttributes = $retain; + + return $this; + } + + /** + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/configuration/sdk-environment-variables.md#span-limits + */ + public function build(): SpanLimits + { + $attributeCountLimit = $this->attributeCountLimit + ?: Configuration::getInt(Env::OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT, SpanLimits::DEFAULT_SPAN_ATTRIBUTE_COUNT_LIMIT); + $attributeValueLengthLimit = $this->attributeValueLengthLimit + ?: Configuration::getInt(Env::OTEL_SPAN_ATTRIBUTE_VALUE_LENGTH_LIMIT, SpanLimits::DEFAULT_SPAN_ATTRIBUTE_LENGTH_LIMIT); + $eventCountLimit = $this->eventCountLimit + ?: Configuration::getInt(Env::OTEL_SPAN_EVENT_COUNT_LIMIT, SpanLimits::DEFAULT_SPAN_EVENT_COUNT_LIMIT); + $linkCountLimit = $this->linkCountLimit + ?: Configuration::getInt(Env::OTEL_SPAN_LINK_COUNT_LIMIT, SpanLimits::DEFAULT_SPAN_LINK_COUNT_LIMIT); + $attributePerEventCountLimit = $this->attributePerEventCountLimit + ?: Configuration::getInt(Env::OTEL_EVENT_ATTRIBUTE_COUNT_LIMIT, SpanLimits::DEFAULT_EVENT_ATTRIBUTE_COUNT_LIMIT); + $attributePerLinkCountLimit = $this->attributePerLinkCountLimit + ?: Configuration::getInt(Env::OTEL_LINK_ATTRIBUTE_COUNT_LIMIT, SpanLimits::DEFAULT_LINK_ATTRIBUTE_COUNT_LIMIT); + + if ($attributeValueLengthLimit === PHP_INT_MAX) { + $attributeValueLengthLimit = null; + } + + $spanAttributesFactory = Attributes::factory($attributeCountLimit, $attributeValueLengthLimit); + + if (!$this->retainGeneralIdentityAttributes) { + $spanAttributesFactory = new FilteredAttributesFactory($spanAttributesFactory, [ + TraceAttributes::ENDUSER_ID, + TraceAttributes::ENDUSER_ROLE, + TraceAttributes::ENDUSER_SCOPE, + ]); + } + + return new SpanLimits( + $spanAttributesFactory, + Attributes::factory($attributePerEventCountLimit, $attributeValueLengthLimit), + Attributes::factory($attributePerLinkCountLimit, $attributeValueLengthLimit), + $eventCountLimit, + $linkCountLimit, + ); + } +} diff --git a/vendor/open-telemetry/sdk/Trace/SpanProcessor/BatchSpanProcessor.php b/vendor/open-telemetry/sdk/Trace/SpanProcessor/BatchSpanProcessor.php new file mode 100644 index 000000000..58032749e --- /dev/null +++ b/vendor/open-telemetry/sdk/Trace/SpanProcessor/BatchSpanProcessor.php @@ -0,0 +1,290 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Trace\SpanProcessor; + +use function assert; +use function count; +use InvalidArgumentException; +use OpenTelemetry\API\Behavior\LogsMessagesTrait; +use OpenTelemetry\API\Metrics\MeterProviderInterface; +use OpenTelemetry\API\Metrics\ObserverInterface; +use OpenTelemetry\Context\Context; +use OpenTelemetry\Context\ContextInterface; +use OpenTelemetry\SDK\Common\Future\CancellationInterface; +use OpenTelemetry\SDK\Common\Time\ClockInterface; +use OpenTelemetry\SDK\Trace\ReadableSpanInterface; +use OpenTelemetry\SDK\Trace\ReadWriteSpanInterface; +use OpenTelemetry\SDK\Trace\SpanDataInterface; +use OpenTelemetry\SDK\Trace\SpanExporterInterface; +use OpenTelemetry\SDK\Trace\SpanProcessorInterface; +use SplQueue; +use function sprintf; +use Throwable; + +class BatchSpanProcessor implements SpanProcessorInterface +{ + use LogsMessagesTrait; + + public const DEFAULT_SCHEDULE_DELAY = 5000; + public const DEFAULT_EXPORT_TIMEOUT = 30000; + public const DEFAULT_MAX_QUEUE_SIZE = 2048; + public const DEFAULT_MAX_EXPORT_BATCH_SIZE = 512; + + private const ATTRIBUTES_PROCESSOR = ['processor' => 'batching']; + private const ATTRIBUTES_QUEUED = self::ATTRIBUTES_PROCESSOR + ['state' => 'queued']; + private const ATTRIBUTES_PENDING = self::ATTRIBUTES_PROCESSOR + ['state' => 'pending']; + private const ATTRIBUTES_PROCESSED = self::ATTRIBUTES_PROCESSOR + ['state' => 'processed']; + private const ATTRIBUTES_DROPPED = self::ATTRIBUTES_PROCESSOR + ['state' => 'dropped']; + private const ATTRIBUTES_FREE = self::ATTRIBUTES_PROCESSOR + ['state' => 'free']; + + private SpanExporterInterface $exporter; + private ClockInterface $clock; + private int $maxQueueSize; + private int $scheduledDelayNanos; + private int $maxExportBatchSize; + private bool $autoFlush; + private ContextInterface $exportContext; + + private ?int $nextScheduledRun = null; + private bool $running = false; + private int $dropped = 0; + private int $processed = 0; + private int $batchId = 0; + private int $queueSize = 0; + /** @var list<SpanDataInterface> */ + private array $batch = []; + /** @var SplQueue<list<SpanDataInterface>> */ + private SplQueue $queue; + /** @var SplQueue<array{int, string, ?CancellationInterface, bool, ContextInterface}> */ + private SplQueue $flush; + + private bool $closed = false; + + public function __construct( + SpanExporterInterface $exporter, + ClockInterface $clock, + int $maxQueueSize = self::DEFAULT_MAX_QUEUE_SIZE, + int $scheduledDelayMillis = self::DEFAULT_SCHEDULE_DELAY, + int $exportTimeoutMillis = self::DEFAULT_EXPORT_TIMEOUT, + int $maxExportBatchSize = self::DEFAULT_MAX_EXPORT_BATCH_SIZE, + bool $autoFlush = true, + ?MeterProviderInterface $meterProvider = null + ) { + if ($maxQueueSize <= 0) { + throw new InvalidArgumentException(sprintf('Maximum queue size (%d) must be greater than zero', $maxQueueSize)); + } + if ($scheduledDelayMillis <= 0) { + throw new InvalidArgumentException(sprintf('Scheduled delay (%d) must be greater than zero', $scheduledDelayMillis)); + } + if ($exportTimeoutMillis <= 0) { + throw new InvalidArgumentException(sprintf('Export timeout (%d) must be greater than zero', $exportTimeoutMillis)); + } + if ($maxExportBatchSize <= 0) { + throw new InvalidArgumentException(sprintf('Maximum export batch size (%d) must be greater than zero', $maxExportBatchSize)); + } + if ($maxExportBatchSize > $maxQueueSize) { + throw new InvalidArgumentException(sprintf('Maximum export batch size (%d) must be less than or equal to maximum queue size (%d)', $maxExportBatchSize, $maxQueueSize)); + } + + $this->exporter = $exporter; + $this->clock = $clock; + $this->maxQueueSize = $maxQueueSize; + $this->scheduledDelayNanos = $scheduledDelayMillis * 1_000_000; + $this->maxExportBatchSize = $maxExportBatchSize; + $this->autoFlush = $autoFlush; + + $this->exportContext = Context::getCurrent(); + $this->queue = new SplQueue(); + $this->flush = new SplQueue(); + + if ($meterProvider === null) { + return; + } + + $meter = $meterProvider->getMeter('io.opentelemetry.sdk'); + $meter + ->createObservableUpDownCounter( + 'otel.trace.span_processor.spans', + '{spans}', + 'The number of sampled spans received by the span processor', + ) + ->observe(function (ObserverInterface $observer): void { + $queued = $this->queue->count() * $this->maxExportBatchSize + count($this->batch); + $pending = $this->queueSize - $queued; + $processed = $this->processed; + $dropped = $this->dropped; + + $observer->observe($queued, self::ATTRIBUTES_QUEUED); + $observer->observe($pending, self::ATTRIBUTES_PENDING); + $observer->observe($processed, self::ATTRIBUTES_PROCESSED); + $observer->observe($dropped, self::ATTRIBUTES_DROPPED); + }); + $meter + ->createObservableUpDownCounter( + 'otel.trace.span_processor.queue.limit', + '{spans}', + 'The queue size limit', + ) + ->observe(function (ObserverInterface $observer): void { + $observer->observe($this->maxQueueSize, self::ATTRIBUTES_PROCESSOR); + }); + $meter + ->createObservableUpDownCounter( + 'otel.trace.span_processor.queue.usage', + '{spans}', + 'The current queue usage', + ) + ->observe(function (ObserverInterface $observer): void { + $queued = $this->queue->count() * $this->maxExportBatchSize + count($this->batch); + $pending = $this->queueSize - $queued; + $free = $this->maxQueueSize - $this->queueSize; + + $observer->observe($queued, self::ATTRIBUTES_QUEUED); + $observer->observe($pending, self::ATTRIBUTES_PENDING); + $observer->observe($free, self::ATTRIBUTES_FREE); + }); + } + + public function onStart(ReadWriteSpanInterface $span, ContextInterface $parentContext): void + { + } + + public function onEnd(ReadableSpanInterface $span): void + { + if ($this->closed) { + return; + } + if (!$span->getContext()->isSampled()) { + return; + } + + if ($this->queueSize === $this->maxQueueSize) { + $this->dropped++; + + return; + } + + $this->queueSize++; + $this->batch[] = $span->toSpanData(); + $this->nextScheduledRun ??= $this->clock->now() + $this->scheduledDelayNanos; + + if (count($this->batch) === $this->maxExportBatchSize) { + $this->enqueueBatch(); + } + if ($this->autoFlush) { + $this->flush(); + } + } + + public function forceFlush(?CancellationInterface $cancellation = null): bool + { + if ($this->closed) { + return false; + } + + return $this->flush(__FUNCTION__, $cancellation); + } + + public function shutdown(?CancellationInterface $cancellation = null): bool + { + if ($this->closed) { + return false; + } + + $this->closed = true; + + return $this->flush(__FUNCTION__, $cancellation); + } + + public static function builder(SpanExporterInterface $exporter): BatchSpanProcessorBuilder + { + return new BatchSpanProcessorBuilder($exporter); + } + + private function flush(?string $flushMethod = null, ?CancellationInterface $cancellation = null): bool + { + if ($flushMethod !== null) { + $flushId = $this->batchId + $this->queue->count() + (int) (bool) $this->batch; + $this->flush->enqueue([$flushId, $flushMethod, $cancellation, !$this->running, Context::getCurrent()]); + } + + if ($this->running) { + return false; + } + + $success = true; + $exception = null; + $this->running = true; + + try { + for (;;) { + while (!$this->flush->isEmpty() && $this->flush->bottom()[0] <= $this->batchId) { + [, $flushMethod, $cancellation, $propagateResult, $context] = $this->flush->dequeue(); + $scope = $context->activate(); + + try { + $result = $this->exporter->$flushMethod($cancellation); + if ($propagateResult) { + $success = $result; + } + } catch (Throwable $e) { + if ($propagateResult) { + $exception = $e; + } else { + self::logError(sprintf('Unhandled %s error', $flushMethod), ['exception' => $e]); + } + } finally { + $scope->detach(); + } + } + + if (!$this->shouldFlush()) { + break; + } + + if ($this->queue->isEmpty()) { + $this->enqueueBatch(); + } + $batchSize = count($this->queue->bottom()); + $this->batchId++; + $scope = $this->exportContext->activate(); + + try { + $this->exporter->export($this->queue->dequeue())->await(); + } catch (Throwable $e) { + self::logError('Unhandled export error', ['exception' => $e]); + } finally { + $this->processed += $batchSize; + $this->queueSize -= $batchSize; + $scope->detach(); + } + } + } finally { + $this->running = false; + } + + if ($exception !== null) { + throw $exception; + } + + return $success; + } + + private function shouldFlush(): bool + { + return !$this->flush->isEmpty() + || $this->autoFlush && !$this->queue->isEmpty() + || $this->autoFlush && $this->nextScheduledRun !== null && $this->clock->now() > $this->nextScheduledRun; + } + + private function enqueueBatch(): void + { + assert($this->batch !== []); + + $this->queue->enqueue($this->batch); + $this->batch = []; + $this->nextScheduledRun = null; + } +} diff --git a/vendor/open-telemetry/sdk/Trace/SpanProcessor/BatchSpanProcessorBuilder.php b/vendor/open-telemetry/sdk/Trace/SpanProcessor/BatchSpanProcessorBuilder.php new file mode 100644 index 000000000..8e81e7dd6 --- /dev/null +++ b/vendor/open-telemetry/sdk/Trace/SpanProcessor/BatchSpanProcessorBuilder.php @@ -0,0 +1,41 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Trace\SpanProcessor; + +use OpenTelemetry\SDK\Common\Time\ClockFactory; +use OpenTelemetry\SDK\Metrics\MeterProviderInterface; +use OpenTelemetry\SDK\Trace\SpanExporterInterface; + +class BatchSpanProcessorBuilder +{ + private SpanExporterInterface $exporter; + private ?MeterProviderInterface $meterProvider = null; + + public function __construct(SpanExporterInterface $exporter) + { + $this->exporter = $exporter; + } + + public function setMeterProvider(MeterProviderInterface $meterProvider): self + { + $this->meterProvider = $meterProvider; + + return $this; + } + + public function build(): BatchSpanProcessor + { + return new BatchSpanProcessor( + $this->exporter, + ClockFactory::getDefault(), + BatchSpanProcessor::DEFAULT_MAX_QUEUE_SIZE, + BatchSpanProcessor::DEFAULT_SCHEDULE_DELAY, + BatchSpanProcessor::DEFAULT_EXPORT_TIMEOUT, + BatchSpanProcessor::DEFAULT_MAX_EXPORT_BATCH_SIZE, + true, + $this->meterProvider + ); + } +} diff --git a/vendor/open-telemetry/sdk/Trace/SpanProcessor/MultiSpanProcessor.php b/vendor/open-telemetry/sdk/Trace/SpanProcessor/MultiSpanProcessor.php new file mode 100644 index 000000000..e690791f2 --- /dev/null +++ b/vendor/open-telemetry/sdk/Trace/SpanProcessor/MultiSpanProcessor.php @@ -0,0 +1,79 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Trace\SpanProcessor; + +use OpenTelemetry\Context\ContextInterface; +use OpenTelemetry\SDK\Common\Future\CancellationInterface; +use OpenTelemetry\SDK\Trace\ReadableSpanInterface; +use OpenTelemetry\SDK\Trace\ReadWriteSpanInterface; +use OpenTelemetry\SDK\Trace\SpanProcessorInterface; + +/** + * Class SpanMultiProcessor is a SpanProcessor that forwards all events to an + * array of SpanProcessors. + */ +final class MultiSpanProcessor implements SpanProcessorInterface +{ + /** @var list<SpanProcessorInterface> */ + private array $processors = []; + + public function __construct(SpanProcessorInterface ...$spanProcessors) + { + foreach ($spanProcessors as $processor) { + $this->addSpanProcessor($processor); + } + } + + public function addSpanProcessor(SpanProcessorInterface $processor): void + { + $this->processors[] = $processor; + } + + /** @return list<SpanProcessorInterface> */ + public function getSpanProcessors(): array + { + return $this->processors; + } + + /** @inheritDoc */ + public function onStart(ReadWriteSpanInterface $span, ContextInterface $parentContext): void + { + foreach ($this->processors as $processor) { + $processor->onStart($span, $parentContext); + } + } + + /** @inheritDoc */ + public function onEnd(ReadableSpanInterface $span): void + { + foreach ($this->processors as $processor) { + $processor->onEnd($span); + } + } + + /** @inheritDoc */ + public function shutdown(?CancellationInterface $cancellation = null): bool + { + $result = true; + + foreach ($this->processors as $processor) { + $result = $result && $processor->shutdown(); + } + + return $result; + } + + /** @inheritDoc */ + public function forceFlush(?CancellationInterface $cancellation = null): bool + { + $result = true; + + foreach ($this->processors as $processor) { + $result = $result && $processor->forceFlush(); + } + + return $result; + } +} diff --git a/vendor/open-telemetry/sdk/Trace/SpanProcessor/NoopSpanProcessor.php b/vendor/open-telemetry/sdk/Trace/SpanProcessor/NoopSpanProcessor.php new file mode 100644 index 000000000..9c4d1eabe --- /dev/null +++ b/vendor/open-telemetry/sdk/Trace/SpanProcessor/NoopSpanProcessor.php @@ -0,0 +1,47 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Trace\SpanProcessor; + +use OpenTelemetry\Context\ContextInterface; +use OpenTelemetry\SDK\Common\Future\CancellationInterface; +use OpenTelemetry\SDK\Trace\ReadableSpanInterface; +use OpenTelemetry\SDK\Trace\ReadWriteSpanInterface; +use OpenTelemetry\SDK\Trace\SpanProcessorInterface; + +class NoopSpanProcessor implements SpanProcessorInterface +{ + private static ?SpanProcessorInterface $instance = null; + + public static function getInstance(): SpanProcessorInterface + { + if (null === self::$instance) { + self::$instance = new self(); + } + + return self::$instance; + } + + /** @inheritDoc */ + public function onStart(ReadWriteSpanInterface $span, ContextInterface $parentContext): void + { + } //@codeCoverageIgnore + + /** @inheritDoc */ + public function onEnd(ReadableSpanInterface $span): void + { + } //@codeCoverageIgnore + + /** @inheritDoc */ + public function forceFlush(?CancellationInterface $cancellation = null): bool + { + return true; + } + + /** @inheritDoc */ + public function shutdown(?CancellationInterface $cancellation = null): bool + { + return $this->forceFlush(); + } +} diff --git a/vendor/open-telemetry/sdk/Trace/SpanProcessor/SimpleSpanProcessor.php b/vendor/open-telemetry/sdk/Trace/SpanProcessor/SimpleSpanProcessor.php new file mode 100644 index 000000000..4e86e79ab --- /dev/null +++ b/vendor/open-telemetry/sdk/Trace/SpanProcessor/SimpleSpanProcessor.php @@ -0,0 +1,120 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Trace\SpanProcessor; + +use Closure; +use OpenTelemetry\API\Behavior\LogsMessagesTrait; +use OpenTelemetry\Context\Context; +use OpenTelemetry\Context\ContextInterface; +use OpenTelemetry\SDK\Common\Future\CancellationInterface; +use OpenTelemetry\SDK\Trace\ReadableSpanInterface; +use OpenTelemetry\SDK\Trace\ReadWriteSpanInterface; +use OpenTelemetry\SDK\Trace\SpanExporterInterface; +use OpenTelemetry\SDK\Trace\SpanProcessorInterface; +use SplQueue; +use function sprintf; +use Throwable; + +class SimpleSpanProcessor implements SpanProcessorInterface +{ + use LogsMessagesTrait; + + private SpanExporterInterface $exporter; + private ContextInterface $exportContext; + + private bool $running = false; + /** @var SplQueue<array{Closure, string, bool, ContextInterface}> */ + private SplQueue $queue; + + private bool $closed = false; + + public function __construct(SpanExporterInterface $exporter) + { + $this->exporter = $exporter; + + $this->exportContext = Context::getCurrent(); + $this->queue = new SplQueue(); + } + + public function onStart(ReadWriteSpanInterface $span, ContextInterface $parentContext): void + { + } + + public function onEnd(ReadableSpanInterface $span): void + { + if ($this->closed) { + return; + } + if (!$span->getContext()->isSampled()) { + return; + } + + $spanData = $span->toSpanData(); + $this->flush(fn () => $this->exporter->export([$spanData])->await(), 'export', false, $this->exportContext); + } + + public function forceFlush(?CancellationInterface $cancellation = null): bool + { + if ($this->closed) { + return false; + } + + return $this->flush(fn (): bool => $this->exporter->forceFlush($cancellation), __FUNCTION__, true, Context::getCurrent()); + } + + public function shutdown(?CancellationInterface $cancellation = null): bool + { + if ($this->closed) { + return false; + } + + $this->closed = true; + + return $this->flush(fn (): bool => $this->exporter->shutdown($cancellation), __FUNCTION__, true, Context::getCurrent()); + } + + private function flush(Closure $task, string $taskName, bool $propagateResult, ContextInterface $context): bool + { + $this->queue->enqueue([$task, $taskName, $propagateResult && !$this->running, $context]); + + if ($this->running) { + return false; + } + + $success = true; + $exception = null; + $this->running = true; + + try { + while (!$this->queue->isEmpty()) { + [$task, $taskName, $propagateResult, $context] = $this->queue->dequeue(); + $scope = $context->activate(); + + try { + $result = $task(); + if ($propagateResult) { + $success = $result; + } + } catch (Throwable $e) { + if ($propagateResult) { + $exception = $e; + } else { + self::logError(sprintf('Unhandled %s error', $taskName), ['exception' => $e]); + } + } finally { + $scope->detach(); + } + } + } finally { + $this->running = false; + } + + if ($exception !== null) { + throw $exception; + } + + return $success; + } +} diff --git a/vendor/open-telemetry/sdk/Trace/SpanProcessorFactory.php b/vendor/open-telemetry/sdk/Trace/SpanProcessorFactory.php new file mode 100644 index 000000000..39144cdf6 --- /dev/null +++ b/vendor/open-telemetry/sdk/Trace/SpanProcessorFactory.php @@ -0,0 +1,48 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Trace; + +use InvalidArgumentException; +use OpenTelemetry\SDK\Common\Configuration\Configuration; +use OpenTelemetry\SDK\Common\Configuration\KnownValues as Values; +use OpenTelemetry\SDK\Common\Configuration\Variables as Env; +use OpenTelemetry\SDK\Common\Time\ClockFactory; +use OpenTelemetry\SDK\Metrics\MeterProviderInterface; +use OpenTelemetry\SDK\Metrics\NoopMeterProvider; +use OpenTelemetry\SDK\Trace\SpanProcessor\BatchSpanProcessor; +use OpenTelemetry\SDK\Trace\SpanProcessor\NoopSpanProcessor; +use OpenTelemetry\SDK\Trace\SpanProcessor\SimpleSpanProcessor; + +class SpanProcessorFactory +{ + public function create(?SpanExporterInterface $exporter = null, ?MeterProviderInterface $meterProvider = null): SpanProcessorInterface + { + if ($exporter === null) { + return new NoopSpanProcessor(); + } + + $name = Configuration::getEnum(Env::OTEL_PHP_TRACES_PROCESSOR); + switch ($name) { + case Values::VALUE_BATCH: + return new BatchSpanProcessor( + $exporter, + ClockFactory::getDefault(), + Configuration::getInt(Env::OTEL_BSP_MAX_QUEUE_SIZE, BatchSpanProcessor::DEFAULT_MAX_QUEUE_SIZE), + Configuration::getInt(Env::OTEL_BSP_SCHEDULE_DELAY, BatchSpanProcessor::DEFAULT_SCHEDULE_DELAY), + Configuration::getInt(Env::OTEL_BSP_EXPORT_TIMEOUT, BatchSpanProcessor::DEFAULT_EXPORT_TIMEOUT), + Configuration::getInt(Env::OTEL_BSP_MAX_EXPORT_BATCH_SIZE, BatchSpanProcessor::DEFAULT_MAX_EXPORT_BATCH_SIZE), + true, //autoflush + $meterProvider ?? new NoopMeterProvider(), + ); + case Values::VALUE_SIMPLE: + return new SimpleSpanProcessor($exporter); + case Values::VALUE_NOOP: + case Values::VALUE_NONE: + return NoopSpanProcessor::getInstance(); + default: + throw new InvalidArgumentException('Unknown processor: ' . $name); + } + } +} diff --git a/vendor/open-telemetry/sdk/Trace/SpanProcessorInterface.php b/vendor/open-telemetry/sdk/Trace/SpanProcessorInterface.php new file mode 100644 index 000000000..24bcea2dd --- /dev/null +++ b/vendor/open-telemetry/sdk/Trace/SpanProcessorInterface.php @@ -0,0 +1,38 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Trace; + +use OpenTelemetry\Context\ContextInterface; +use OpenTelemetry\SDK\Common\Future\CancellationInterface; + +/** @see https://github.com/open-telemetry/opentelemetry-specification/blob/v1.6.1/specification/trace/sdk.md#span-processor */ +interface SpanProcessorInterface +{ + /** + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/v1.7.0/specification/trace/sdk.md#onstart + */ + public function onStart(ReadWriteSpanInterface $span, ContextInterface $parentContext): void; + + /** + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/v1.7.0/specification/trace/sdk.md#onendspan + */ + public function onEnd(ReadableSpanInterface $span): void; + + /** + * Export all ended spans to the configured Exporter that have not yet been exported. + * Returns `true` if the flush was successful, otherwise `false`. + * + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/v1.7.0/specification/trace/sdk.md#forceflush-1 + */ + public function forceFlush(?CancellationInterface $cancellation = null): bool; + + /** + * Cleanup; after shutdown, calling onStart, onEnd, or forceFlush is invalid + * Returns `false` is the processor is already shutdown, otherwise `true`. + * + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/v1.7.0/specification/trace/sdk.md#shutdown-1 + */ + public function shutdown(?CancellationInterface $cancellation = null): bool; +} diff --git a/vendor/open-telemetry/sdk/Trace/StatusData.php b/vendor/open-telemetry/sdk/Trace/StatusData.php new file mode 100644 index 000000000..c28ea22ab --- /dev/null +++ b/vendor/open-telemetry/sdk/Trace/StatusData.php @@ -0,0 +1,84 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Trace; + +use OpenTelemetry\API\Trace as API; + +final class StatusData implements StatusDataInterface +{ + private static ?self $ok = null; + private static ?self $unset = null; + private static ?self $error = null; + private string $code; + private string $description; + + /** @psalm-param API\StatusCode::STATUS_* $code */ + public function __construct( + string $code, + string $description + ) { + $this->code = $code; + $this->description = $description; + } + + /** @psalm-param API\StatusCode::STATUS_* $code */ + public static function create(string $code, ?string $description = null): self + { + if (empty($description)) { + switch ($code) { + case API\StatusCode::STATUS_UNSET: + return self::unset(); + case API\StatusCode::STATUS_ERROR: + return self::error(); + case API\StatusCode::STATUS_OK: + return self::ok(); + } + } + + // Ignore description for non Error statuses. + if (API\StatusCode::STATUS_ERROR !== $code) { + $description = ''; + } + + return new self($code, $description); /** @phan-suppress-current-line PhanTypeMismatchArgumentNullable */ + } + + public static function ok(): self + { + if (null === self::$ok) { + self::$ok = new self(API\StatusCode::STATUS_OK, ''); + } + + return self::$ok; + } + + public static function error(): self + { + if (null === self::$error) { + self::$error = new self(API\StatusCode::STATUS_ERROR, ''); + } + + return self::$error; + } + + public static function unset(): self + { + if (null === self::$unset) { + self::$unset = new self(API\StatusCode::STATUS_UNSET, ''); + } + + return self::$unset; + } + + public function getCode(): string + { + return $this->code; + } + + public function getDescription(): string + { + return $this->description; + } +} diff --git a/vendor/open-telemetry/sdk/Trace/StatusDataInterface.php b/vendor/open-telemetry/sdk/Trace/StatusDataInterface.php new file mode 100644 index 000000000..973d2b519 --- /dev/null +++ b/vendor/open-telemetry/sdk/Trace/StatusDataInterface.php @@ -0,0 +1,18 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Trace; + +interface StatusDataInterface +{ + public static function ok(): self; + + public static function error(): self; + + public static function unset(): self; + + public function getCode(): string; + + public function getDescription(): string; +} diff --git a/vendor/open-telemetry/sdk/Trace/Tracer.php b/vendor/open-telemetry/sdk/Trace/Tracer.php new file mode 100644 index 000000000..913773f60 --- /dev/null +++ b/vendor/open-telemetry/sdk/Trace/Tracer.php @@ -0,0 +1,52 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Trace; + +use function ctype_space; +use OpenTelemetry\API\Trace as API; +use OpenTelemetry\Context\Context; +use OpenTelemetry\SDK\Common\Instrumentation\InstrumentationScopeInterface; + +class Tracer implements API\TracerInterface +{ + public const FALLBACK_SPAN_NAME = 'empty'; + + /** @readonly */ + private TracerSharedState $tracerSharedState; + + /** @readonly */ + private InstrumentationScopeInterface $instrumentationScope; + + public function __construct( + TracerSharedState $tracerSharedState, + InstrumentationScopeInterface $instrumentationScope + ) { + $this->tracerSharedState = $tracerSharedState; + $this->instrumentationScope = $instrumentationScope; + } + + /** @inheritDoc */ + public function spanBuilder(string $spanName): API\SpanBuilderInterface + { + if (ctype_space($spanName)) { + $spanName = self::FALLBACK_SPAN_NAME; + } + + if ($this->tracerSharedState->hasShutdown()) { + return new API\NoopSpanBuilder(Context::storage()); + } + + return new SpanBuilder( + $spanName, + $this->instrumentationScope, + $this->tracerSharedState, + ); + } + + public function getInstrumentationScope(): InstrumentationScopeInterface + { + return $this->instrumentationScope; + } +} diff --git a/vendor/open-telemetry/sdk/Trace/TracerProvider.php b/vendor/open-telemetry/sdk/Trace/TracerProvider.php new file mode 100644 index 000000000..fdae4aea2 --- /dev/null +++ b/vendor/open-telemetry/sdk/Trace/TracerProvider.php @@ -0,0 +1,99 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Trace; + +use function is_array; +use OpenTelemetry\API\Trace as API; +use OpenTelemetry\API\Trace\NoopTracer; +use OpenTelemetry\SDK\Common\Attribute\Attributes; +use OpenTelemetry\SDK\Common\Future\CancellationInterface; +use OpenTelemetry\SDK\Common\Instrumentation\InstrumentationScopeFactory; +use OpenTelemetry\SDK\Common\Instrumentation\InstrumentationScopeFactoryInterface; +use OpenTelemetry\SDK\Resource\ResourceInfo; +use OpenTelemetry\SDK\Resource\ResourceInfoFactory; +use OpenTelemetry\SDK\Trace\Sampler\AlwaysOnSampler; +use OpenTelemetry\SDK\Trace\Sampler\ParentBased; + +final class TracerProvider implements TracerProviderInterface +{ + /** @readonly */ + private TracerSharedState $tracerSharedState; + private InstrumentationScopeFactoryInterface $instrumentationScopeFactory; + + /** @param list<SpanProcessorInterface>|SpanProcessorInterface|null $spanProcessors */ + public function __construct( + $spanProcessors = [], + SamplerInterface $sampler = null, + ResourceInfo $resource = null, + SpanLimits $spanLimits = null, + IdGeneratorInterface $idGenerator = null, + ?InstrumentationScopeFactoryInterface $instrumentationScopeFactory = null + ) { + if (null === $spanProcessors) { + $spanProcessors = []; + } + + $spanProcessors = is_array($spanProcessors) ? $spanProcessors : [$spanProcessors]; + $resource ??= ResourceInfoFactory::defaultResource(); + $sampler ??= new ParentBased(new AlwaysOnSampler()); + $idGenerator ??= new RandomIdGenerator(); + $spanLimits ??= (new SpanLimitsBuilder())->build(); + + $this->tracerSharedState = new TracerSharedState( + $idGenerator, + $resource, + $spanLimits, + $sampler, + $spanProcessors + ); + $this->instrumentationScopeFactory = $instrumentationScopeFactory ?? new InstrumentationScopeFactory(Attributes::factory()); + } + + public function forceFlush(?CancellationInterface $cancellation = null): bool + { + return $this->tracerSharedState->getSpanProcessor()->forceFlush($cancellation); + } + + /** + * @inheritDoc + */ + public function getTracer( + string $name, + ?string $version = null, + ?string $schemaUrl = null, + iterable $attributes = [] + ): API\TracerInterface { + if ($this->tracerSharedState->hasShutdown()) { + return NoopTracer::getInstance(); + } + + return new Tracer( + $this->tracerSharedState, + $this->instrumentationScopeFactory->create($name, $version, $schemaUrl, $attributes), + ); + } + + public function getSampler(): SamplerInterface + { + return $this->tracerSharedState->getSampler(); + } + + /** + * Returns `false` is the provider is already shutdown, otherwise `true`. + */ + public function shutdown(?CancellationInterface $cancellation = null): bool + { + if ($this->tracerSharedState->hasShutdown()) { + return true; + } + + return $this->tracerSharedState->shutdown($cancellation); + } + + public static function builder(): TracerProviderBuilder + { + return new TracerProviderBuilder(); + } +} diff --git a/vendor/open-telemetry/sdk/Trace/TracerProviderBuilder.php b/vendor/open-telemetry/sdk/Trace/TracerProviderBuilder.php new file mode 100644 index 000000000..8dcfdc700 --- /dev/null +++ b/vendor/open-telemetry/sdk/Trace/TracerProviderBuilder.php @@ -0,0 +1,45 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Trace; + +use OpenTelemetry\SDK\Resource\ResourceInfo; + +class TracerProviderBuilder +{ + // @var array<SpanProcessorInterface> + private ?array $spanProcessors = []; + private ?ResourceInfo $resource = null; + private ?SamplerInterface $sampler = null; + + public function addSpanProcessor(SpanProcessorInterface $spanProcessor): self + { + $this->spanProcessors[] = $spanProcessor; + + return $this; + } + + public function setResource(ResourceInfo $resource): self + { + $this->resource = $resource; + + return $this; + } + + public function setSampler(SamplerInterface $sampler): self + { + $this->sampler = $sampler; + + return $this; + } + + public function build(): TracerProviderInterface + { + return new TracerProvider( + $this->spanProcessors, + $this->sampler, + $this->resource, + ); + } +} diff --git a/vendor/open-telemetry/sdk/Trace/TracerProviderFactory.php b/vendor/open-telemetry/sdk/Trace/TracerProviderFactory.php new file mode 100644 index 000000000..a545319b6 --- /dev/null +++ b/vendor/open-telemetry/sdk/Trace/TracerProviderFactory.php @@ -0,0 +1,60 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Trace; + +use OpenTelemetry\API\Behavior\LogsMessagesTrait; +use OpenTelemetry\SDK\Sdk; + +final class TracerProviderFactory +{ + use LogsMessagesTrait; + + private ExporterFactory $exporterFactory; + private SamplerFactory $samplerFactory; + private SpanProcessorFactory $spanProcessorFactory; + + public function __construct( + ?ExporterFactory $exporterFactory = null, + ?SamplerFactory $samplerFactory = null, + ?SpanProcessorFactory $spanProcessorFactory = null + ) { + $this->exporterFactory = $exporterFactory ?: new ExporterFactory(); + $this->samplerFactory = $samplerFactory ?: new SamplerFactory(); + $this->spanProcessorFactory = $spanProcessorFactory ?: new SpanProcessorFactory(); + } + + public function create(): TracerProviderInterface + { + if (Sdk::isDisabled()) { + return new NoopTracerProvider(); + } + + try { + $exporter = $this->exporterFactory->create(); + } catch (\Throwable $t) { + self::logWarning('Unable to create exporter', ['exception' => $t]); + $exporter = null; + } + + try { + $sampler = $this->samplerFactory->create(); + } catch (\Throwable $t) { + self::logWarning('Unable to create sampler', ['exception' => $t]); + $sampler = null; + } + + try { + $spanProcessor = $this->spanProcessorFactory->create($exporter); + } catch (\Throwable $t) { + self::logWarning('Unable to create span processor', ['exception' => $t]); + $spanProcessor = null; + } + + return new TracerProvider( + $spanProcessor, + $sampler, + ); + } +} diff --git a/vendor/open-telemetry/sdk/Trace/TracerProviderInterface.php b/vendor/open-telemetry/sdk/Trace/TracerProviderInterface.php new file mode 100644 index 000000000..d61c1ea8f --- /dev/null +++ b/vendor/open-telemetry/sdk/Trace/TracerProviderInterface.php @@ -0,0 +1,15 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Trace; + +use OpenTelemetry\API\Trace as API; +use OpenTelemetry\SDK\Common\Future\CancellationInterface; + +interface TracerProviderInterface extends API\TracerProviderInterface +{ + public function forceFlush(?CancellationInterface $cancellation = null): bool; + + public function shutdown(?CancellationInterface $cancellation = null): bool; +} diff --git a/vendor/open-telemetry/sdk/Trace/TracerSharedState.php b/vendor/open-telemetry/sdk/Trace/TracerSharedState.php new file mode 100644 index 000000000..d0540cc1f --- /dev/null +++ b/vendor/open-telemetry/sdk/Trace/TracerSharedState.php @@ -0,0 +1,100 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Trace; + +use OpenTelemetry\API\Trace as API; /** @phan-suppress-current-line PhanUnreferencedUseNormal */ +use OpenTelemetry\SDK\Common\Future\CancellationInterface; +use OpenTelemetry\SDK\Resource\ResourceInfo; +use OpenTelemetry\SDK\Trace\SpanProcessor\MultiSpanProcessor; +use OpenTelemetry\SDK\Trace\SpanProcessor\NoopSpanProcessor; + +/** + * Stores shared state/config between all {@see API\TracerInterface} created via the same {@see API\TracerProviderInterface}. + */ +final class TracerSharedState +{ + /** @readonly */ + private IdGeneratorInterface $idGenerator; + + /** @readonly */ + private ResourceInfo $resource; + + /** @readonly */ + private SpanLimits $spanLimits; + + /** @readonly */ + private SamplerInterface $sampler; + + /** @readonly */ + private SpanProcessorInterface $spanProcessor; + + private ?bool $shutdownResult = null; + + public function __construct( + IdGeneratorInterface $idGenerator, + ResourceInfo $resource, + SpanLimits $spanLimits, + SamplerInterface $sampler, + array $spanProcessors + ) { + $this->idGenerator = $idGenerator; + $this->resource = $resource; + $this->spanLimits = $spanLimits; + $this->sampler = $sampler; + + switch (count($spanProcessors)) { + case 0: + $this->spanProcessor = NoopSpanProcessor::getInstance(); + + break; + case 1: + $this->spanProcessor = $spanProcessors[0]; + + break; + default: + $this->spanProcessor = new MultiSpanProcessor(...$spanProcessors); + + break; + } + } + + public function hasShutdown(): bool + { + return null !== $this->shutdownResult; + } + + public function getIdGenerator(): IdGeneratorInterface + { + return $this->idGenerator; + } + + public function getResource(): ResourceInfo + { + return $this->resource; + } + + public function getSpanLimits(): SpanLimits + { + return $this->spanLimits; + } + + public function getSampler(): SamplerInterface + { + return $this->sampler; + } + + public function getSpanProcessor(): SpanProcessorInterface + { + return $this->spanProcessor; + } + + /** + * Returns `false` is the provider is already shutdown, otherwise `true`. + */ + public function shutdown(?CancellationInterface $cancellation = null): bool + { + return $this->shutdownResult ?? ($this->shutdownResult = $this->spanProcessor->shutdown($cancellation)); + } +} |