diff options
Diffstat (limited to 'vendor/open-telemetry/sdk')
286 files changed, 14929 insertions, 0 deletions
diff --git a/vendor/open-telemetry/sdk/Common/Adapter/HttpDiscovery/DependencyResolver.php b/vendor/open-telemetry/sdk/Common/Adapter/HttpDiscovery/DependencyResolver.php new file mode 100644 index 000000000..8ba992f9a --- /dev/null +++ b/vendor/open-telemetry/sdk/Common/Adapter/HttpDiscovery/DependencyResolver.php @@ -0,0 +1,83 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Common\Adapter\HttpDiscovery; + +use Http\Client\HttpAsyncClient; +use OpenTelemetry\SDK\Common\Http\DependencyResolverInterface; +use OpenTelemetry\SDK\Common\Http\HttpPlug\Client\ResolverInterface as HttpPlugClientResolverInterface; +use OpenTelemetry\SDK\Common\Http\Psr\Client\ResolverInterface as PsrClientResolverInterface; +use OpenTelemetry\SDK\Common\Http\Psr\Message\FactoryResolverInterface as MessageFactoryResolverInterface; +use Psr\Http\Client\ClientInterface; +use Psr\Http\Message\RequestFactoryInterface; +use Psr\Http\Message\ResponseFactoryInterface; +use Psr\Http\Message\ServerRequestFactoryInterface; +use Psr\Http\Message\StreamFactoryInterface; +use Psr\Http\Message\UploadedFileFactoryInterface; +use Psr\Http\Message\UriFactoryInterface; + +final class DependencyResolver implements DependencyResolverInterface +{ + private MessageFactoryResolverInterface $messageFactoryResolver; + private PsrClientResolverInterface $psrClientResolver; + private HttpPlugClientResolverInterface $httpPlugClientResolver; + + public function __construct( + ?MessageFactoryResolverInterface $messageFactoryResolver = null, + ?PsrClientResolverInterface $psrClientResolver = null, + ?HttpPlugClientResolverInterface $httpPlugClientResolver = null + ) { + $this->messageFactoryResolver = $messageFactoryResolver ?? MessageFactoryResolver::create(); + $this->psrClientResolver = $psrClientResolver ?? PsrClientResolver::create(); + $this->httpPlugClientResolver = $httpPlugClientResolver ?? HttpPlugClientResolver::create(); + } + + public static function create( + ?MessageFactoryResolverInterface $messageFactoryResolver = null, + ?PsrClientResolverInterface $psrClientResolver = null, + ?HttpPlugClientResolverInterface $httpPlugClientResolver = null + ): self { + return new self($messageFactoryResolver, $psrClientResolver, $httpPlugClientResolver); + } + + public function resolveRequestFactory(): RequestFactoryInterface + { + return $this->messageFactoryResolver->resolveRequestFactory(); + } + + public function resolveResponseFactory(): ResponseFactoryInterface + { + return $this->messageFactoryResolver->resolveResponseFactory(); + } + + public function resolveServerRequestFactory(): ServerRequestFactoryInterface + { + return $this->messageFactoryResolver->resolveServerRequestFactory(); + } + + public function resolveStreamFactory(): StreamFactoryInterface + { + return $this->messageFactoryResolver->resolveStreamFactory(); + } + + public function resolveUploadedFileFactory(): UploadedFileFactoryInterface + { + return $this->messageFactoryResolver->resolveUploadedFileFactory(); + } + + public function resolveUriFactory(): UriFactoryInterface + { + return $this->messageFactoryResolver->resolveUriFactory(); + } + + public function resolveHttpPlugAsyncClient(): HttpAsyncClient + { + return $this->httpPlugClientResolver->resolveHttpPlugAsyncClient(); + } + + public function resolvePsrClient(): ClientInterface + { + return $this->psrClientResolver->resolvePsrClient(); + } +} diff --git a/vendor/open-telemetry/sdk/Common/Adapter/HttpDiscovery/HttpPlugClientResolver.php b/vendor/open-telemetry/sdk/Common/Adapter/HttpDiscovery/HttpPlugClientResolver.php new file mode 100644 index 000000000..9751984ee --- /dev/null +++ b/vendor/open-telemetry/sdk/Common/Adapter/HttpDiscovery/HttpPlugClientResolver.php @@ -0,0 +1,29 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Common\Adapter\HttpDiscovery; + +use Http\Client\HttpAsyncClient; +use Http\Discovery\HttpAsyncClientDiscovery; +use OpenTelemetry\SDK\Common\Http\HttpPlug\Client\ResolverInterface; + +final class HttpPlugClientResolver implements ResolverInterface +{ + private ?HttpAsyncClient $httpAsyncClient; + + public function __construct(?HttpAsyncClient $httpAsyncClient = null) + { + $this->httpAsyncClient = $httpAsyncClient; + } + + public static function create(?HttpAsyncClient $httpAsyncClient = null): self + { + return new self($httpAsyncClient); + } + + public function resolveHttpPlugAsyncClient(): HttpAsyncClient + { + return $this->httpAsyncClient ??= HttpAsyncClientDiscovery::find(); + } +} diff --git a/vendor/open-telemetry/sdk/Common/Adapter/HttpDiscovery/MessageFactoryResolver.php b/vendor/open-telemetry/sdk/Common/Adapter/HttpDiscovery/MessageFactoryResolver.php new file mode 100644 index 000000000..6ed0895ff --- /dev/null +++ b/vendor/open-telemetry/sdk/Common/Adapter/HttpDiscovery/MessageFactoryResolver.php @@ -0,0 +1,88 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Common\Adapter\HttpDiscovery; + +use Http\Discovery\Psr17FactoryDiscovery; +use OpenTelemetry\SDK\Common\Http\Psr\Message\FactoryResolverInterface; +use Psr\Http\Message\RequestFactoryInterface; +use Psr\Http\Message\ResponseFactoryInterface; +use Psr\Http\Message\ServerRequestFactoryInterface; +use Psr\Http\Message\StreamFactoryInterface; +use Psr\Http\Message\UploadedFileFactoryInterface; +use Psr\Http\Message\UriFactoryInterface; + +final class MessageFactoryResolver implements FactoryResolverInterface +{ + private ?RequestFactoryInterface $requestFactory; + private ?ResponseFactoryInterface $responseFactory; + private ?ServerRequestFactoryInterface $serverRequestFactory; + private ?StreamFactoryInterface $streamFactory; + private ?UploadedFileFactoryInterface $uploadedFileFactory; + private ?UriFactoryInterface $uriFactory; + + public function __construct( + ?RequestFactoryInterface $requestFactory = null, + ?ResponseFactoryInterface $responseFactory = null, + ?ServerRequestFactoryInterface $serverRequestFactory = null, + ?StreamFactoryInterface $streamFactory = null, + ?UploadedFileFactoryInterface $uploadedFileFactory = null, + ?UriFactoryInterface $uriFactory = null + ) { + $this->requestFactory = $requestFactory; + $this->responseFactory = $responseFactory; + $this->serverRequestFactory = $serverRequestFactory; + $this->streamFactory = $streamFactory; + $this->uploadedFileFactory = $uploadedFileFactory; + $this->uriFactory = $uriFactory; + } + + public static function create( + ?RequestFactoryInterface $requestFactory = null, + ?ResponseFactoryInterface $responseFactory = null, + ?ServerRequestFactoryInterface $serverRequestFactory = null, + ?StreamFactoryInterface $streamFactory = null, + ?UploadedFileFactoryInterface $uploadedFileFactory = null, + ?UriFactoryInterface $uriFactory = null + ): self { + return new self( + $requestFactory, + $responseFactory, + $serverRequestFactory, + $streamFactory, + $uploadedFileFactory, + $uriFactory + ); + } + + public function resolveRequestFactory(): RequestFactoryInterface + { + return $this->requestFactory ??= Psr17FactoryDiscovery::findRequestFactory(); + } + + public function resolveResponseFactory(): ResponseFactoryInterface + { + return $this->responseFactory ??= Psr17FactoryDiscovery::findResponseFactory(); + } + + public function resolveServerRequestFactory(): ServerRequestFactoryInterface + { + return $this->serverRequestFactory ??= Psr17FactoryDiscovery::findServerRequestFactory(); + } + + public function resolveStreamFactory(): StreamFactoryInterface + { + return $this->streamFactory ??= Psr17FactoryDiscovery::findStreamFactory(); + } + + public function resolveUploadedFileFactory(): UploadedFileFactoryInterface + { + return $this->uploadedFileFactory ??= Psr17FactoryDiscovery::findUploadedFileFactory(); + } + + public function resolveUriFactory(): UriFactoryInterface + { + return $this->uriFactory ??= Psr17FactoryDiscovery::findUriFactory(); + } +} diff --git a/vendor/open-telemetry/sdk/Common/Adapter/HttpDiscovery/PsrClientResolver.php b/vendor/open-telemetry/sdk/Common/Adapter/HttpDiscovery/PsrClientResolver.php new file mode 100644 index 000000000..46fb36312 --- /dev/null +++ b/vendor/open-telemetry/sdk/Common/Adapter/HttpDiscovery/PsrClientResolver.php @@ -0,0 +1,29 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Common\Adapter\HttpDiscovery; + +use Http\Discovery\Psr18ClientDiscovery; +use OpenTelemetry\SDK\Common\Http\Psr\Client\ResolverInterface; +use Psr\Http\Client\ClientInterface; + +final class PsrClientResolver implements ResolverInterface +{ + private ?ClientInterface $client; + + public function __construct(?ClientInterface $client = null) + { + $this->client = $client; + } + + public static function create(?ClientInterface $client = null): self + { + return new self($client); + } + + public function resolvePsrClient(): ClientInterface + { + return $this->client ??= Psr18ClientDiscovery::find(); + } +} diff --git a/vendor/open-telemetry/sdk/Common/Attribute/AttributeValidator.php b/vendor/open-telemetry/sdk/Common/Attribute/AttributeValidator.php new file mode 100644 index 000000000..e9a1f7334 --- /dev/null +++ b/vendor/open-telemetry/sdk/Common/Attribute/AttributeValidator.php @@ -0,0 +1,58 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Common\Attribute; + +class AttributeValidator implements AttributeValidatorInterface +{ + private const PRIMITIVES = [ + 'string', + 'integer', + 'double', + 'boolean', + ]; + private const NUMERICS = [ + 'double', + 'integer', + ]; + + /** + * Validate whether a value is a primitive, or a homogeneous array of primitives (treating int/double as equivalent). + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/v1.21.0/specification/common/README.md#attribute + */ + public function validate($value): bool + { + if (is_array($value)) { + return $this->validateArray($value); + } + + return in_array(gettype($value), self::PRIMITIVES); + } + + private function validateArray(array $value): bool + { + if ($value === []) { + return true; + } + $type = gettype(reset($value)); + if (!in_array($type, self::PRIMITIVES)) { + return false; + } + foreach ($value as $v) { + if (in_array(gettype($v), self::NUMERICS) && in_array($type, self::NUMERICS)) { + continue; + } + if (gettype($v) !== $type) { + return false; + } + } + + return true; + } + + public function getInvalidMessage(): string + { + return 'attribute with non-primitive or non-homogeneous array of primitives dropped'; + } +} diff --git a/vendor/open-telemetry/sdk/Common/Attribute/AttributeValidatorInterface.php b/vendor/open-telemetry/sdk/Common/Attribute/AttributeValidatorInterface.php new file mode 100644 index 000000000..afbfba6e7 --- /dev/null +++ b/vendor/open-telemetry/sdk/Common/Attribute/AttributeValidatorInterface.php @@ -0,0 +1,11 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Common\Attribute; + +interface AttributeValidatorInterface +{ + public function validate($value): bool; + public function getInvalidMessage(): string; +} diff --git a/vendor/open-telemetry/sdk/Common/Attribute/Attributes.php b/vendor/open-telemetry/sdk/Common/Attribute/Attributes.php new file mode 100644 index 000000000..bb131ce94 --- /dev/null +++ b/vendor/open-telemetry/sdk/Common/Attribute/Attributes.php @@ -0,0 +1,67 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Common\Attribute; + +use function array_key_exists; +use IteratorAggregate; +use Traversable; + +final class Attributes implements AttributesInterface, IteratorAggregate +{ + private array $attributes; + private int $droppedAttributesCount; + + /** + * @internal + */ + public function __construct(array $attributes, int $droppedAttributesCount) + { + $this->attributes = $attributes; + $this->droppedAttributesCount = $droppedAttributesCount; + } + + public static function create(iterable $attributes): AttributesInterface + { + return self::factory()->builder($attributes)->build(); + } + + public static function factory(?int $attributeCountLimit = null, ?int $attributeValueLengthLimit = null): AttributesFactoryInterface + { + return new AttributesFactory($attributeCountLimit, $attributeValueLengthLimit); + } + + public function has(string $name): bool + { + return array_key_exists($name, $this->attributes); + } + + public function get(string $name) + { + return $this->attributes[$name] ?? null; + } + + /** @psalm-mutation-free */ + public function count(): int + { + return \count($this->attributes); + } + + public function getIterator(): Traversable + { + foreach ($this->attributes as $key => $value) { + yield (string) $key => $value; + } + } + + public function toArray(): array + { + return $this->attributes; + } + + public function getDroppedAttributesCount(): int + { + return $this->droppedAttributesCount; + } +} diff --git a/vendor/open-telemetry/sdk/Common/Attribute/AttributesBuilder.php b/vendor/open-telemetry/sdk/Common/Attribute/AttributesBuilder.php new file mode 100644 index 000000000..5c1150638 --- /dev/null +++ b/vendor/open-telemetry/sdk/Common/Attribute/AttributesBuilder.php @@ -0,0 +1,120 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Common\Attribute; + +use function array_key_exists; +use function count; +use function is_array; +use function is_string; +use function mb_substr; +use OpenTelemetry\API\Behavior\LogsMessagesTrait; + +/** + * @internal + */ +final class AttributesBuilder implements AttributesBuilderInterface +{ + use LogsMessagesTrait; + + private array $attributes; + private ?int $attributeCountLimit; + private ?int $attributeValueLengthLimit; + private int $droppedAttributesCount; + private AttributeValidatorInterface $attributeValidator; + + public function __construct( + array $attributes, + ?int $attributeCountLimit, + ?int $attributeValueLengthLimit, + int $droppedAttributesCount, + ?AttributeValidatorInterface $attributeValidator + ) { + $this->attributes = $attributes; + $this->attributeCountLimit = $attributeCountLimit; + $this->attributeValueLengthLimit = $attributeValueLengthLimit; + $this->droppedAttributesCount = $droppedAttributesCount; + $this->attributeValidator = $attributeValidator ?? new AttributeValidator(); + } + + public function build(): AttributesInterface + { + return new Attributes($this->attributes, $this->droppedAttributesCount); + } + + public function offsetExists($offset): bool + { + return array_key_exists($offset, $this->attributes); + } + + /** + * @phan-suppress PhanUndeclaredClassAttribute + */ + #[\ReturnTypeWillChange] + public function offsetGet($offset) + { + return $this->attributes[$offset] ?? null; + } + + /** + * @phan-suppress PhanUndeclaredClassAttribute + */ + #[\ReturnTypeWillChange] + public function offsetSet($offset, $value) + { + if ($offset === null) { + return; + } + if ($value === null) { + unset($this->attributes[$offset]); + + return; + } + if (!$this->attributeValidator->validate($value)) { + self::logWarning($this->attributeValidator->getInvalidMessage() . ': ' . $offset); + $this->droppedAttributesCount++; + + return; + } + if (count($this->attributes) === $this->attributeCountLimit && !array_key_exists($offset, $this->attributes)) { + $this->droppedAttributesCount++; + + return; + } + + $this->attributes[$offset] = $this->normalizeValue($value); + //@todo "There SHOULD be a message printed in the SDK's log to indicate to the user that an attribute was + // discarded due to such a limit. To prevent excessive logging, the message MUST be printed at most + // once per <thing> (i.e., not per discarded attribute)." + } + + /** + * @phan-suppress PhanUndeclaredClassAttribute + */ + #[\ReturnTypeWillChange] + public function offsetUnset($offset) + { + unset($this->attributes[$offset]); + } + + private function normalizeValue($value) + { + if (is_string($value) && $this->attributeValueLengthLimit !== null) { + return mb_substr($value, 0, $this->attributeValueLengthLimit); + } + + if (is_array($value)) { + foreach ($value as $k => $v) { + $processed = $this->normalizeValue($v); + if ($processed !== $v) { + $value[$k] = $processed; + } + } + + return $value; + } + + return $value; + } +} diff --git a/vendor/open-telemetry/sdk/Common/Attribute/AttributesBuilderInterface.php b/vendor/open-telemetry/sdk/Common/Attribute/AttributesBuilderInterface.php new file mode 100644 index 000000000..7e3d64062 --- /dev/null +++ b/vendor/open-telemetry/sdk/Common/Attribute/AttributesBuilderInterface.php @@ -0,0 +1,12 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Common\Attribute; + +use ArrayAccess; + +interface AttributesBuilderInterface extends ArrayAccess +{ + public function build(): AttributesInterface; +} diff --git a/vendor/open-telemetry/sdk/Common/Attribute/AttributesFactory.php b/vendor/open-telemetry/sdk/Common/Attribute/AttributesFactory.php new file mode 100644 index 000000000..d53ab25aa --- /dev/null +++ b/vendor/open-telemetry/sdk/Common/Attribute/AttributesFactory.php @@ -0,0 +1,36 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Common\Attribute; + +/** + * @internal + */ +final class AttributesFactory implements AttributesFactoryInterface +{ + private ?int $attributeCountLimit; + private ?int $attributeValueLengthLimit; + + public function __construct(?int $attributeCountLimit = null, ?int $attributeValueLengthLimit = null) + { + $this->attributeCountLimit = $attributeCountLimit; + $this->attributeValueLengthLimit = $attributeValueLengthLimit; + } + + public function builder(iterable $attributes = [], ?AttributeValidatorInterface $attributeValidator = null): AttributesBuilderInterface + { + $builder = new AttributesBuilder( + [], + $this->attributeCountLimit, + $this->attributeValueLengthLimit, + 0, + $attributeValidator, + ); + foreach ($attributes as $key => $value) { + $builder[$key] = $value; + } + + return $builder; + } +} diff --git a/vendor/open-telemetry/sdk/Common/Attribute/AttributesFactoryInterface.php b/vendor/open-telemetry/sdk/Common/Attribute/AttributesFactoryInterface.php new file mode 100644 index 000000000..1b74461d4 --- /dev/null +++ b/vendor/open-telemetry/sdk/Common/Attribute/AttributesFactoryInterface.php @@ -0,0 +1,10 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Common\Attribute; + +interface AttributesFactoryInterface +{ + public function builder(iterable $attributes = [], ?AttributeValidatorInterface $attributeValidator = null): AttributesBuilderInterface; +} diff --git a/vendor/open-telemetry/sdk/Common/Attribute/AttributesInterface.php b/vendor/open-telemetry/sdk/Common/Attribute/AttributesInterface.php new file mode 100644 index 000000000..1af7dc8d9 --- /dev/null +++ b/vendor/open-telemetry/sdk/Common/Attribute/AttributesInterface.php @@ -0,0 +1,19 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Common\Attribute; + +use Countable; +use Traversable; + +interface AttributesInterface extends Traversable, Countable +{ + public function has(string $name): bool; + + public function get(string $name); + + public function getDroppedAttributesCount(): int; + + public function toArray(): array; +} diff --git a/vendor/open-telemetry/sdk/Common/Attribute/FilteredAttributesBuilder.php b/vendor/open-telemetry/sdk/Common/Attribute/FilteredAttributesBuilder.php new file mode 100644 index 000000000..d79cff96a --- /dev/null +++ b/vendor/open-telemetry/sdk/Common/Attribute/FilteredAttributesBuilder.php @@ -0,0 +1,77 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Common\Attribute; + +use function in_array; + +/** + * @internal + */ +final class FilteredAttributesBuilder implements AttributesBuilderInterface +{ + private AttributesBuilderInterface $builder; + private array $rejectedKeys; + private int $rejected = 0; + + /** + * @param list<string> $rejectedKeys + */ + public function __construct(AttributesBuilderInterface $builder, array $rejectedKeys) + { + $this->builder = $builder; + $this->rejectedKeys = $rejectedKeys; + } + + public function __clone() + { + $this->builder = clone $this->builder; + } + + public function build(): AttributesInterface + { + $attributes = $this->builder->build(); + $dropped = $attributes->getDroppedAttributesCount() + $this->rejected; + + return new Attributes($attributes->toArray(), $dropped); + } + + public function offsetExists($offset): bool + { + return $this->builder->offsetExists($offset); + } + + /** + * @phan-suppress PhanUndeclaredClassAttribute + */ + #[\ReturnTypeWillChange] + public function offsetGet($offset) + { + return $this->builder->offsetGet($offset); + } + + /** + * @phan-suppress PhanUndeclaredClassAttribute + */ + #[\ReturnTypeWillChange] + public function offsetSet($offset, $value) + { + if ($value !== null && in_array($offset, $this->rejectedKeys, true)) { + $this->rejected++; + + return; + } + + $this->builder->offsetSet($offset, $value); + } + + /** + * @phan-suppress PhanUndeclaredClassAttribute + */ + #[\ReturnTypeWillChange] + public function offsetUnset($offset) + { + $this->builder->offsetUnset($offset); + } +} diff --git a/vendor/open-telemetry/sdk/Common/Attribute/FilteredAttributesFactory.php b/vendor/open-telemetry/sdk/Common/Attribute/FilteredAttributesFactory.php new file mode 100644 index 000000000..1d9c4ae1c --- /dev/null +++ b/vendor/open-telemetry/sdk/Common/Attribute/FilteredAttributesFactory.php @@ -0,0 +1,33 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Common\Attribute; + +/** + * @internal + */ +final class FilteredAttributesFactory implements AttributesFactoryInterface +{ + private AttributesFactoryInterface $factory; + private array $rejectedKeys; + + /** + * @param list<string> $rejectedKeys + */ + public function __construct(AttributesFactoryInterface $factory, array $rejectedKeys) + { + $this->factory = $factory; + $this->rejectedKeys = $rejectedKeys; + } + + public function builder(iterable $attributes = [], ?AttributeValidatorInterface $attributeValidator = null): AttributesBuilderInterface + { + $builder = new FilteredAttributesBuilder($this->factory->builder([], $attributeValidator), $this->rejectedKeys); + foreach ($attributes as $attribute => $value) { + $builder[$attribute] = $value; + } + + return $builder; + } +} diff --git a/vendor/open-telemetry/sdk/Common/Attribute/LogRecordAttributeValidator.php b/vendor/open-telemetry/sdk/Common/Attribute/LogRecordAttributeValidator.php new file mode 100644 index 000000000..a09d26372 --- /dev/null +++ b/vendor/open-telemetry/sdk/Common/Attribute/LogRecordAttributeValidator.php @@ -0,0 +1,19 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Common\Attribute; + +class LogRecordAttributeValidator implements AttributeValidatorInterface +{ + public function validate($value): bool + { + return true; + } + + public function getInvalidMessage(): string + { + //not required as this validator always returns true + return 'unused'; + } +} diff --git a/vendor/open-telemetry/sdk/Common/Configuration/Configuration.php b/vendor/open-telemetry/sdk/Common/Configuration/Configuration.php new file mode 100644 index 000000000..58673fd98 --- /dev/null +++ b/vendor/open-telemetry/sdk/Common/Configuration/Configuration.php @@ -0,0 +1,182 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Common\Configuration; + +use InvalidArgumentException; +use OpenTelemetry\API\Behavior\LogsMessagesTrait; +use OpenTelemetry\SDK\Common\Configuration\Parser\BooleanParser; +use OpenTelemetry\SDK\Common\Configuration\Parser\ListParser; +use OpenTelemetry\SDK\Common\Configuration\Parser\MapParser; +use OpenTelemetry\SDK\Common\Configuration\Parser\RatioParser; +use OpenTelemetry\SDK\Common\Configuration\Resolver\CompositeResolver; +use OpenTelemetry\SDK\Common\Util\ClassConstantAccessor; +use UnexpectedValueException; + +/** + * Configuration can come from one or more of the following sources (from highest to lowest priority): + * - values defined in php.ini + * - environment variable ($_SERVER) + * - configuration file (todo) + */ +class Configuration +{ + use LogsMessagesTrait; + + public static function has(string $name): bool + { + return CompositeResolver::instance()->hasVariable($name); + } + + public static function getInt(string $key, int $default = null): int + { + return (int) self::validateVariableValue( + CompositeResolver::instance()->resolve( + self::validateVariableType($key, VariableTypes::INTEGER), + $default + ), + FILTER_VALIDATE_INT + ); + } + + public static function getString(string $key, string $default = null): string + { + return (string) self::validateVariableValue( + CompositeResolver::instance()->resolve( + self::validateVariableType($key, VariableTypes::STRING), + $default + ) + ); + } + + public static function getBoolean(string $key, bool $default = null): bool + { + $resolved = self::validateVariableValue( + CompositeResolver::instance()->resolve( + self::validateVariableType($key, VariableTypes::BOOL), + null === $default ? $default : ($default ? 'true' : 'false') + ) + ); + + try { + return BooleanParser::parse($resolved); + } catch (InvalidArgumentException $e) { + self::logWarning(sprintf('Invalid boolean value "%s" interpreted as "false" for %s', $resolved, $key)); + + return false; + } + } + + public static function getMixed(string $key, $default = null) + { + return self::validateVariableValue( + CompositeResolver::instance()->resolve( + $key, + $default + ) + ); + } + + public static function getMap(string $key, array $default = null): array + { + return MapParser::parse( + CompositeResolver::instance()->resolve( + self::validateVariableType($key, VariableTypes::MAP), + $default + ) + ); + } + + public static function getList(string $key, array $default = null): array + { + return ListParser::parse( + CompositeResolver::instance()->resolve( + self::validateVariableType($key, VariableTypes::LIST), + $default + ) + ); + } + + public static function getEnum(string $key, string $default = null): string + { + return (string) self::validateVariableValue( + CompositeResolver::instance()->resolve( + self::validateVariableType($key, VariableTypes::ENUM), + $default + ) + ); + } + + public static function getFloat(string $key, float $default = null): float + { + return (float) self::validateVariableValue( + CompositeResolver::instance()->resolve( + self::validateVariableType($key, VariableTypes::FLOAT), + $default + ), + FILTER_VALIDATE_FLOAT + ); + } + + public static function getRatio(string $key, float $default = null): float + { + return RatioParser::parse( + self::validateVariableValue( + CompositeResolver::instance()->resolve( + self::validateVariableType($key, VariableTypes::RATIO), + $default + ) + ) + ); + } + + public static function getKnownValues(string $variableName): ?array + { + return ClassConstantAccessor::getValue(KnownValues::class, $variableName); + } + + public static function getDefault(string $variableName) + { + return ClassConstantAccessor::getValue(Defaults::class, $variableName); + } + + public static function getType(string $variableName): ?string + { + return ClassConstantAccessor::getValue(ValueTypes::class, $variableName); + } + + public static function isEmpty($value): bool + { + // don't use 'empty()', since '0' is not considered to be empty + return $value === null || $value === ''; + } + + private static function validateVariableType(string $variableName, string $type): string + { + $variableType = self::getType($variableName); + + if ($variableType !== null && $variableType !== $type && $variableType !== VariableTypes::MIXED) { + throw new UnexpectedValueException( + sprintf('Variable "%s" is not supposed to be of type "%s" but type "%s"', $variableName, $type, $variableType) + ); + } + + return $variableName; + } + + private static function validateVariableValue($value, ?int $filterType = null) + { + if ($filterType !== null && filter_var($value, $filterType) === false) { + throw new UnexpectedValueException(sprintf('Value has invalid type "%s"', gettype($value))); + } + + if ($value === null || $value === '') { + throw new UnexpectedValueException( + 'Variable must not be null or empty' + ); + } + + return $value; + } +} diff --git a/vendor/open-telemetry/sdk/Common/Configuration/Defaults.php b/vendor/open-telemetry/sdk/Common/Configuration/Defaults.php new file mode 100644 index 000000000..7228270a6 --- /dev/null +++ b/vendor/open-telemetry/sdk/Common/Configuration/Defaults.php @@ -0,0 +1,122 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Common\Configuration; + +/** + * Default values for environment variables defined by the OpenTelemetry specification and language specific variables for the PHP SDK. + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/configuration/sdk-environment-variables.md + */ +interface Defaults +{ + /** + * General SDK Configuration + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/configuration/sdk-environment-variables.md#general-sdk-configuration + */ + public const OTEL_LOG_LEVEL = 'info'; + public const OTEL_PROPAGATORS = 'tracecontext,baggage'; + public const OTEL_TRACES_SAMPLER = 'parentbased_always_on'; + public const OTEL_SDK_DISABLED = 'false'; + /** + * Batch Span Processor + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/configuration/sdk-environment-variables.md#batch-span-processor + */ + public const OTEL_BSP_SCHEDULE_DELAY = 5000; + public const OTEL_BSP_EXPORT_TIMEOUT = 30000; + public const OTEL_BSP_MAX_QUEUE_SIZE = 2048; + public const OTEL_BSP_MAX_EXPORT_BATCH_SIZE = 512; + /** + * Batch LogRecord Processor + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/configuration/sdk-environment-variables.md#batch-logrecord-processor + */ + public const OTEL_BLRP_SCHEDULE_DELAY = 1000; + public const OTEL_BLRP_EXPORT_TIMEOUT = 30000; + public const OTEL_BLRP_MAX_QUEUE_SIZE = 2048; + public const OTEL_BLRP_MAX_EXPORT_BATCH_SIZE = 512; + /** + * Attribute Limits + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/configuration/sdk-environment-variables.md#attribute-limits + */ + public const OTEL_ATTRIBUTE_COUNT_LIMIT = 128; + public const OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT = PHP_INT_MAX; + /** + * Span Limits + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/configuration/sdk-environment-variables.md#span-limits + */ + public const OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT = 128; + public const OTEL_SPAN_EVENT_COUNT_LIMIT = 128; + public const OTEL_SPAN_LINK_COUNT_LIMIT = 128; + public const OTEL_EVENT_ATTRIBUTE_COUNT_LIMIT = 128; + public const OTEL_LINK_ATTRIBUTE_COUNT_LIMIT = 128; + /** + * LogRecord Limits + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/configuration/sdk-environment-variables.md#logrecord-limits + */ + public const OTEL_LOGRECORD_ATTRIBUTE_VALUE_LENGTH_LIMIT = PHP_INT_MAX; + public const OTEL_LOGRECORD_ATTRIBUTE_COUNT_LIMIT = 128; + /** + * OTLP Exporter + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/protocol/exporter.md#configuration-options + */ + // Endpoint + public const OTEL_EXPORTER_OTLP_ENDPOINT = 'http://localhost:4318'; + public const OTEL_EXPORTER_OTLP_TRACES_ENDPOINT = 'http://localhost:4318'; + public const OTEL_EXPORTER_OTLP_METRICS_ENDPOINT = 'http://localhost:4318'; + public const OTEL_EXPORTER_OTLP_LOGS_ENDPOINT = 'http://localhost:4318'; + // Insecure + public const OTEL_EXPORTER_OTLP_INSECURE = 'false'; + public const OTEL_EXPORTER_OTLP_TRACES_INSECURE = 'false'; + public const OTEL_EXPORTER_OTLP_METRICS_INSECURE = 'false'; + public const OTEL_EXPORTER_OTLP_LOGS_INSECURE = 'false'; + // Timeout (seconds) + public const OTEL_EXPORTER_OTLP_TIMEOUT = 10; + public const OTEL_EXPORTER_OTLP_TRACES_TIMEOUT = 10; + public const OTEL_EXPORTER_OTLP_METRICS_TIMEOUT = 10; + public const OTEL_EXPORTER_OTLP_LOGS_TIMEOUT = 10; + // Protocol + public const OTEL_EXPORTER_OTLP_PROTOCOL = 'http/protobuf'; + public const OTEL_EXPORTER_OTLP_TRACES_PROTOCOL = 'http/protobuf'; + public const OTEL_EXPORTER_OTLP_METRICS_PROTOCOL = 'http/protobuf'; + public const OTEL_EXPORTER_OTLP_LOGS_PROTOCOL = 'http/protobuf'; + /** + * Zipkin Exporter + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/configuration/sdk-environment-variables.md#zipkin-exporter + */ + public const OTEL_EXPORTER_ZIPKIN_ENDPOINT = 'http://localhost:9411/api/v2/spans'; + // Timeout (seconds) + public const OTEL_EXPORTER_ZIPKIN_TIMEOUT = 10; + /** + * Prometheus Exporter + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/configuration/sdk-environment-variables.md#prometheus-exporter + */ + public const OTEL_EXPORTER_PROMETHEUS_HOST = '0.0.0.0'; + public const OTEL_EXPORTER_PROMETHEUS_PORT = 9464; + /** + * Exporter Selection + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/configuration/sdk-environment-variables.md#exporter-selection + */ + public const OTEL_TRACES_EXPORTER = 'otlp'; + public const OTEL_METRICS_EXPORTER = 'otlp'; + public const OTEL_LOGS_EXPORTER = 'otlp'; + /** + * Metrics SDK Configuration + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/configuration/sdk-environment-variables.md#metrics-sdk-configuration + */ + public const OTEL_METRICS_EXEMPLAR_FILTER = 'with_sampled_trace'; + public const OTEL_METRIC_EXPORT_INTERVAL = 60000; + public const OTEL_METRIC_EXPORT_TIMEOUT = 30000; + public const OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE = 'cumulative'; + public const OTEL_EXPORTER_OTLP_METRICS_DEFAULT_HISTOGRAM_AGGREGATION = 'explicit_bucket_histogram'; + /** + * Language Specific Environment Variables + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/configuration/sdk-environment-variables.md#language-specific-environment-variables + */ + public const OTEL_PHP_TRACES_PROCESSOR = 'batch'; + public const OTEL_PHP_DETECTORS = 'all'; + public const OTEL_PHP_AUTOLOAD_ENABLED = 'false'; + public const OTEL_PHP_INTERNAL_METRICS_ENABLED = 'false'; + public const OTEL_PHP_DISABLED_INSTRUMENTATIONS = []; + public const OTEL_PHP_LOGS_PROCESSOR = 'batch'; + public const OTEL_PHP_LOG_DESTINATION = 'default'; +} diff --git a/vendor/open-telemetry/sdk/Common/Configuration/KnownValues.php b/vendor/open-telemetry/sdk/Common/Configuration/KnownValues.php new file mode 100644 index 000000000..8975b20f9 --- /dev/null +++ b/vendor/open-telemetry/sdk/Common/Configuration/KnownValues.php @@ -0,0 +1,208 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Common\Configuration; + +use Psr\Log\LogLevel; + +/** + * "Known values" for OpenTelemetry configurataion variables. + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/configuration/sdk-environment-variables.md + * Notice: Values specific to the PHP SDK have been added + */ +interface KnownValues +{ + public const VALUE_TRUE = 'true'; + public const VALUE_FALSE = 'false'; + public const VALUE_ON = 'on'; + public const VALUE_OFF = 'off'; + public const VALUE_1 = '1'; + public const VALUE_0 = '0'; + public const VALUE_ALL = 'all'; + public const VALUE_NONE = 'none'; + public const VALUE_TRACECONTEXT = 'tracecontext'; + public const VALUE_BAGGAGE = 'baggage'; + public const VALUE_B3 = 'b3'; + public const VALUE_B3_MULTI = 'b3multi'; + public const VALUE_XRAY = 'xray'; + public const VALUE_OTTRACE = 'ottrace'; + public const VALUE_ALWAYS_ON = 'always_on'; + public const VALUE_ALWAYS_OFF = 'always_off'; + public const VALUE_TRACE_ID_RATIO = 'traceidratio'; + public const VALUE_PARENT_BASED_ALWAYS_ON = 'parentbased_always_on'; + public const VALUE_PARENT_BASED_ALWAYS_OFF = 'parentbased_always_off'; + public const VALUE_PARENT_BASED_TRACE_ID_RATIO = 'parentbased_traceidratio'; + public const VALUE_GZIP = 'gzip'; + public const VALUE_GRPC = 'grpc'; + public const VALUE_HTTP_PROTOBUF = 'http/protobuf'; + public const VALUE_HTTP_JSON = 'http/json'; + public const VALUE_HTTP_NDJSON = 'http/ndjson'; + public const VALUE_OTLP = 'otlp'; + public const VALUE_ZIPKIN = 'zipkin'; + public const VALUE_PROMETHEUS = 'prometheus'; + public const VALUE_WITH_SAMPLED_TRACE = 'with_sampled_trace'; + public const VALUE_BATCH = 'batch'; + public const VALUE_SIMPLE = 'simple'; + public const VALUE_NOOP = 'noop'; + public const VALUE_LOG_EMERGENCY = LogLevel::EMERGENCY; + public const VALUE_LOG_ALERT = LogLevel::ALERT; + public const VALUE_LOG_CRITICAL = LogLevel::CRITICAL; + public const VALUE_LOG_ERROR = LogLevel::ERROR; + public const VALUE_LOG_WARNING = LogLevel::WARNING; + public const VALUE_LOG_NOTICE = LogLevel::NOTICE; + public const VALUE_LOG_INFO = LogLevel::INFO; + public const VALUE_LOG_DEBUG = LogLevel::DEBUG; + public const VALUE_TEMPORALITY_CUMULATIVE = 'cumulative'; + public const VALUE_TEMPORALITY_DELTA = 'delta'; + public const VALUE_TEMPORALITY_LOW_MEMORY = 'lowmemory'; + public const VALUE_HISTOGRAM_AGGREGATION_EXPLICIT = 'explicit_bucket_histogram'; + public const VALUE_HISTOGRAM_AGGREGATION_BASE2_EXPONENTIAL = 'base2_exponential_bucket_histogram'; + + public const VALUES_BOOLEAN = [ + self::VALUE_TRUE, + self::VALUE_FALSE, + ]; + + public const VALUES_COMPRESSION= [ + self::VALUE_GZIP, + self::VALUE_NONE, + ]; + + public const VALUES_OTLP_PROTOCOL = [ + self::VALUE_GRPC, + self::VALUE_HTTP_PROTOBUF, + self::VALUE_HTTP_JSON, + ]; + + public const VALUES_TEMPORALITY_PREFERENCE = [ + self::VALUE_TEMPORALITY_CUMULATIVE, + self::VALUE_TEMPORALITY_DELTA, + self::VALUE_TEMPORALITY_LOW_MEMORY, + ]; + + public const VALUES_HISTOGRAM_AGGREGATION = [ + self::VALUE_HISTOGRAM_AGGREGATION_EXPLICIT, + self::VALUE_HISTOGRAM_AGGREGATION_BASE2_EXPONENTIAL, + ]; + + /** + * General SDK Configuration + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/configuration/sdk-environment-variables.md#general-sdk-configuration + */ + public const OTEL_LOG_LEVEL = [ + self::VALUE_LOG_EMERGENCY, + self::VALUE_LOG_ALERT, + self::VALUE_LOG_CRITICAL, + self::VALUE_LOG_ERROR, + self::VALUE_LOG_WARNING, + self::VALUE_LOG_NOTICE, + self::VALUE_LOG_INFO, + self::VALUE_LOG_DEBUG, + ]; + public const OTEL_PROPAGATORS = [ + self::VALUE_TRACECONTEXT, // W3C Trace Context + self::VALUE_BAGGAGE, // W3C Baggage + self::VALUE_B3, // B3 Single + self::VALUE_B3_MULTI, // B3 Multi + self::VALUE_XRAY, // AWS X-Ray (third party) + self::VALUE_OTTRACE, // OT Trace (third party) + self::VALUE_NONE, // No automatically configured propagator. + ]; + public const OTEL_TRACES_SAMPLER = [ + self::VALUE_ALWAYS_ON, + self::VALUE_ALWAYS_OFF, + self::VALUE_TRACE_ID_RATIO, + self::VALUE_PARENT_BASED_ALWAYS_ON, + self::VALUE_PARENT_BASED_ALWAYS_OFF, + self::VALUE_PARENT_BASED_TRACE_ID_RATIO, + self::VALUE_XRAY, + ]; + /** + * OTLP Exporter + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/protocol/exporter.md#configuration-options + */ + // Insecure + public const OTEL_EXPORTER_OTLP_INSECURE = self::VALUES_BOOLEAN; + public const OTEL_EXPORTER_OTLP_TRACES_INSECURE = self::VALUES_BOOLEAN; + public const OTEL_EXPORTER_OTLP_METRICS_INSECURE = self::VALUES_BOOLEAN; + // Compression + public const OTEL_EXPORTER_OTLP_COMPRESSION = self::VALUES_COMPRESSION; + public const OTEL_EXPORTER_OTLP_TRACES_COMPRESSION = self::VALUES_COMPRESSION; + public const OTEL_EXPORTER_OTLP_METRICS_COMPRESSION = self::VALUES_COMPRESSION; + // Protocol + public const OTEL_EXPORTER_OTLP_PROTOCOL = self::VALUES_OTLP_PROTOCOL; + public const OTEL_EXPORTER_OTLP_TRACES_PROTOCOL = self::VALUES_OTLP_PROTOCOL; + public const OTEL_EXPORTER_OTLP_METRICS_PROTOCOL = self::VALUES_OTLP_PROTOCOL; + /** + * Exporter Selection + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/configuration/sdk-environment-variables.md#exporter-selection + */ + public const OTEL_TRACES_EXPORTER = [ + self::VALUE_OTLP, + self::VALUE_ZIPKIN, + self::VALUE_NONE, + ]; + public const OTEL_METRICS_EXPORTER = [ + self::VALUE_OTLP, + self::VALUE_PROMETHEUS, + self::VALUE_NONE, + ]; + public const OTEL_LOGS_EXPORTER = [ + self::VALUE_OTLP, + self::VALUE_NONE, + ]; + /** + * Metrics SDK Configuration + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/configuration/sdk-environment-variables.md#metrics-sdk-configuration + */ + public const OTEL_METRICS_EXEMPLAR_FILTER = [ + self::VALUE_WITH_SAMPLED_TRACE, + self::VALUE_ALL, + self::VALUE_NONE, + ]; + /** + * Language Specific Environment Variables + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/configuration/sdk-environment-variables.md#language-specific-environment-variables + */ + public const OTEL_PHP_TRACES_PROCESSOR = [ + self::VALUE_BATCH, + self::VALUE_SIMPLE, + self::VALUE_NOOP, + self::VALUE_NONE, + ]; + public const OTEL_PHP_AUTOLOAD_ENABLED = self::VALUES_BOOLEAN; + public const VALUE_ERROR_LOG = 'error_log'; + public const VALUE_STDERR = 'stderr'; + public const VALUE_STDOUT = 'stdout'; + public const VALUE_PSR3 = 'psr3'; + public const VALUE_EMPTY = ''; + public const VALUE_DETECTORS_ENVIRONMENT = 'env'; + public const VALUE_DETECTORS_HOST = 'host'; + public const VALUE_DETECTORS_OS = 'os'; + public const VALUE_DETECTORS_PROCESS = 'process'; + public const VALUE_DETECTORS_PROCESS_RUNTIME = 'process_runtime'; + public const VALUE_DETECTORS_SDK = 'sdk'; + public const VALUE_DETECTORS_SDK_PROVIDED = 'sdk_provided'; + public const VALUE_DETECTORS_COMPOSER = 'composer'; + public const OTEL_PHP_DETECTORS = [ + self::VALUE_ALL, + self::VALUE_DETECTORS_ENVIRONMENT, + self::VALUE_DETECTORS_HOST, + self::VALUE_DETECTORS_OS, + self::VALUE_DETECTORS_PROCESS, + self::VALUE_DETECTORS_PROCESS_RUNTIME, + self::VALUE_DETECTORS_SDK, + self::VALUE_DETECTORS_SDK_PROVIDED, + self::VALUE_DETECTORS_COMPOSER, + self::VALUE_NONE, + ]; + public const OTEL_PHP_LOG_DESTINATION = [ + self::VALUE_ERROR_LOG, + self::VALUE_STDERR, + self::VALUE_STDOUT, + self::VALUE_PSR3, + self::VALUE_EMPTY, + self::VALUE_NONE, + ]; +} diff --git a/vendor/open-telemetry/sdk/Common/Configuration/Parser/BooleanParser.php b/vendor/open-telemetry/sdk/Common/Configuration/Parser/BooleanParser.php new file mode 100644 index 000000000..4141c61ef --- /dev/null +++ b/vendor/open-telemetry/sdk/Common/Configuration/Parser/BooleanParser.php @@ -0,0 +1,34 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Common\Configuration\Parser; + +use InvalidArgumentException; + +class BooleanParser +{ + private const TRUE_VALUE = 'true'; + private const FALSE_VALUE = 'false'; + + /** + * @param string|bool $value + */ + public static function parse($value): bool + { + if (is_bool($value)) { + return $value; + } + if (strtolower($value) === self::TRUE_VALUE) { + return true; + } + + if (strtolower($value) === self::FALSE_VALUE) { + return false; + } + + throw new InvalidArgumentException( + sprintf('Value "%s" is a non-boolean value', $value) + ); + } +} diff --git a/vendor/open-telemetry/sdk/Common/Configuration/Parser/ListParser.php b/vendor/open-telemetry/sdk/Common/Configuration/Parser/ListParser.php new file mode 100644 index 000000000..f27b16597 --- /dev/null +++ b/vendor/open-telemetry/sdk/Common/Configuration/Parser/ListParser.php @@ -0,0 +1,28 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Common\Configuration\Parser; + +class ListParser +{ + private const DEFAULT_SEPARATOR = ','; + + /** + * @param string|array $value + */ + public static function parse($value): array + { + if (is_array($value)) { + return $value; + } + if (trim($value) === '') { + return []; + } + + return array_map( + fn ($value) => trim($value), + explode(self::DEFAULT_SEPARATOR, $value) + ); + } +} diff --git a/vendor/open-telemetry/sdk/Common/Configuration/Parser/MapParser.php b/vendor/open-telemetry/sdk/Common/Configuration/Parser/MapParser.php new file mode 100644 index 000000000..273d57c87 --- /dev/null +++ b/vendor/open-telemetry/sdk/Common/Configuration/Parser/MapParser.php @@ -0,0 +1,45 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Common\Configuration\Parser; + +use InvalidArgumentException; + +class MapParser +{ + private const VARIABLE_SEPARATOR = ','; + private const KEY_VALUE_SEPARATOR = '='; + + public static function parse($value): array + { + if (is_array($value)) { + return $value; + } + $result = []; + + if (null === $value || trim($value) === '') { + return $result; + } + + foreach (explode(self::VARIABLE_SEPARATOR, $value) as $pair) { + self::validateKeyValuePair($pair); + + [$key, $value] = explode(self::KEY_VALUE_SEPARATOR, $pair, 2); + $result[trim($key)] = trim($value); + } + + return $result; + } + + private static function validateKeyValuePair(string $pair) + { + if (strpos($pair, self::KEY_VALUE_SEPARATOR) === false) { + throw new InvalidArgumentException(sprintf( + 'Key-Value pair "%s" does not contain separator "%s"', + $pair, + self::KEY_VALUE_SEPARATOR + )); + } + } +} diff --git a/vendor/open-telemetry/sdk/Common/Configuration/Parser/RatioParser.php b/vendor/open-telemetry/sdk/Common/Configuration/Parser/RatioParser.php new file mode 100644 index 000000000..f0fe32100 --- /dev/null +++ b/vendor/open-telemetry/sdk/Common/Configuration/Parser/RatioParser.php @@ -0,0 +1,38 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Common\Configuration\Parser; + +use InvalidArgumentException; +use RangeException; + +class RatioParser +{ + private const MAX_VALUE = 1; + private const MIN_VALUE = 0; + + public static function parse($value): float + { + if (filter_var($value, FILTER_VALIDATE_FLOAT) === false) { + throw new InvalidArgumentException( + sprintf('Value "%s" contains non-numeric value', $value) + ); + } + + $result = (float) $value; + + if ($result > self::MAX_VALUE || $result < self::MIN_VALUE) { + throw new RangeException( + sprintf( + 'Value must not be lower than %s or higher than %s. Given: %s', + self::MIN_VALUE, + self::MAX_VALUE, + $value + ) + ); + } + + return $result; + } +} diff --git a/vendor/open-telemetry/sdk/Common/Configuration/Resolver/CompositeResolver.php b/vendor/open-telemetry/sdk/Common/Configuration/Resolver/CompositeResolver.php new file mode 100644 index 000000000..b72400b01 --- /dev/null +++ b/vendor/open-telemetry/sdk/Common/Configuration/Resolver/CompositeResolver.php @@ -0,0 +1,68 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Common\Configuration\Resolver; + +use OpenTelemetry\SDK\Common\Configuration\Configuration; + +/** + * @interal + */ +class CompositeResolver +{ + // @var array<ResolverInterface> + private array $resolvers = []; + + public static function instance(): self + { + static $instance; + $instance ??= new self([ + new PhpIniResolver(), + new EnvironmentResolver(), + ]); + + return $instance; + } + + public function __construct($resolvers) + { + foreach ($resolvers as $resolver) { + $this->addResolver($resolver); + } + } + + public function addResolver(ResolverInterface $resolver): void + { + $this->resolvers[] = $resolver; + } + + public function getResolvers(): array + { + return $this->resolvers; + } + + public function resolve(string $variableName, $default = '') + { + foreach ($this->resolvers as $resolver) { + if ($resolver->hasVariable($variableName)) { + return $resolver->retrieveValue($variableName); + } + } + + return Configuration::isEmpty($default) + ? Configuration::getDefault($variableName) + : $default; + } + + public function hasVariable(string $variableName): bool + { + foreach ($this->resolvers as $resolver) { + if ($resolver->hasVariable($variableName)) { + return true; + } + } + + return false; + } +} diff --git a/vendor/open-telemetry/sdk/Common/Configuration/Resolver/EnvironmentResolver.php b/vendor/open-telemetry/sdk/Common/Configuration/Resolver/EnvironmentResolver.php new file mode 100644 index 000000000..453f98e39 --- /dev/null +++ b/vendor/open-telemetry/sdk/Common/Configuration/Resolver/EnvironmentResolver.php @@ -0,0 +1,40 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Common\Configuration\Resolver; + +use OpenTelemetry\SDK\Common\Configuration\Configuration; + +/** + * @internal + */ +class EnvironmentResolver implements ResolverInterface +{ + public function hasVariable(string $variableName): bool + { + if (!Configuration::isEmpty($_SERVER[$variableName] ?? null)) { + return true; + } + $env = getenv($variableName); + if ($env === false) { + return false; + } + + return !Configuration::isEmpty($env); + } + + /** + * @psalm-suppress InvalidReturnStatement + * @psalm-suppress InvalidReturnType + */ + public function retrieveValue(string $variableName) + { + $value = getenv($variableName); + if ($value === false) { + $value = $_SERVER[$variableName] ?? null; + } + + return $value; + } +} diff --git a/vendor/open-telemetry/sdk/Common/Configuration/Resolver/PhpIniAccessor.php b/vendor/open-telemetry/sdk/Common/Configuration/Resolver/PhpIniAccessor.php new file mode 100644 index 000000000..a12b507e8 --- /dev/null +++ b/vendor/open-telemetry/sdk/Common/Configuration/Resolver/PhpIniAccessor.php @@ -0,0 +1,18 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Common\Configuration\Resolver; + +class PhpIniAccessor +{ + /** + * Mockable accessor for php.ini values + * @internal + * @return array|false|string + */ + public function get(string $variableName) + { + return get_cfg_var($variableName); + } +} diff --git a/vendor/open-telemetry/sdk/Common/Configuration/Resolver/PhpIniResolver.php b/vendor/open-telemetry/sdk/Common/Configuration/Resolver/PhpIniResolver.php new file mode 100644 index 000000000..c9a8f3b4e --- /dev/null +++ b/vendor/open-telemetry/sdk/Common/Configuration/Resolver/PhpIniResolver.php @@ -0,0 +1,41 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Common\Configuration\Resolver; + +use OpenTelemetry\SDK\Common\Configuration\Configuration; + +/** + * @interal + * @psalm-suppress TypeDoesNotContainType + */ +class PhpIniResolver implements ResolverInterface +{ + private PhpIniAccessor $accessor; + + public function __construct(?PhpIniAccessor $accessor = null) + { + $this->accessor = $accessor ?? new PhpIniAccessor(); + } + + public function retrieveValue(string $variableName) + { + $value = $this->accessor->get($variableName) ?: ''; + if (is_array($value)) { + return implode(',', $value); + } + + return $value; + } + + public function hasVariable(string $variableName): bool + { + $value = $this->accessor->get($variableName); + if ($value === []) { + return false; + } + + return $value !== false && !Configuration::isEmpty($value); + } +} diff --git a/vendor/open-telemetry/sdk/Common/Configuration/Resolver/ResolverInterface.php b/vendor/open-telemetry/sdk/Common/Configuration/Resolver/ResolverInterface.php new file mode 100644 index 000000000..4e88f3ff6 --- /dev/null +++ b/vendor/open-telemetry/sdk/Common/Configuration/Resolver/ResolverInterface.php @@ -0,0 +1,15 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Common\Configuration\Resolver; + +interface ResolverInterface +{ + /** + * @return mixed + */ + public function retrieveValue(string $variableName); + + public function hasVariable(string $variableName): bool; +} diff --git a/vendor/open-telemetry/sdk/Common/Configuration/ValueTypes.php b/vendor/open-telemetry/sdk/Common/Configuration/ValueTypes.php new file mode 100644 index 000000000..64a69f6a7 --- /dev/null +++ b/vendor/open-telemetry/sdk/Common/Configuration/ValueTypes.php @@ -0,0 +1,133 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Common\Configuration; + +/** + * Environment variables defined by the OpenTelemetry specification and language specific variables for the PHP SDK. + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/configuration/sdk-environment-variables.md + */ +interface ValueTypes +{ + /** + * General SDK Configuration + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/configuration/sdk-environment-variables.md#general-sdk-configuration + */ + public const OTEL_RESOURCE_ATTRIBUTES = VariableTypes::MAP; + public const OTEL_SERVICE_NAME = VariableTypes::STRING; + public const OTEL_LOG_LEVEL = VariableTypes::ENUM; + public const OTEL_PROPAGATORS = VariableTypes::LIST; + public const OTEL_TRACES_SAMPLER = VariableTypes::STRING; + public const OTEL_TRACES_SAMPLER_ARG = VariableTypes::MIXED; + /** + * Batch Span Processor + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/configuration/sdk-environment-variables.md#batch-span-processor + */ + public const OTEL_BSP_SCHEDULE_DELAY = VariableTypes::INTEGER; + public const OTEL_BSP_EXPORT_TIMEOUT = VariableTypes::INTEGER; + public const OTEL_BSP_MAX_QUEUE_SIZE = VariableTypes::INTEGER; + public const OTEL_BSP_MAX_EXPORT_BATCH_SIZE = VariableTypes::INTEGER; + /** + * Batch LogRecord Processor + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/configuration/sdk-environment-variables.md#batch-logrecord-processor + */ + public const OTEL_BLRP_SCHEDULE_DELAY = VariableTypes::INTEGER; + public const OTEL_BLRP_EXPORT_TIMEOUT = VariableTypes::INTEGER; + public const OTEL_BLRP_MAX_QUEUE_SIZE = VariableTypes::INTEGER; + public const OTEL_BLRP_MAX_EXPORT_BATCH_SIZE = VariableTypes::INTEGER; + /** + * Attribute Limits + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/configuration/sdk-environment-variables.md#attribute-limits + */ + public const OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT = VariableTypes::INTEGER; + public const OTEL_ATTRIBUTE_COUNT_LIMIT = VariableTypes::INTEGER; + /** + * Span Limits + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/configuration/sdk-environment-variables.md#span-limits + */ + public const OTEL_SPAN_ATTRIBUTE_VALUE_LENGTH_LIMIT = VariableTypes::INTEGER; + public const OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT = VariableTypes::INTEGER; + public const OTEL_SPAN_EVENT_COUNT_LIMIT = VariableTypes::INTEGER; + public const OTEL_SPAN_LINK_COUNT_LIMIT = VariableTypes::INTEGER; + public const OTEL_EVENT_ATTRIBUTE_COUNT_LIMIT = VariableTypes::INTEGER; + public const OTEL_LINK_ATTRIBUTE_COUNT_LIMIT = VariableTypes::INTEGER; + /** + * LogRecord Limits + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/configuration/sdk-environment-variables.md#logrecord-limits + */ + public const OTEL_LOGRECORD_ATTRIBUTE_VALUE_LENGTH_LIMIT = VariableTypes::INTEGER; + public const OTEL_LOGRECORD_ATTRIBUTE_COUNT_LIMIT = VariableTypes::INTEGER; + /** + * OTLP Exporter + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/protocol/exporter.md#configuration-options + */ + // Endpoint + public const OTEL_EXPORTER_OTLP_ENDPOINT = VariableTypes::STRING; + public const OTEL_EXPORTER_OTLP_TRACES_ENDPOINT = VariableTypes::STRING; + public const OTEL_EXPORTER_OTLP_METRICS_ENDPOINT = VariableTypes::STRING; + // Insecure + public const OTEL_EXPORTER_OTLP_INSECURE = VariableTypes::BOOL; + public const OTEL_EXPORTER_OTLP_TRACES_INSECURE = VariableTypes::BOOL; + public const OTEL_EXPORTER_OTLP_METRICS_INSECURE = VariableTypes::BOOL; + // Certificate File + public const OTEL_EXPORTER_OTLP_CERTIFICATE = VariableTypes::STRING; + public const OTEL_EXPORTER_OTLP_TRACES_CERTIFICATE = VariableTypes::STRING; + public const OTEL_EXPORTER_OTLP_METRICS_CERTIFICATE = VariableTypes::STRING; + // Headers + public const OTEL_EXPORTER_OTLP_HEADERS = VariableTypes::MAP; + public const OTEL_EXPORTER_OTLP_TRACES_HEADERS = VariableTypes::MAP; + public const OTEL_EXPORTER_OTLP_METRICS_HEADERS = VariableTypes::MAP; + // Compression + public const OTEL_EXPORTER_OTLP_COMPRESSION = VariableTypes::ENUM; + public const OTEL_EXPORTER_OTLP_TRACES_COMPRESSION = VariableTypes::ENUM; + public const OTEL_EXPORTER_OTLP_METRICS_COMPRESSION = VariableTypes::ENUM; + // Timeout + public const OTEL_EXPORTER_OTLP_TIMEOUT = VariableTypes::INTEGER; + public const OTEL_EXPORTER_OTLP_TRACES_TIMEOUT = VariableTypes::INTEGER; + public const OTEL_EXPORTER_OTLP_METRICS_TIMEOUT = VariableTypes::INTEGER; + // Protocol + public const OTEL_EXPORTER_OTLP_PROTOCOL = VariableTypes::ENUM; + public const OTEL_EXPORTER_OTLP_TRACES_PROTOCOL = VariableTypes::ENUM; + public const OTEL_EXPORTER_OTLP_METRICS_PROTOCOL = VariableTypes::ENUM; + /** + * Zipkin Exporter + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/configuration/sdk-environment-variables.md#zipkin-exporter + */ + public const OTEL_EXPORTER_ZIPKIN_ENDPOINT = VariableTypes::STRING; + public const OTEL_EXPORTER_ZIPKIN_TIMEOUT = VariableTypes::INTEGER; + public const OTEL_EXPORTER_ZIPKIN_PROTOCOL = VariableTypes::STRING; + /** + * Prometheus Exporter + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/configuration/sdk-environment-variables.md#prometheus-exporter + */ + public const OTEL_EXPORTER_PROMETHEUS_HOST = VariableTypes::STRING; + public const OTEL_EXPORTER_PROMETHEUS_PORT = VariableTypes::INTEGER; + /** + * Exporter Selection + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/configuration/sdk-environment-variables.md#exporter-selection + */ + public const OTEL_TRACES_EXPORTER = VariableTypes::LIST; + public const OTEL_METRICS_EXPORTER = VariableTypes::LIST; + public const OTEL_LOGS_EXPORTER = VariableTypes::LIST; + /** + * Metrics SDK Configuration + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/configuration/sdk-environment-variables.md#metrics-sdk-configuration + */ + public const OTEL_METRICS_EXEMPLAR_FILTER = VariableTypes::ENUM; + public const OTEL_METRIC_EXPORT_INTERVAL = VariableTypes::INTEGER; + public const OTEL_METRIC_EXPORT_TIMEOUT = VariableTypes::INTEGER; + public const OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE = VariableTypes::ENUM; + public const OTEL_EXPORTER_OTLP_METRICS_DEFAULT_HISTOGRAM_AGGREGATION = VariableTypes::ENUM; + /** + * Language Specific Environment Variables + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/configuration/sdk-environment-variables.md#language-specific-environment-variables + */ + public const OTEL_PHP_TRACES_PROCESSOR = VariableTypes::ENUM; + public const OTEL_PHP_LOGS_PROCESSOR = VariableTypes::LIST; + public const OTEL_PHP_DETECTORS = VariableTypes::LIST; + public const OTEL_PHP_AUTOLOAD_ENABLED = VariableTypes::BOOL; + public const OTEL_PHP_LOG_DESTINATION = VariableTypes::ENUM; + public const OTEL_PHP_INTERNAL_METRICS_ENABLED = VariableTypes::BOOL; + public const OTEL_PHP_DISABLED_INSTRUMENTATIONS = VariableTypes::LIST; +} diff --git a/vendor/open-telemetry/sdk/Common/Configuration/VariableTypes.php b/vendor/open-telemetry/sdk/Common/Configuration/VariableTypes.php new file mode 100644 index 000000000..471632e16 --- /dev/null +++ b/vendor/open-telemetry/sdk/Common/Configuration/VariableTypes.php @@ -0,0 +1,62 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Common\Configuration; + +interface VariableTypes +{ + /** + * A single boolean value represented as a string or integer ('true', 'false', 0, 1) + * example: value1 + */ + public const BOOL = 'bool'; + + /** + * A single string value + * example: value1 + */ + public const STRING = 'string'; + + /** + * A single integer value + * example: 5000 + */ + public const INTEGER = 'integer'; + + /** + * A single float value + * example: 10.5 + */ + public const FLOAT = 'float'; + + /** + * A single float value between 0.0 and 1.0 + * example: 0.5 + */ + public const RATIO = 'ratio'; + + /** + * A single string value from a fixed list of values + * example values: value1, value2, value3 + * example: value1 + */ + public const ENUM = 'enum'; + + /** + * A comma separated list of single string values + * example: value1,value2,value3 + */ + public const LIST = 'list'; + + /** + * A comma separated list of key-value pairs + * example: key1=value1,key2=value2 + */ + public const MAP = 'map'; + + /** + * Values of mixed type + */ + public const MIXED = 'mixed'; +} diff --git a/vendor/open-telemetry/sdk/Common/Configuration/Variables.php b/vendor/open-telemetry/sdk/Common/Configuration/Variables.php new file mode 100644 index 000000000..d0bb3c8ab --- /dev/null +++ b/vendor/open-telemetry/sdk/Common/Configuration/Variables.php @@ -0,0 +1,142 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Common\Configuration; + +/** + * Environment variables defined by the OpenTelemetry specification and language specific variables for the PHP SDK. + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/configuration/sdk-environment-variables.md + */ +interface Variables +{ + /** + * General SDK Configuration + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/configuration/sdk-environment-variables.md#general-sdk-configuration + */ + public const OTEL_RESOURCE_ATTRIBUTES = 'OTEL_RESOURCE_ATTRIBUTES'; + public const OTEL_SERVICE_NAME = 'OTEL_SERVICE_NAME'; + public const OTEL_LOG_LEVEL = 'OTEL_LOG_LEVEL'; + public const OTEL_PROPAGATORS = 'OTEL_PROPAGATORS'; + public const OTEL_TRACES_SAMPLER = 'OTEL_TRACES_SAMPLER'; + public const OTEL_TRACES_SAMPLER_ARG = 'OTEL_TRACES_SAMPLER_ARG'; + public const OTEL_SDK_DISABLED = 'OTEL_SDK_DISABLED'; + /** + * Batch Span Processor + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/configuration/sdk-environment-variables.md#batch-span-processor + */ + public const OTEL_BSP_SCHEDULE_DELAY = 'OTEL_BSP_SCHEDULE_DELAY'; + public const OTEL_BSP_EXPORT_TIMEOUT = 'OTEL_BSP_EXPORT_TIMEOUT'; + public const OTEL_BSP_MAX_QUEUE_SIZE = 'OTEL_BSP_MAX_QUEUE_SIZE'; + public const OTEL_BSP_MAX_EXPORT_BATCH_SIZE = 'OTEL_BSP_MAX_EXPORT_BATCH_SIZE'; + /** + * Batch LogRecord Processor + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/configuration/sdk-environment-variables.md#batch-logrecord-processor + */ + public const OTEL_BLRP_SCHEDULE_DELAY = 'OTEL_BLRP_SCHEDULE_DELAY'; + public const OTEL_BLRP_EXPORT_TIMEOUT = 'OTEL_BLRP_EXPORT_TIMEOUT'; + public const OTEL_BLRP_MAX_QUEUE_SIZE = 'OTEL_BLRP_MAX_QUEUE_SIZE'; + public const OTEL_BLRP_MAX_EXPORT_BATCH_SIZE = 'OTEL_BLRP_MAX_EXPORT_BATCH_SIZE'; + /** + * Attribute Limits + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/configuration/sdk-environment-variables.md#attribute-limits + */ + public const OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT = 'OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT'; + public const OTEL_ATTRIBUTE_COUNT_LIMIT = 'OTEL_ATTRIBUTE_COUNT_LIMIT'; + /** + * LogRecord limits + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/configuration/sdk-environment-variables.md#logrecord-limits + */ + public const OTEL_LOGRECORD_ATTRIBUTE_VALUE_LENGTH_LIMIT = 'OTEL_LOGRECORD_ATTRIBUTE_VALUE_LENGTH_LIMIT'; + public const OTEL_LOGRECORD_ATTRIBUTE_COUNT_LIMIT = 'OTEL_LOGRECORD_ATTRIBUTE_COUNT_LIMIT'; + /** + * Span Limits + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/configuration/sdk-environment-variables.md#span-limits + */ + public const OTEL_SPAN_ATTRIBUTE_VALUE_LENGTH_LIMIT = 'OTEL_SPAN_ATTRIBUTE_VALUE_LENGTH_LIMIT'; + public const OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT = 'OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT'; + public const OTEL_SPAN_EVENT_COUNT_LIMIT = 'OTEL_SPAN_EVENT_COUNT_LIMIT'; + public const OTEL_SPAN_LINK_COUNT_LIMIT = 'OTEL_SPAN_LINK_COUNT_LIMIT'; + public const OTEL_EVENT_ATTRIBUTE_COUNT_LIMIT = 'OTEL_EVENT_ATTRIBUTE_COUNT_LIMIT'; + public const OTEL_LINK_ATTRIBUTE_COUNT_LIMIT = 'OTEL_LINK_ATTRIBUTE_COUNT_LIMIT'; + /** + * OTLP Exporter + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/protocol/exporter.md#configuration-options + */ + // Endpoint + public const OTEL_EXPORTER_OTLP_ENDPOINT = 'OTEL_EXPORTER_OTLP_ENDPOINT'; + public const OTEL_EXPORTER_OTLP_TRACES_ENDPOINT = 'OTEL_EXPORTER_OTLP_TRACES_ENDPOINT'; + public const OTEL_EXPORTER_OTLP_METRICS_ENDPOINT = 'OTEL_EXPORTER_OTLP_METRICS_ENDPOINT'; + public const OTEL_EXPORTER_OTLP_LOGS_ENDPOINT = 'OTEL_EXPORTER_OTLP_LOGS_ENDPOINT'; + // Insecure + public const OTEL_EXPORTER_OTLP_INSECURE = 'OTEL_EXPORTER_OTLP_INSECURE'; + public const OTEL_EXPORTER_OTLP_TRACES_INSECURE = 'OTEL_EXPORTER_OTLP_TRACES_INSECURE'; + public const OTEL_EXPORTER_OTLP_METRICS_INSECURE = 'OTEL_EXPORTER_OTLP_METRICS_INSECURE'; + public const OTEL_EXPORTER_OTLP_LOGS_INSECURE = 'OTEL_EXPORTER_OTLP_LOGS_INSECURE'; + // Certificate File + public const OTEL_EXPORTER_OTLP_CERTIFICATE = 'OTEL_EXPORTER_OTLP_CERTIFICATE'; + public const OTEL_EXPORTER_OTLP_TRACES_CERTIFICATE = 'OTEL_EXPORTER_OTLP_TRACES_CERTIFICATE'; + public const OTEL_EXPORTER_OTLP_METRICS_CERTIFICATE = 'OTEL_EXPORTER_OTLP_METRICS_CERTIFICATE'; + public const OTEL_EXPORTER_OTLP_LOGS_CERTIFICATE = 'OTEL_EXPORTER_OTLP_LOGS_CERTIFICATE'; + // Headers + public const OTEL_EXPORTER_OTLP_HEADERS = 'OTEL_EXPORTER_OTLP_HEADERS'; + public const OTEL_EXPORTER_OTLP_TRACES_HEADERS = 'OTEL_EXPORTER_OTLP_TRACES_HEADERS'; + public const OTEL_EXPORTER_OTLP_METRICS_HEADERS = 'OTEL_EXPORTER_OTLP_METRICS_HEADERS'; + public const OTEL_EXPORTER_OTLP_LOGS_HEADERS = 'OTEL_EXPORTER_OTLP_LOGS_HEADERS'; + // Compression + public const OTEL_EXPORTER_OTLP_COMPRESSION = 'OTEL_EXPORTER_OTLP_COMPRESSION'; + public const OTEL_EXPORTER_OTLP_TRACES_COMPRESSION = 'OTEL_EXPORTER_OTLP_TRACES_COMPRESSION'; + public const OTEL_EXPORTER_OTLP_METRICS_COMPRESSION = 'OTEL_EXPORTER_OTLP_METRICS_COMPRESSION'; + public const OTEL_EXPORTER_OTLP_LOGS_COMPRESSION = 'OTEL_EXPORTER_OTLP_LOGS_COMPRESSION'; + // Timeout + public const OTEL_EXPORTER_OTLP_TIMEOUT = 'OTEL_EXPORTER_OTLP_TIMEOUT'; + public const OTEL_EXPORTER_OTLP_TRACES_TIMEOUT = 'OTEL_EXPORTER_OTLP_TRACES_TIMEOUT'; + public const OTEL_EXPORTER_OTLP_METRICS_TIMEOUT = 'OTEL_EXPORTER_OTLP_METRICS_TIMEOUT'; + public const OTEL_EXPORTER_OTLP_LOGS_TIMEOUT = 'OTEL_EXPORTER_OTLP_LOGS_TIMEOUT'; + // Protocol + public const OTEL_EXPORTER_OTLP_PROTOCOL = 'OTEL_EXPORTER_OTLP_PROTOCOL'; + public const OTEL_EXPORTER_OTLP_TRACES_PROTOCOL = 'OTEL_EXPORTER_OTLP_TRACES_PROTOCOL'; + public const OTEL_EXPORTER_OTLP_METRICS_PROTOCOL = 'OTEL_EXPORTER_OTLP_METRICS_PROTOCOL'; + public const OTEL_EXPORTER_OTLP_LOGS_PROTOCOL = 'OTEL_EXPORTER_OTLP_LOGS_PROTOCOL'; + /** + * Zipkin Exporter + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/configuration/sdk-environment-variables.md#zipkin-exporter + */ + public const OTEL_EXPORTER_ZIPKIN_ENDPOINT = 'OTEL_EXPORTER_ZIPKIN_ENDPOINT'; + public const OTEL_EXPORTER_ZIPKIN_TIMEOUT = 'OTEL_EXPORTER_ZIPKIN_TIMEOUT'; + public const OTEL_EXPORTER_ZIPKIN_PROTOCOL = 'OTEL_EXPORTER_ZIPKIN_PROTOCOL'; + /** + * Prometheus Exporter + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/configuration/sdk-environment-variables.md#prometheus-exporter + */ + public const OTEL_EXPORTER_PROMETHEUS_HOST = 'OTEL_EXPORTER_PROMETHEUS_HOST'; + public const OTEL_EXPORTER_PROMETHEUS_PORT = 'OTEL_EXPORTER_PROMETHEUS_PORT'; + /** + * Exporter Selection + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/configuration/sdk-environment-variables.md#exporter-selection + */ + public const OTEL_TRACES_EXPORTER = 'OTEL_TRACES_EXPORTER'; + public const OTEL_METRICS_EXPORTER = 'OTEL_METRICS_EXPORTER'; + public const OTEL_LOGS_EXPORTER = 'OTEL_LOGS_EXPORTER'; + /** + * Metrics SDK Configuration + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/configuration/sdk-environment-variables.md#metrics-sdk-configuration + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/configuration/sdk-environment-variables.md#periodic-exporting-metricreader + */ + public const OTEL_METRICS_EXEMPLAR_FILTER = 'OTEL_METRICS_EXEMPLAR_FILTER'; + public const OTEL_METRIC_EXPORT_INTERVAL = 'OTEL_METRIC_EXPORT_INTERVAL'; + public const OTEL_METRIC_EXPORT_TIMEOUT = 'OTEL_METRIC_EXPORT_TIMEOUT'; + public const OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE = 'OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE'; + public const OTEL_EXPORTER_OTLP_METRICS_DEFAULT_HISTOGRAM_AGGREGATION = 'OTEL_EXPORTER_OTLP_METRICS_DEFAULT_HISTOGRAM_AGGREGATION'; + /** + * Language Specific Environment Variables + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/configuration/sdk-environment-variables.md#language-specific-environment-variables + */ + public const OTEL_PHP_TRACES_PROCESSOR = 'OTEL_PHP_TRACES_PROCESSOR'; + public const OTEL_PHP_LOGS_PROCESSOR = 'OTEL_PHP_LOGS_PROCESSOR'; + public const OTEL_PHP_LOG_DESTINATION = 'OTEL_PHP_LOG_DESTINATION'; + public const OTEL_PHP_DETECTORS = 'OTEL_PHP_DETECTORS'; + public const OTEL_PHP_AUTOLOAD_ENABLED = 'OTEL_PHP_AUTOLOAD_ENABLED'; + public const OTEL_PHP_INTERNAL_METRICS_ENABLED = 'OTEL_PHP_INTERNAL_METRICS_ENABLED'; //whether the SDK should emit its own metrics + public const OTEL_PHP_DISABLED_INSTRUMENTATIONS = 'OTEL_PHP_DISABLED_INSTRUMENTATIONS'; +} diff --git a/vendor/open-telemetry/sdk/Common/Dev/Compatibility/README.md b/vendor/open-telemetry/sdk/Common/Dev/Compatibility/README.md new file mode 100644 index 000000000..661eed3b8 --- /dev/null +++ b/vendor/open-telemetry/sdk/Common/Dev/Compatibility/README.md @@ -0,0 +1,14 @@ +# Backwards Compatibility + +We aim to provide backward compatibility (without any guarantee) even for alpha releases, however the library will raise notices indicating breaking changes and what to do about them. \ +If you don't want these notices to appear or change the error message level, you can do so by calling: +```php +OpenTelemetry\SDK\Common\Dev\Compatibility\Util::setErrorLevel(0) +``` +to turn messages off completely, or (for example) +```php +OpenTelemetry\SDK\Common\Dev\Compatibility\Util::setErrorLevel(E_USER_DEPRECATED) +``` +to trigger only deprecation notices. Valid error levels are `0` (none), `E_USER_DEPRECATED`, `E_USER_NOTICE`, `E_USER_WARNING` and `E_USER_ERROR` \ +However (as long as in alpha) it is safer to pin a dependency on the library to a specific version and/or make the adjustments +mentioned in the provided messages, since doing otherwise may break things completely for you in the future! diff --git a/vendor/open-telemetry/sdk/Common/Dev/Compatibility/Util.php b/vendor/open-telemetry/sdk/Common/Dev/Compatibility/Util.php new file mode 100644 index 000000000..1a3debfdd --- /dev/null +++ b/vendor/open-telemetry/sdk/Common/Dev/Compatibility/Util.php @@ -0,0 +1,93 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Common\Dev\Compatibility; + +class Util +{ + public const E_NONE = 0; + public const DEFAULT_ERROR_LEVEL = E_USER_NOTICE; + public const ERROR_LEVELS = [ + self::E_NONE, + E_USER_DEPRECATED, + E_USER_NOTICE, + E_USER_WARNING, + E_USER_ERROR, + ]; + + private static int $errorLevel = E_USER_NOTICE; + + public static function setErrorLevel(int $errorLevel = E_USER_NOTICE): void + { + self::validateErrorLevel($errorLevel); + + self::$errorLevel = $errorLevel; + } + + public static function getErrorLevel(): int + { + return self::$errorLevel; + } + + /** + * @psalm-suppress ArgumentTypeCoercion + */ + public static function triggerClassDeprecationNotice(string $className, string $alternativeClassName = null): void + { + if (self::getErrorLevel() === self::E_NONE) { + return; + } + + $notice = sprintf( + 'Class "%s" is deprecated and will be removed in a future release. ', + $className + ); + + if ($alternativeClassName !== null) { + $notice .= sprintf('Please, use "%s" instead.', $alternativeClassName); + } + + trigger_error($notice, self::$errorLevel); + } + + /** + * @psalm-suppress ArgumentTypeCoercion + */ + public static function triggerMethodDeprecationNotice( + string $methodName, + string $alternativeMethodName = null, + string $alternativeClassName = null + ): void { + if (self::getErrorLevel() === self::E_NONE) { + return; + } + + $notice = sprintf( + 'Method "%s " is deprecated and will be removed in a future release. ', + $methodName + ); + + if ($alternativeMethodName !== null) { + $method = $alternativeClassName === null + ? $alternativeMethodName + : sprintf('%s::%s', $alternativeClassName, $alternativeMethodName); + + $notice .= sprintf('Please, use "%s" instead.', $method); + } + + trigger_error($notice, self::$errorLevel); + } + + private static function validateErrorLevel(int $errorLevel): void + { + if (!in_array($errorLevel, self::ERROR_LEVELS, true)) { + throw new \InvalidArgumentException( + sprintf( + 'Error level must be one of "%s"', + implode('", "', self::ERROR_LEVELS) + ), + ); + } + } +} diff --git a/vendor/open-telemetry/sdk/Common/Dev/Compatibility/_load.php b/vendor/open-telemetry/sdk/Common/Dev/Compatibility/_load.php new file mode 100644 index 000000000..99f86c574 --- /dev/null +++ b/vendor/open-telemetry/sdk/Common/Dev/Compatibility/_load.php @@ -0,0 +1,7 @@ +<?php + +declare(strict_types=1); +/** + * To add a BC compatibility: + * require_once __DIR__ . '/BC/SomeFile.php'; + */ diff --git a/vendor/open-telemetry/sdk/Common/Exception/StackTraceFormatter.php b/vendor/open-telemetry/sdk/Common/Exception/StackTraceFormatter.php new file mode 100644 index 000000000..675fc7626 --- /dev/null +++ b/vendor/open-telemetry/sdk/Common/Exception/StackTraceFormatter.php @@ -0,0 +1,155 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Common\Exception; + +use function basename; +use function count; +use function get_class; +use function sprintf; +use function str_repeat; + +use Throwable; + +/** + * @psalm-type Frame = array{ + * function: string, + * class: ?class-string, + * file: ?string, + * line: ?int, + * } + * @psalm-type Frames = non-empty-list<Frame> + */ +final class StackTraceFormatter +{ + private function __construct() + { + } + + /** + * Formats an exception in a java-like format. + * + * @param Throwable $e exception to format + * @return string formatted exception + * + * @see https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/Throwable.html#printStackTrace() + */ + public static function format(Throwable $e): string + { + $s = ''; + $seen = []; + + /** @var Frames|null $enclosing */ + $enclosing = null; + do { + if ($enclosing) { + self::writeNewline($s); + $s .= 'Caused by: '; + } + if (isset($seen[spl_object_id($e)])) { + $s .= '[CIRCULAR REFERENCE: '; + self::writeInlineHeader($s, $e); + $s .= ']'; + + break; + } + $seen[spl_object_id($e)] = $e; + + $frames = self::frames($e); + self::writeInlineHeader($s, $e); + self::writeFrames($s, $frames, $enclosing); + + $enclosing = $frames; + } while ($e = $e->getPrevious()); + + return $s; + } + + /** + * @phan-suppress-next-line PhanTypeMismatchDeclaredParam + * @param Frames $frames + * @phan-suppress-next-line PhanTypeMismatchDeclaredParam + * @param Frames|null $enclosing + */ + private static function writeFrames(string &$s, array $frames, ?array $enclosing): void + { + $n = count($frames); + if ($enclosing) { + for ($m = count($enclosing); + $n && $m && $frames[$n - 1] === $enclosing[$m - 1]; + $n--, $m--) { + } + } + for ($i = 0; $i < $n; $i++) { + $frame = $frames[$i]; + self::writeNewline($s, 1); + $s .= 'at '; + if ($frame['class'] !== null) { + $s .= self::formatName($frame['class']); + $s .= '.'; + } + $s .= self::formatName($frame['function']); + $s .= '('; + if ($frame['file'] !== null) { + $s .= basename($frame['file']); + if ($frame['line']) { + $s .= ':'; + $s .= $frame['line']; + } + } else { + $s .= 'Unknown Source'; + } + $s .= ')'; + } + if ($n !== count($frames)) { + self::writeNewline($s, 1); + $s .= sprintf('... %d more', count($frames) - $n); + } + } + + private static function writeInlineHeader(string &$s, Throwable $e): void + { + $s .= self::formatName(get_class($e)); + if ($e->getMessage() !== '') { + $s .= ': '; + $s .= $e->getMessage(); + } + } + + private static function writeNewline(string &$s, int $indent = 0): void + { + $s .= "\n"; + $s .= str_repeat("\t", $indent); + } + + /** + * @return Frames + * + * @psalm-suppress PossiblyUndefinedArrayOffset + */ + private static function frames(Throwable $e): array + { + $frames = []; + $trace = $e->getTrace(); + $traceCount = count($trace); + for ($i = 0; $i < $traceCount + 1; $i++) { + $frames[] = [ + 'function' => $trace[$i]['function'] ?? '{main}', + 'class' => $trace[$i]['class'] ?? null, + 'file' => $trace[$i - 1]['file'] ?? null, + 'line' => $trace[$i - 1]['line'] ?? null, + ]; + } + $frames[0]['file'] = $e->getFile(); + $frames[0]['line'] = $e->getLine(); + + /** @var Frames $frames */ + return $frames; + } + + private static function formatName(string $name): string + { + return strtr($name, ['\\' => '.']); + } +} diff --git a/vendor/open-telemetry/sdk/Common/Export/Http/PsrTransport.php b/vendor/open-telemetry/sdk/Common/Export/Http/PsrTransport.php new file mode 100644 index 000000000..a53e5b80a --- /dev/null +++ b/vendor/open-telemetry/sdk/Common/Export/Http/PsrTransport.php @@ -0,0 +1,168 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Common\Export\Http; + +use function assert; +use BadMethodCallException; +use function explode; +use function in_array; +use OpenTelemetry\SDK\Common\Export\TransportInterface; +use OpenTelemetry\SDK\Common\Future\CancellationInterface; +use OpenTelemetry\SDK\Common\Future\CompletedFuture; +use OpenTelemetry\SDK\Common\Future\ErrorFuture; +use OpenTelemetry\SDK\Common\Future\FutureInterface; +use Psr\Http\Client\ClientInterface; +use Psr\Http\Client\NetworkExceptionInterface; +use Psr\Http\Message\RequestFactoryInterface; +use Psr\Http\Message\ResponseInterface; +use Psr\Http\Message\StreamFactoryInterface; +use RuntimeException; +use function strtolower; +use Throwable; +use function time_nanosleep; +use function trim; + +/** + * @psalm-template CONTENT_TYPE of string + * @template-implements TransportInterface<CONTENT_TYPE> + */ +final class PsrTransport implements TransportInterface +{ + private ClientInterface $client; + private RequestFactoryInterface $requestFactory; + private StreamFactoryInterface $streamFactory; + + private string $endpoint; + private string $contentType; + private array $headers; + private array $compression; + private int $retryDelay; + private int $maxRetries; + + private bool $closed = false; + + /** + * @psalm-param CONTENT_TYPE $contentType + */ + public function __construct( + ClientInterface $client, + RequestFactoryInterface $requestFactory, + StreamFactoryInterface $streamFactory, + string $endpoint, + string $contentType, + array $headers, + array $compression, + int $retryDelay, + int $maxRetries + ) { + $this->client = $client; + $this->requestFactory = $requestFactory; + $this->streamFactory = $streamFactory; + $this->endpoint = $endpoint; + $this->contentType = $contentType; + $this->headers = $headers; + $this->compression = $compression; + $this->retryDelay = $retryDelay; + $this->maxRetries = $maxRetries; + } + + public function contentType(): string + { + return $this->contentType; + } + + public function send(string $payload, ?CancellationInterface $cancellation = null): FutureInterface + { + if ($this->closed) { + return new ErrorFuture(new BadMethodCallException('Transport closed')); + } + + $body = PsrUtils::encode($payload, $this->compression, $appliedEncodings); + $request = $this->requestFactory + ->createRequest('POST', $this->endpoint) + ->withBody($this->streamFactory->createStream($body)) + ->withHeader('Content-Type', $this->contentType) + ; + if ($appliedEncodings) { + $request = $request->withHeader('Content-Encoding', $appliedEncodings); + } + foreach ($this->headers as $header => $value) { + $request = $request->withAddedHeader($header, $value); + } + + for ($retries = 0;; $retries++) { + $response = null; + $e = null; + + try { + $response = $this->client->sendRequest($request); + if ($response->getStatusCode() >= 200 && $response->getStatusCode() < 300) { + break; + } + + if ($response->getStatusCode() >= 400 && $response->getStatusCode() < 500 && !in_array($response->getStatusCode(), [408, 429], true)) { + throw new RuntimeException($response->getReasonPhrase(), $response->getStatusCode()); + } + } catch (NetworkExceptionInterface $e) { + } catch (Throwable $e) { + return new ErrorFuture($e); + } + + if ($retries >= $this->maxRetries) { + return new ErrorFuture(new RuntimeException('Export retry limit exceeded', 0, $e)); + } + + $delay = PsrUtils::retryDelay($retries, $this->retryDelay, $response); + $sec = (int) $delay; + $nsec = (int) (($delay - $sec) * 1e9); + + /** @psalm-suppress ArgumentTypeCoercion */ + if (time_nanosleep($sec, $nsec) !== true) { + return new ErrorFuture(new RuntimeException('Export cancelled', 0, $e)); + } + } + + assert(isset($response)); + + try { + $body = PsrUtils::decode( + $response->getBody()->__toString(), + self::parseContentEncoding($response), + ); + } catch (Throwable $e) { + return new ErrorFuture($e); + } + + return new CompletedFuture($body); + } + + private static function parseContentEncoding(ResponseInterface $response): array + { + $encodings = []; + foreach (explode(',', $response->getHeaderLine('Content-Encoding')) as $encoding) { + if (($encoding = trim($encoding, " \t")) !== '') { + $encodings[] = strtolower($encoding); + } + } + + return $encodings; + } + + public function shutdown(?CancellationInterface $cancellation = null): bool + { + if ($this->closed) { + return false; + } + + $this->closed = true; + + return true; + } + + public function forceFlush(?CancellationInterface $cancellation = null): bool + { + return !$this->closed; + } +} diff --git a/vendor/open-telemetry/sdk/Common/Export/Http/PsrTransportFactory.php b/vendor/open-telemetry/sdk/Common/Export/Http/PsrTransportFactory.php new file mode 100644 index 000000000..5ef78d82c --- /dev/null +++ b/vendor/open-telemetry/sdk/Common/Export/Http/PsrTransportFactory.php @@ -0,0 +1,74 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Common\Export\Http; + +use const FILTER_VALIDATE_URL; +use function filter_var; +use Http\Discovery\Psr17FactoryDiscovery; +use Http\Discovery\Psr18ClientDiscovery; +use InvalidArgumentException; +use OpenTelemetry\SDK\Common\Export\TransportFactoryInterface; +use Psr\Http\Client\ClientInterface; +use Psr\Http\Message\RequestFactoryInterface; +use Psr\Http\Message\StreamFactoryInterface; + +final class PsrTransportFactory implements TransportFactoryInterface +{ + private ClientInterface $client; + private RequestFactoryInterface $requestFactory; + private StreamFactoryInterface $streamFactory; + + public function __construct( + ClientInterface $client, + RequestFactoryInterface $requestFactory, + StreamFactoryInterface $streamFactory + ) { + $this->client = $client; + $this->requestFactory = $requestFactory; + $this->streamFactory = $streamFactory; + } + + /** + * @phan-suppress PhanTypeMismatchArgumentNullable + */ + public function create( + string $endpoint, + string $contentType, + array $headers = [], + $compression = null, + float $timeout = 10., + int $retryDelay = 100, + int $maxRetries = 3, + ?string $cacert = null, + ?string $cert = null, + ?string $key = null + ): PsrTransport { + if (!filter_var($endpoint, FILTER_VALIDATE_URL)) { + throw new InvalidArgumentException(sprintf('Invalid endpoint url "%s"', $endpoint)); + } + assert(!empty($endpoint)); + + return new PsrTransport( + $this->client, + $this->requestFactory, + $this->streamFactory, + $endpoint, + $contentType, + $headers, + PsrUtils::compression($compression), + $retryDelay, + $maxRetries, + ); + } + + public static function discover(): self + { + return new self( + Psr18ClientDiscovery::find(), + Psr17FactoryDiscovery::findRequestFactory(), + Psr17FactoryDiscovery::findStreamFactory(), + ); + } +} diff --git a/vendor/open-telemetry/sdk/Common/Export/Http/PsrUtils.php b/vendor/open-telemetry/sdk/Common/Export/Http/PsrUtils.php new file mode 100644 index 000000000..eaf2f3b47 --- /dev/null +++ b/vendor/open-telemetry/sdk/Common/Export/Http/PsrUtils.php @@ -0,0 +1,175 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Common\Export\Http; + +use function array_filter; +use function array_map; +use function count; +use ErrorException; +use LogicException; +use function max; +use OpenTelemetry\SDK\Common\Export\TransportFactoryInterface; +use Psr\Http\Message\ResponseInterface; +use function rand; +use function restore_error_handler; +use function set_error_handler; +use function sprintf; +use function strcasecmp; +use function strtotime; +use Throwable; +use function time; +use function trim; +use UnexpectedValueException; + +/** + * @internal + */ +final class PsrUtils +{ + /** + * @param int $retry zero-indexed attempt number + * @param int $retryDelay initial delay in milliseconds + * @param ResponseInterface|null $response response of failed request + * @return float delay in seconds + */ + public static function retryDelay(int $retry, int $retryDelay, ?ResponseInterface $response = null): float + { + $delay = $retryDelay << $retry; + $delay = rand($delay >> 1, $delay) / 1000; + + return max($delay, self::parseRetryAfter($response)); + } + + private static function parseRetryAfter(?ResponseInterface $response): int + { + if (!$response || !$retryAfter = $response->getHeaderLine('Retry-After')) { + return 0; + } + + $retryAfter = trim($retryAfter, " \t"); + if ($retryAfter === (string) (int) $retryAfter) { + return (int) $retryAfter; + } + + if (($time = strtotime($retryAfter)) !== false) { + return $time - time(); + } + + return 0; + } + + /** + * @param list<string> $encodings + * @param array<int, string>|null $appliedEncodings + */ + public static function encode(string $value, array $encodings, ?array &$appliedEncodings = null): string + { + for ($i = 0, $n = count($encodings); $i < $n; $i++) { + if (!$encoder = self::encoder($encodings[$i])) { + unset($encodings[$i]); + + continue; + } + + try { + $value = $encoder($value); + } catch (Throwable $e) { + unset($encodings[$i]); + } + } + + $appliedEncodings = $encodings; + + return $value; + } + + /** + * @param list<string> $encodings + */ + public static function decode(string $value, array $encodings): string + { + for ($i = count($encodings); --$i >= 0;) { + if (strcasecmp($encodings[$i], 'identity') === 0) { + continue; + } + if (!$decoder = self::decoder($encodings[$i])) { + throw new UnexpectedValueException(sprintf('Not supported decompression encoding "%s"', $encodings[$i])); + } + + $value = $decoder($value); + } + + return $value; + } + + /** + * Resolve an array or CSV of compression types to a list + */ + public static function compression($compression): array + { + if (is_array($compression)) { + return $compression; + } + if (!$compression) { + return []; + } + if (strpos($compression, ',') === false) { + return [$compression]; + } + + return array_map('trim', explode(',', $compression)); + } + + private static function encoder(string $encoding): ?callable + { + static $encoders; + + /** @noinspection SpellCheckingInspection */ + $encoders ??= array_map(fn (callable $callable): callable => self::throwOnErrorOrFalse($callable), array_filter([ + TransportFactoryInterface::COMPRESSION_GZIP => 'gzencode', + TransportFactoryInterface::COMPRESSION_DEFLATE => 'gzcompress', + TransportFactoryInterface::COMPRESSION_BROTLI => 'brotli_compress', + ], 'function_exists')); + + return $encoders[$encoding] ?? null; + } + + private static function decoder(string $encoding): ?callable + { + static $decoders; + + /** @noinspection SpellCheckingInspection */ + $decoders ??= array_map(fn (callable $callable): callable => self::throwOnErrorOrFalse($callable), array_filter([ + TransportFactoryInterface::COMPRESSION_GZIP => 'gzdecode', + TransportFactoryInterface::COMPRESSION_DEFLATE => 'gzuncompress', + TransportFactoryInterface::COMPRESSION_BROTLI => 'brotli_uncompress', + ], 'function_exists')); + + return $decoders[$encoding] ?? null; + } + + private static function throwOnErrorOrFalse(callable $callable): callable + { + return static function (...$args) use ($callable) { + set_error_handler(static function (int $errno, string $errstr, string $errfile, int $errline): bool { + throw new ErrorException($errstr, 0, $errno, $errfile, $errline); + }); + + try { + $result = $callable(...$args); + } finally { + restore_error_handler(); + } + + /** @phan-suppress-next-line PhanPossiblyUndeclaredVariable */ + if ($result === false) { + throw new LogicException(); + } + + /** @phan-suppress-next-line PhanPossiblyUndeclaredVariable */ + return $result; + }; + } +} diff --git a/vendor/open-telemetry/sdk/Common/Export/Stream/StreamTransport.php b/vendor/open-telemetry/sdk/Common/Export/Stream/StreamTransport.php new file mode 100644 index 000000000..4b99cf756 --- /dev/null +++ b/vendor/open-telemetry/sdk/Common/Export/Stream/StreamTransport.php @@ -0,0 +1,97 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Common\Export\Stream; + +use BadMethodCallException; +use ErrorException; +use function fflush; +use function fwrite; +use OpenTelemetry\SDK\Common\Export\TransportInterface; +use OpenTelemetry\SDK\Common\Future\CancellationInterface; +use OpenTelemetry\SDK\Common\Future\CompletedFuture; +use OpenTelemetry\SDK\Common\Future\ErrorFuture; +use OpenTelemetry\SDK\Common\Future\FutureInterface; +use function restore_error_handler; +use RuntimeException; +use function set_error_handler; +use function strlen; +use Throwable; + +/** + * @internal + * + * @psalm-template CONTENT_TYPE of string + * @template-implements TransportInterface<CONTENT_TYPE> + */ +final class StreamTransport implements TransportInterface +{ + /** + * @var resource|null + */ + private $stream; + private string $contentType; + + /** + * @param resource $stream + * + * @psalm-param CONTENT_TYPE $contentType + */ + public function __construct($stream, string $contentType) + { + $this->stream = $stream; + $this->contentType = $contentType; + } + + public function contentType(): string + { + return $this->contentType; + } + + public function send(string $payload, ?CancellationInterface $cancellation = null): FutureInterface + { + if (!$this->stream) { + return new ErrorFuture(new BadMethodCallException('Transport closed')); + } + + set_error_handler(static function (int $errno, string $errstr, string $errfile, int $errline): bool { + throw new ErrorException($errstr, 0, $errno, $errfile, $errline); + }); + + try { + $bytesWritten = fwrite($this->stream, $payload); + } catch (Throwable $e) { + return new ErrorFuture($e); + } finally { + restore_error_handler(); + } + + if ($bytesWritten !== strlen($payload)) { + return new ErrorFuture(new RuntimeException(sprintf('Write failure, wrote %d of %d bytes', $bytesWritten, strlen($payload)))); + } + + return new CompletedFuture(null); + } + + public function shutdown(?CancellationInterface $cancellation = null): bool + { + if (!$this->stream) { + return false; + } + + $flush = @fflush($this->stream); + $this->stream = null; + + return $flush; + } + + public function forceFlush(?CancellationInterface $cancellation = null): bool + { + if (!$this->stream) { + return false; + } + + return @fflush($this->stream); + } +} diff --git a/vendor/open-telemetry/sdk/Common/Export/Stream/StreamTransportFactory.php b/vendor/open-telemetry/sdk/Common/Export/Stream/StreamTransportFactory.php new file mode 100644 index 000000000..59e411318 --- /dev/null +++ b/vendor/open-telemetry/sdk/Common/Export/Stream/StreamTransportFactory.php @@ -0,0 +1,118 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Common\Export\Stream; + +use ErrorException; +use function fopen; +use function implode; +use function is_resource; +use LogicException; +use OpenTelemetry\SDK\Common\Export\TransportFactoryInterface; +use OpenTelemetry\SDK\Common\Export\TransportInterface; +use function restore_error_handler; +use function set_error_handler; +use function sprintf; +use function stream_context_create; + +/** + * @psalm-internal \OpenTelemetry + */ +final class StreamTransportFactory implements TransportFactoryInterface +{ + /** + * @param string|resource $endpoint + * @param array<string, string|string[]> $headers + * @param string|string[]|null $compression + * + * @psalm-template CONTENT_TYPE of string + * @psalm-param CONTENT_TYPE $contentType + * @psalm-return TransportInterface<CONTENT_TYPE> + */ + public function create( + $endpoint, + string $contentType, + array $headers = [], + $compression = null, + float $timeout = 10., + int $retryDelay = 100, + int $maxRetries = 3, + ?string $cacert = null, + ?string $cert = null, + ?string $key = null + ): TransportInterface { + assert(!empty($endpoint)); + $stream = is_resource($endpoint) + ? $endpoint + : self::createStream( + $endpoint, + $contentType, + $headers, + $timeout, + $cacert, + $cert, + $key, + ); + + return new StreamTransport($stream, $contentType); + } + + /** + * @throws ErrorException + * @return resource + */ + private static function createStream( + string $endpoint, + string $contentType, + array $headers = [], + float $timeout = 10., + ?string $cacert = null, + ?string $cert = null, + ?string $key = null + ) { + $context = stream_context_create([ + 'http' => [ + 'method' => 'POST', + 'header' => self::createHeaderArray($contentType, $headers), + 'timeout' => $timeout, + ], + 'ssl' => [ + 'cafile' => $cacert, + 'local_cert' => $cert, + 'local_pk' => $key, + ], + ]); + + set_error_handler(static function (int $errno, string $errstr, string $errfile, int $errline): bool { + throw new ErrorException($errstr, 0, $errno, $errfile, $errline); + }); + + /** + * @psalm-suppress PossiblyNullArgument + */ + try { + $stream = fopen($endpoint, 'ab', false, $context); + } finally { + restore_error_handler(); + } + + /** @phan-suppress-next-line PhanPossiblyUndeclaredVariable */ + if (!$stream) { + throw new LogicException(sprintf('Failed opening stream "%s"', $endpoint)); + } + + return $stream; + } + + private static function createHeaderArray(string $contentType, array $headers): array + { + $header = []; + $header[] = sprintf('Content-Type: %s', $contentType); + foreach ($headers as $name => $value) { + $header[] = sprintf('%s: %s', $name, implode(', ', (array) $value)); + } + + return $header; + } +} diff --git a/vendor/open-telemetry/sdk/Common/Export/TransportFactoryInterface.php b/vendor/open-telemetry/sdk/Common/Export/TransportFactoryInterface.php new file mode 100644 index 000000000..48e538443 --- /dev/null +++ b/vendor/open-telemetry/sdk/Common/Export/TransportFactoryInterface.php @@ -0,0 +1,32 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Common\Export; + +interface TransportFactoryInterface +{ + public const COMPRESSION_GZIP = 'gzip'; + public const COMPRESSION_DEFLATE = 'deflate'; + public const COMPRESSION_BROTLI = 'br'; + + /** + * @psalm-template CONTENT_TYPE of string + * @psalm-param CONTENT_TYPE $contentType + * @psalm-param array<string, string|string[]> $headers + * @psalm-param string|string[]|null $compression + * @psalm-return TransportInterface<CONTENT_TYPE> + */ + public function create( + string $endpoint, + string $contentType, + array $headers = [], + $compression = null, + float $timeout = 10., + int $retryDelay = 100, + int $maxRetries = 3, + ?string $cacert = null, + ?string $cert = null, + ?string $key = null + ): TransportInterface; +} diff --git a/vendor/open-telemetry/sdk/Common/Export/TransportInterface.php b/vendor/open-telemetry/sdk/Common/Export/TransportInterface.php new file mode 100644 index 000000000..5fb26eff8 --- /dev/null +++ b/vendor/open-telemetry/sdk/Common/Export/TransportInterface.php @@ -0,0 +1,22 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Common\Export; + +use OpenTelemetry\SDK\Common\Future\CancellationInterface; +use OpenTelemetry\SDK\Common\Future\FutureInterface; + +/** + * @psalm-template-covariant CONTENT_TYPE of string + */ +interface TransportInterface +{ + public function contentType(): string; + + public function send(string $payload, ?CancellationInterface $cancellation = null): FutureInterface; + + public function shutdown(?CancellationInterface $cancellation = null): bool; + + public function forceFlush(?CancellationInterface $cancellation = null): bool; +} diff --git a/vendor/open-telemetry/sdk/Common/Future/CancellationInterface.php b/vendor/open-telemetry/sdk/Common/Future/CancellationInterface.php new file mode 100644 index 000000000..16909ec6d --- /dev/null +++ b/vendor/open-telemetry/sdk/Common/Future/CancellationInterface.php @@ -0,0 +1,18 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Common\Future; + +use Closure; +use Throwable; + +interface CancellationInterface +{ + /** + * @param Closure(Throwable): void $callback + */ + public function subscribe(Closure $callback): string; + + public function unsubscribe(string $id): void; +} diff --git a/vendor/open-telemetry/sdk/Common/Future/CompletedFuture.php b/vendor/open-telemetry/sdk/Common/Future/CompletedFuture.php new file mode 100644 index 000000000..7f0cd6536 --- /dev/null +++ b/vendor/open-telemetry/sdk/Common/Future/CompletedFuture.php @@ -0,0 +1,48 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Common\Future; + +use Closure; +use Throwable; + +/** + * @template T + * @template-implements FutureInterface<T> + */ +final class CompletedFuture implements FutureInterface +{ + /** @var T */ + private $value; + + /** + * @param T $value + */ + public function __construct($value) + { + $this->value = $value; + } + + public function await() + { + return $this->value; + } + + public function map(Closure $closure): FutureInterface + { + $c = $closure; + unset($closure); + + try { + return new CompletedFuture($c($this->value)); + } catch (Throwable $e) { + return new ErrorFuture($e); + } + } + + public function catch(Closure $closure): FutureInterface + { + return $this; + } +} diff --git a/vendor/open-telemetry/sdk/Common/Future/ErrorFuture.php b/vendor/open-telemetry/sdk/Common/Future/ErrorFuture.php new file mode 100644 index 000000000..32cf3d995 --- /dev/null +++ b/vendor/open-telemetry/sdk/Common/Future/ErrorFuture.php @@ -0,0 +1,40 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Common\Future; + +use Closure; +use Throwable; + +final class ErrorFuture implements FutureInterface +{ + private Throwable $throwable; + + public function __construct(Throwable $throwable) + { + $this->throwable = $throwable; + } + + public function await() + { + throw $this->throwable; + } + + public function map(Closure $closure): FutureInterface + { + return $this; + } + + public function catch(Closure $closure): FutureInterface + { + $c = $closure; + unset($closure); + + try { + return new CompletedFuture($c($this->throwable)); + } catch (Throwable $e) { + return new ErrorFuture($e); + } + } +} diff --git a/vendor/open-telemetry/sdk/Common/Future/FutureInterface.php b/vendor/open-telemetry/sdk/Common/Future/FutureInterface.php new file mode 100644 index 000000000..850699bf6 --- /dev/null +++ b/vendor/open-telemetry/sdk/Common/Future/FutureInterface.php @@ -0,0 +1,34 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Common\Future; + +use Closure; + +/** + * @template-covariant T + */ +interface FutureInterface +{ + /** + * @psalm-return T + */ + public function await(); + + /** + * @psalm-template U + * @psalm-param Closure(T): U $closure + * @psalm-return FutureInterface<U> + * + * @psalm-suppress InvalidTemplateParam + */ + public function map(Closure $closure): FutureInterface; + + /** + * @psalm-template U + * @psalm-param Closure(\Throwable): U $closure + * @psalm-return FutureInterface<T|U> + */ + public function catch(Closure $closure): FutureInterface; +} diff --git a/vendor/open-telemetry/sdk/Common/Future/NullCancellation.php b/vendor/open-telemetry/sdk/Common/Future/NullCancellation.php new file mode 100644 index 000000000..5e5b642f9 --- /dev/null +++ b/vendor/open-telemetry/sdk/Common/Future/NullCancellation.php @@ -0,0 +1,20 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Common\Future; + +use Closure; + +final class NullCancellation implements CancellationInterface +{ + public function subscribe(Closure $callback): string + { + return self::class; + } + + public function unsubscribe(string $id): void + { + // no-op + } +} diff --git a/vendor/open-telemetry/sdk/Common/Http/DependencyResolverInterface.php b/vendor/open-telemetry/sdk/Common/Http/DependencyResolverInterface.php new file mode 100644 index 000000000..824335213 --- /dev/null +++ b/vendor/open-telemetry/sdk/Common/Http/DependencyResolverInterface.php @@ -0,0 +1,13 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Common\Http; + +use OpenTelemetry\SDK\Common\Http\HttpPlug\Client\ResolverInterface as HttpPlugClientResolverInterface; +use OpenTelemetry\SDK\Common\Http\Psr\Client\ResolverInterface as PsrClientResolverInterface; +use OpenTelemetry\SDK\Common\Http\Psr\Message\FactoryResolverInterface; + +interface DependencyResolverInterface extends FactoryResolverInterface, PsrClientResolverInterface, HttpPlugClientResolverInterface +{ +} diff --git a/vendor/open-telemetry/sdk/Common/Http/HttpPlug/Client/ResolverInterface.php b/vendor/open-telemetry/sdk/Common/Http/HttpPlug/Client/ResolverInterface.php new file mode 100644 index 000000000..3b2f4d53e --- /dev/null +++ b/vendor/open-telemetry/sdk/Common/Http/HttpPlug/Client/ResolverInterface.php @@ -0,0 +1,12 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Common\Http\HttpPlug\Client; + +use Http\Client\HttpAsyncClient; + +interface ResolverInterface +{ + public function resolveHttpPlugAsyncClient(): HttpAsyncClient; +} diff --git a/vendor/open-telemetry/sdk/Common/Http/Psr/Client/ResolverInterface.php b/vendor/open-telemetry/sdk/Common/Http/Psr/Client/ResolverInterface.php new file mode 100644 index 000000000..ba028e38a --- /dev/null +++ b/vendor/open-telemetry/sdk/Common/Http/Psr/Client/ResolverInterface.php @@ -0,0 +1,12 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Common\Http\Psr\Client; + +use Psr\Http\Client\ClientInterface; + +interface ResolverInterface +{ + public function resolvePsrClient(): ClientInterface; +} diff --git a/vendor/open-telemetry/sdk/Common/Http/Psr/Message/FactoryResolverInterface.php b/vendor/open-telemetry/sdk/Common/Http/Psr/Message/FactoryResolverInterface.php new file mode 100644 index 000000000..4582e19ce --- /dev/null +++ b/vendor/open-telemetry/sdk/Common/Http/Psr/Message/FactoryResolverInterface.php @@ -0,0 +1,22 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Common\Http\Psr\Message; + +use Psr\Http\Message\RequestFactoryInterface; +use Psr\Http\Message\ResponseFactoryInterface; +use Psr\Http\Message\ServerRequestFactoryInterface; +use Psr\Http\Message\StreamFactoryInterface; +use Psr\Http\Message\UploadedFileFactoryInterface; +use Psr\Http\Message\UriFactoryInterface; + +interface FactoryResolverInterface +{ + public function resolveRequestFactory(): RequestFactoryInterface; + public function resolveResponseFactory(): ResponseFactoryInterface; + public function resolveServerRequestFactory(): ServerRequestFactoryInterface; + public function resolveStreamFactory(): StreamFactoryInterface; + public function resolveUploadedFileFactory(): UploadedFileFactoryInterface; + public function resolveUriFactory(): UriFactoryInterface; +} diff --git a/vendor/open-telemetry/sdk/Common/Http/Psr/Message/MessageFactory.php b/vendor/open-telemetry/sdk/Common/Http/Psr/Message/MessageFactory.php new file mode 100644 index 000000000..8e99d64c0 --- /dev/null +++ b/vendor/open-telemetry/sdk/Common/Http/Psr/Message/MessageFactory.php @@ -0,0 +1,52 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Common\Http\Psr\Message; + +use Psr\Http\Message\RequestFactoryInterface; +use Psr\Http\Message\RequestInterface; +use Psr\Http\Message\ResponseFactoryInterface; +use Psr\Http\Message\ResponseInterface; +use Psr\Http\Message\ServerRequestFactoryInterface; +use Psr\Http\Message\ServerRequestInterface; + +final class MessageFactory implements MessageFactoryInterface +{ + private RequestFactoryInterface $requestFactory; + private ResponseFactoryInterface $responseFactory; + private ServerRequestFactoryInterface $serverRequestFactory; + + public function __construct( + RequestFactoryInterface $requestFactory, + ResponseFactoryInterface $responseFactory, + ServerRequestFactoryInterface $serverRequestFactory + ) { + $this->requestFactory = $requestFactory; + $this->responseFactory = $responseFactory; + $this->serverRequestFactory = $serverRequestFactory; + } + + public static function create( + RequestFactoryInterface $requestFactory, + ResponseFactoryInterface $responseFactory, + ServerRequestFactoryInterface $serverRequestFactory + ): self { + return new self($requestFactory, $responseFactory, $serverRequestFactory); + } + + public function createRequest(string $method, $uri): RequestInterface + { + return $this->requestFactory->createRequest($method, $uri); + } + + public function createResponse(int $code = 200, string $reasonPhrase = ''): ResponseInterface + { + return $this->responseFactory->createResponse($code, $reasonPhrase); + } + + public function createServerRequest(string $method, $uri, array $serverParams = []): ServerRequestInterface + { + return $this->serverRequestFactory->createServerRequest($method, $uri, $serverParams); + } +} diff --git a/vendor/open-telemetry/sdk/Common/Http/Psr/Message/MessageFactoryInterface.php b/vendor/open-telemetry/sdk/Common/Http/Psr/Message/MessageFactoryInterface.php new file mode 100644 index 000000000..97258491f --- /dev/null +++ b/vendor/open-telemetry/sdk/Common/Http/Psr/Message/MessageFactoryInterface.php @@ -0,0 +1,13 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Common\Http\Psr\Message; + +use Psr\Http\Message\RequestFactoryInterface; +use Psr\Http\Message\ResponseFactoryInterface; +use Psr\Http\Message\ServerRequestFactoryInterface; + +interface MessageFactoryInterface extends RequestFactoryInterface, ServerRequestFactoryInterface, ResponseFactoryInterface +{ +} diff --git a/vendor/open-telemetry/sdk/Common/Instrumentation/InstrumentationScope.php b/vendor/open-telemetry/sdk/Common/Instrumentation/InstrumentationScope.php new file mode 100644 index 000000000..ec9b52fb0 --- /dev/null +++ b/vendor/open-telemetry/sdk/Common/Instrumentation/InstrumentationScope.php @@ -0,0 +1,46 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Common\Instrumentation; + +use OpenTelemetry\SDK\Common\Attribute\AttributesInterface; + +/** + * Represents the instrumentation scope information associated with the Tracer or Meter + */ +final class InstrumentationScope implements InstrumentationScopeInterface +{ + private string $name; + private ?string $version; + private ?string $schemaUrl; + private AttributesInterface $attributes; + + public function __construct(string $name, ?string $version, ?string $schemaUrl, AttributesInterface $attributes) + { + $this->name = $name; + $this->version = $version; + $this->schemaUrl = $schemaUrl; + $this->attributes = $attributes; + } + + public function getName(): string + { + return $this->name; + } + + public function getVersion(): ?string + { + return $this->version; + } + + public function getSchemaUrl(): ?string + { + return $this->schemaUrl; + } + + public function getAttributes(): AttributesInterface + { + return $this->attributes; + } +} diff --git a/vendor/open-telemetry/sdk/Common/Instrumentation/InstrumentationScopeFactory.php b/vendor/open-telemetry/sdk/Common/Instrumentation/InstrumentationScopeFactory.php new file mode 100644 index 000000000..f1ae7c072 --- /dev/null +++ b/vendor/open-telemetry/sdk/Common/Instrumentation/InstrumentationScopeFactory.php @@ -0,0 +1,31 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Common\Instrumentation; + +use OpenTelemetry\SDK\Common\Attribute\AttributesFactoryInterface; + +final class InstrumentationScopeFactory implements InstrumentationScopeFactoryInterface +{ + private AttributesFactoryInterface $attributesFactory; + + public function __construct(AttributesFactoryInterface $attributesFactory) + { + $this->attributesFactory = $attributesFactory; + } + + public function create( + string $name, + ?string $version = null, + ?string $schemaUrl = null, + iterable $attributes = [] + ): InstrumentationScopeInterface { + return new InstrumentationScope( + $name, + $version, + $schemaUrl, + $this->attributesFactory->builder($attributes)->build(), + ); + } +} diff --git a/vendor/open-telemetry/sdk/Common/Instrumentation/InstrumentationScopeFactoryInterface.php b/vendor/open-telemetry/sdk/Common/Instrumentation/InstrumentationScopeFactoryInterface.php new file mode 100644 index 000000000..78292de58 --- /dev/null +++ b/vendor/open-telemetry/sdk/Common/Instrumentation/InstrumentationScopeFactoryInterface.php @@ -0,0 +1,15 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Common\Instrumentation; + +interface InstrumentationScopeFactoryInterface +{ + public function create( + string $name, + ?string $version = null, + ?string $schemaUrl = null, + iterable $attributes = [] + ): InstrumentationScopeInterface; +} diff --git a/vendor/open-telemetry/sdk/Common/Instrumentation/InstrumentationScopeInterface.php b/vendor/open-telemetry/sdk/Common/Instrumentation/InstrumentationScopeInterface.php new file mode 100644 index 000000000..43ba71d89 --- /dev/null +++ b/vendor/open-telemetry/sdk/Common/Instrumentation/InstrumentationScopeInterface.php @@ -0,0 +1,18 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Common\Instrumentation; + +use OpenTelemetry\SDK\Common\Attribute\AttributesInterface; + +interface InstrumentationScopeInterface +{ + public function getName(): string; + + public function getVersion(): ?string; + + public function getSchemaUrl(): ?string; + + public function getAttributes(): AttributesInterface; +} diff --git a/vendor/open-telemetry/sdk/Common/Time/ClockFactory.php b/vendor/open-telemetry/sdk/Common/Time/ClockFactory.php new file mode 100644 index 000000000..33f4364f6 --- /dev/null +++ b/vendor/open-telemetry/sdk/Common/Time/ClockFactory.php @@ -0,0 +1,30 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Common\Time; + +final class ClockFactory implements ClockFactoryInterface +{ + private static ?ClockInterface $default = null; + + public static function create(): self + { + return new self(); + } + + public function build(): ClockInterface + { + return new SystemClock(); + } + + public static function getDefault(): ClockInterface + { + return self::$default ?? self::$default = self::create()->build(); + } + + public static function setDefault(?ClockInterface $clock): void + { + self::$default = $clock; + } +} diff --git a/vendor/open-telemetry/sdk/Common/Time/ClockFactoryInterface.php b/vendor/open-telemetry/sdk/Common/Time/ClockFactoryInterface.php new file mode 100644 index 000000000..6d9afde91 --- /dev/null +++ b/vendor/open-telemetry/sdk/Common/Time/ClockFactoryInterface.php @@ -0,0 +1,16 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Common\Time; + +interface ClockFactoryInterface +{ + public static function create(): self; + + public function build(): ClockInterface; + + public static function getDefault(): ClockInterface; + + public static function setDefault(?ClockInterface $clock): void; +} diff --git a/vendor/open-telemetry/sdk/Common/Time/ClockInterface.php b/vendor/open-telemetry/sdk/Common/Time/ClockInterface.php new file mode 100644 index 000000000..8f3170185 --- /dev/null +++ b/vendor/open-telemetry/sdk/Common/Time/ClockInterface.php @@ -0,0 +1,19 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Common\Time; + +interface ClockInterface +{ + public const MILLIS_PER_SECOND = 1_000; + public const MICROS_PER_SECOND = 1_000_000; + public const NANOS_PER_SECOND = 1_000_000_000; + public const NANOS_PER_MILLISECOND = 1_000_000; + public const NANOS_PER_MICROSECOND = 1_000; + + /** + * Returns the current epoch wall-clock timestamp in nanoseconds + */ + public function now(): int; +} diff --git a/vendor/open-telemetry/sdk/Common/Time/StopWatch.php b/vendor/open-telemetry/sdk/Common/Time/StopWatch.php new file mode 100644 index 000000000..b2abdabae --- /dev/null +++ b/vendor/open-telemetry/sdk/Common/Time/StopWatch.php @@ -0,0 +1,119 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Common\Time; + +final class StopWatch implements StopWatchInterface +{ + private const INITIAL_ELAPSED_TIME = 0; + + private ClockInterface $clock; + private bool $running = false; + private ?int $initialStartTime; + private ?int $startTime = null; + private ?int $stopTime = null; + + public function __construct(ClockInterface $clock, ?int $initialStartTime = null) + { + $this->clock = $clock; + $this->initialStartTime = $initialStartTime; + } + + public function isRunning(): bool + { + return $this->running; + } + + public function start(): void + { + // resolve start time as early as possible + $startTime = $this->time(); + + if ($this->isRunning()) { + return; + } + + $this->startTime = $startTime; + if (!$this->hasBeenStarted()) { + $this->initialStartTime = $startTime; + } + $this->running = true; + } + + public function stop(): void + { + if (!$this->isRunning()) { + return; + } + + $this->stopTime = $this->time(); + $this->running = false; + } + + public function reset(): void + { + $this->startTime = $this->initialStartTime = $this->isRunning() ? $this->time() : null; + } + + public function getElapsedTime(): int + { + if (!$this->hasBeenStarted()) { + return self::INITIAL_ELAPSED_TIME; + } + + return $this->calculateElapsedTime(); + } + + public function getLastElapsedTime(): int + { + if (!$this->hasBeenStarted()) { + return self::INITIAL_ELAPSED_TIME; + } + + return $this->calculateLastElapsedTime(); + } + + private function time(): int + { + return $this->clock->now(); + } + + private function hasBeenStarted(): bool + { + return $this->initialStartTime !== null; + } + + private function calculateElapsedTime(): int + { + $referenceTime = $this->isRunning() + ? $this->time() + : $this->getStopTime(); + + return $referenceTime - $this->getInitialStartTime(); + } + + private function calculateLastElapsedTime(): int + { + $referenceTime = $this->isRunning() + ? $this->time() + : $this->getStopTime(); + + return $referenceTime - $this->getStartTime(); + } + + private function getInitialStartTime(): ?int + { + return $this->initialStartTime; + } + + private function getStartTime(): ?int + { + return $this->startTime; + } + + private function getStopTime(): ?int + { + return $this->stopTime; + } +} diff --git a/vendor/open-telemetry/sdk/Common/Time/StopWatchFactory.php b/vendor/open-telemetry/sdk/Common/Time/StopWatchFactory.php new file mode 100644 index 000000000..f60c377fc --- /dev/null +++ b/vendor/open-telemetry/sdk/Common/Time/StopWatchFactory.php @@ -0,0 +1,44 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Common\Time; + +final class StopWatchFactory implements StopWatchFactoryInterface +{ + private static ?StopWatchInterface $default = null; + + private ClockInterface $clock; + private ?int $initialStartTime; + + public function __construct(?ClockInterface $clock = null, ?int $initialStartTime = null) + { + $this->clock = $clock ?? ClockFactory::getDefault(); + $this->initialStartTime = $initialStartTime; + } + + public static function create(?ClockInterface $clock = null, ?int $initialStartTime = null): self + { + return new self($clock, $initialStartTime); + } + + public static function fromClockFactory(ClockFactoryInterface $factory, ?int $initialStartTime = null): self + { + return self::create($factory->build(), $initialStartTime); + } + + public function build(): StopWatch + { + return new StopWatch($this->clock, $this->initialStartTime); + } + + public static function getDefault(): StopWatchInterface + { + return self::$default ?? self::$default = self::create()->build(); + } + + public static function setDefault(?StopWatchInterface $default): void + { + self::$default = $default; + } +} diff --git a/vendor/open-telemetry/sdk/Common/Time/StopWatchFactoryInterface.php b/vendor/open-telemetry/sdk/Common/Time/StopWatchFactoryInterface.php new file mode 100644 index 000000000..9750f5769 --- /dev/null +++ b/vendor/open-telemetry/sdk/Common/Time/StopWatchFactoryInterface.php @@ -0,0 +1,18 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Common\Time; + +interface StopWatchFactoryInterface +{ + public static function create(?ClockInterface $clock = null, ?int $initialStartTime = null): self; + + public static function fromClockFactory(ClockFactoryInterface $factory, ?int $initialStartTime = null): self; + + public function build(): StopWatchInterface; + + public static function getDefault(): StopWatchInterface; + + public static function setDefault(?StopWatchInterface $default): void; +} diff --git a/vendor/open-telemetry/sdk/Common/Time/StopWatchInterface.php b/vendor/open-telemetry/sdk/Common/Time/StopWatchInterface.php new file mode 100644 index 000000000..69a03b75e --- /dev/null +++ b/vendor/open-telemetry/sdk/Common/Time/StopWatchInterface.php @@ -0,0 +1,20 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Common\Time; + +interface StopWatchInterface +{ + public function isRunning(): bool; + + public function start(): void; + + public function stop(): void; + + public function reset(): void; + + public function getElapsedTime(): int; + + public function getLastElapsedTime(): int; +} diff --git a/vendor/open-telemetry/sdk/Common/Time/SystemClock.php b/vendor/open-telemetry/sdk/Common/Time/SystemClock.php new file mode 100644 index 000000000..f57e98490 --- /dev/null +++ b/vendor/open-telemetry/sdk/Common/Time/SystemClock.php @@ -0,0 +1,49 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Common\Time; + +use function hrtime; +use function microtime; + +final class SystemClock implements ClockInterface +{ + private static int $referenceTime = 0; + + public function __construct() + { + self::init(); + } + + public static function create(): self + { + return new self(); + } + + /** @inheritDoc */ + public function now(): int + { + return self::$referenceTime + hrtime(true); + } + + private static function init(): void + { + if (self::$referenceTime > 0) { + return; + } + + self::$referenceTime = self::calculateReferenceTime( + microtime(true), + hrtime(true) + ); + } + + /** + * Calculates the reference time which is later used to calculate the current wall clock time in nanoseconds by adding the current uptime. + */ + private static function calculateReferenceTime(float $wallClockMicroTime, int $upTime): int + { + return ((int) ($wallClockMicroTime * ClockInterface::NANOS_PER_SECOND)) - $upTime; + } +} diff --git a/vendor/open-telemetry/sdk/Common/Time/Util.php b/vendor/open-telemetry/sdk/Common/Time/Util.php new file mode 100644 index 000000000..e1be1f750 --- /dev/null +++ b/vendor/open-telemetry/sdk/Common/Time/Util.php @@ -0,0 +1,32 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Common\Time; + +class Util +{ + /** @psalm-pure */ + public static function nanosToMicros(int $nanoseconds): int + { + return intdiv($nanoseconds, ClockInterface::NANOS_PER_MICROSECOND); + } + + /** @psalm-pure */ + public static function nanosToMillis(int $nanoseconds): int + { + return intdiv($nanoseconds, ClockInterface::NANOS_PER_MILLISECOND); + } + + /** @psalm-pure */ + public static function secondsToNanos(int $seconds): int + { + return $seconds * ClockInterface::NANOS_PER_SECOND; + } + + /** @psalm-pure */ + public static function millisToNanos(int $milliSeconds): int + { + return $milliSeconds * ClockInterface::NANOS_PER_MILLISECOND; + } +} diff --git a/vendor/open-telemetry/sdk/Common/Util/ClassConstantAccessor.php b/vendor/open-telemetry/sdk/Common/Util/ClassConstantAccessor.php new file mode 100644 index 000000000..237e70ba5 --- /dev/null +++ b/vendor/open-telemetry/sdk/Common/Util/ClassConstantAccessor.php @@ -0,0 +1,35 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Common\Util; + +use LogicException; + +class ClassConstantAccessor +{ + public static function requireValue(string $className, string $constantName) + { + $constant = self::getFullName($className, $constantName); + + if (!defined($constant)) { + throw new LogicException( + sprintf('The class "%s" does not have a constant "%s"', $className, $constantName) + ); + } + + return constant($constant); + } + + public static function getValue(string $className, string $constantName) + { + $constant = self::getFullName($className, $constantName); + + return defined($constant) ? constant($constant) : null; + } + + private static function getFullName(string $className, string $constantName): string + { + return sprintf('%s::%s', $className, $constantName); + } +} diff --git a/vendor/open-telemetry/sdk/Common/Util/ShutdownHandler.php b/vendor/open-telemetry/sdk/Common/Util/ShutdownHandler.php new file mode 100644 index 000000000..2de6d47df --- /dev/null +++ b/vendor/open-telemetry/sdk/Common/Util/ShutdownHandler.php @@ -0,0 +1,82 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Common\Util; + +use function array_key_last; +use ArrayAccess; +use Closure; +use function register_shutdown_function; + +final class ShutdownHandler +{ + /** @var array<int, Closure>|null */ + private static ?array $handlers = null; + /** @var ArrayAccess<object, self>|null */ + private static ?ArrayAccess $weakMap = null; + + private array $ids = []; + + private function __construct() + { + } + + public function __destruct() + { + if (!self::$handlers) { + return; + } + foreach ($this->ids as $id) { + unset(self::$handlers[$id]); + } + } + + /** + * Registers a function that will be executed on shutdown. + * + * If the given function is bound to an object, then the function will only + * be executed if the bound object is still referenced on shutdown handler + * invocation. + * + * ```php + * ShutdownHandler::register([$tracerProvider, 'shutdown']); + * ``` + * + * @param callable $shutdownFunction function to register + * + * @see register_shutdown_function + */ + public static function register(callable $shutdownFunction): void + { + self::registerShutdownFunction(); + self::$handlers[] = weaken(closure($shutdownFunction), $target); + + if (!$object = $target) { + return; + } + + self::$weakMap ??= WeakMap::create(); + $handler = self::$weakMap[$object] ??= new self(); + $handler->ids[] = array_key_last(self::$handlers); + } + + private static function registerShutdownFunction(): void + { + if (self::$handlers === null) { + register_shutdown_function(static function (): void { + $handlers = self::$handlers; + self::$handlers = null; + self::$weakMap = null; + + // Push shutdown to end of queue + // @phan-suppress-next-line PhanTypeMismatchArgumentInternal + register_shutdown_function(static function (array $handlers): void { + foreach ($handlers as $handler) { + $handler(); + } + }, $handlers); + }); + } + } +} diff --git a/vendor/open-telemetry/sdk/Common/Util/WeakMap.php b/vendor/open-telemetry/sdk/Common/Util/WeakMap.php new file mode 100644 index 000000000..3b62d6d64 --- /dev/null +++ b/vendor/open-telemetry/sdk/Common/Util/WeakMap.php @@ -0,0 +1,175 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Common\Util; + +use ArrayAccess; +use function assert; +use function class_exists; +use function count; +use Countable; +use Error; +use function get_class; +use function is_object; +use IteratorAggregate; +use const PHP_VERSION_ID; +use function spl_object_id; +use function sprintf; +use Traversable; +use TypeError; +use WeakReference; + +/** + * @internal + */ +final class WeakMap implements ArrayAccess, Countable, IteratorAggregate +{ + private const KEY = '__otel_weak_map'; + + /** + * @var array<int, WeakReference> + */ + private array $objects = []; + + private function __construct() + { + } + + /** + * @return ArrayAccess&Countable&IteratorAggregate + */ + public static function create(): ArrayAccess + { + if (PHP_VERSION_ID >= 80000) { + /** @phan-suppress-next-line PhanUndeclaredClassReference */ + assert(class_exists(\WeakMap::class, false)); + /** @phan-suppress-next-line PhanUndeclaredClassMethod */ + $map = new \WeakMap(); + assert($map instanceof ArrayAccess); + assert($map instanceof Countable); + assert($map instanceof IteratorAggregate); + + return $map; + } + + return new self(); + } + + public function offsetExists($offset): bool + { + if (!is_object($offset)) { + throw new TypeError('WeakMap key must be an object'); + } + + return isset($offset->{self::KEY}[spl_object_id($this)]); + } + + /** + * @phan-suppress PhanUndeclaredClassAttribute + */ + #[\ReturnTypeWillChange] + public function offsetGet($offset) + { + if (!is_object($offset)) { + throw new TypeError('WeakMap key must be an object'); + } + if (!$this->contains($offset)) { + throw new Error(sprintf('Object %s#%d not contained in WeakMap', get_class($offset), spl_object_id($offset))); + } + + return $offset->{self::KEY}[spl_object_id($this)]; + } + + public function offsetSet($offset, $value): void + { + if ($offset === null) { + throw new Error('Cannot append to WeakMap'); + } + if (!is_object($offset)) { + throw new TypeError('WeakMap key must be an object'); + } + if (!$this->contains($offset)) { + $this->expunge(); + } + + $offset->{self::KEY}[spl_object_id($this)] = $value; + $this->objects[spl_object_id($offset)] = WeakReference::create($offset); + } + + public function offsetUnset($offset): void + { + if (!is_object($offset)) { + throw new TypeError('WeakMap key must be an object'); + } + if (!$this->contains($offset)) { + return; + } + + unset( + $offset->{self::KEY}[spl_object_id($this)], + $this->objects[spl_object_id($offset)], + ); + if (!$offset->{self::KEY}) { + unset($offset->{self::KEY}); + } + } + + public function count(): int + { + $this->expunge(); + + return count($this->objects); + } + + public function getIterator(): Traversable + { + $this->expunge(); + + foreach ($this->objects as $reference) { + if (($object = $reference->get()) && $this->contains($object)) { + yield $object => $this[$object]; + } + } + } + + public function __debugInfo(): array + { + $debugInfo = []; + foreach ($this as $key => $value) { + $debugInfo[] = ['key' => $key, 'value' => $value]; + } + + return $debugInfo; + } + + public function __destruct() + { + foreach ($this->objects as $reference) { + if ($object = $reference->get()) { + unset($this[$object]); + } + } + } + + private function contains(object $offset): bool + { + $reference = $this->objects[spl_object_id($offset)] ?? null; + if ($reference && $reference->get() === $offset) { + return true; + } + + unset($this->objects[spl_object_id($offset)]); + + return false; + } + + private function expunge(): void + { + foreach ($this->objects as $id => $reference) { + if (!$reference->get()) { + unset($this->objects[$id]); + } + } + } +} diff --git a/vendor/open-telemetry/sdk/Common/Util/functions.php b/vendor/open-telemetry/sdk/Common/Util/functions.php new file mode 100644 index 000000000..f4fb13b80 --- /dev/null +++ b/vendor/open-telemetry/sdk/Common/Util/functions.php @@ -0,0 +1,52 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Common\Util; + +use Closure; +use function get_class; +use ReflectionFunction; +use stdClass; +use WeakReference; + +/** + * @internal + */ +function closure(callable $callable): Closure +{ + return Closure::fromCallable($callable); +} + +/** + * @internal + * @see https://github.com/amphp/amp/blob/f682341c856b1f688026f787bef4f77eaa5c7970/src/functions.php#L140-L191 + */ +function weaken(Closure $closure, ?object &$target = null): Closure +{ + $reflection = new ReflectionFunction($closure); + if (!$target = $reflection->getClosureThis()) { + return $closure; + } + + $scope = $reflection->getClosureScopeClass(); + $name = $reflection->getShortName(); + if ($name !== '{closure}') { + /** @psalm-suppress InvalidScope @phpstan-ignore-next-line @phan-suppress-next-line PhanUndeclaredThis */ + $closure = fn (...$args) => $this->$name(...$args); + if ($scope !== null) { + $closure = $closure->bindTo(null, $scope->name); + } + } + + static $placeholder; + $placeholder ??= new stdClass(); + $closure = $closure->bindTo($placeholder); + + $ref = WeakReference::create($target); + + /** @psalm-suppress PossiblyInvalidFunctionCall */ + return $scope && get_class($target) === $scope->name && !$scope->isInternal() + ? static fn (...$args) => ($obj = $ref->get()) ? $closure->call($obj, ...$args) : null + : static fn (...$args) => ($obj = $ref->get()) ? $closure->bindTo($obj)(...$args) : null; +} diff --git a/vendor/open-telemetry/sdk/Logs/Exporter/ConsoleExporter.php b/vendor/open-telemetry/sdk/Logs/Exporter/ConsoleExporter.php new file mode 100644 index 000000000..e34fa308c --- /dev/null +++ b/vendor/open-telemetry/sdk/Logs/Exporter/ConsoleExporter.php @@ -0,0 +1,106 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Logs\Exporter; + +use OpenTelemetry\SDK\Common\Export\TransportInterface; +use OpenTelemetry\SDK\Common\Future\CancellationInterface; +use OpenTelemetry\SDK\Common\Future\CompletedFuture; +use OpenTelemetry\SDK\Common\Future\FutureInterface; +use OpenTelemetry\SDK\Common\Instrumentation\InstrumentationScopeInterface; +use OpenTelemetry\SDK\Logs\LogRecordExporterInterface; +use OpenTelemetry\SDK\Logs\ReadableLogRecord; +use OpenTelemetry\SDK\Resource\ResourceInfo; + +/** + * A JSON console exporter for LogRecords. This is only useful for testing; the + * output is human-readable, and is not compatible with the OTLP format. + */ +class ConsoleExporter implements LogRecordExporterInterface +{ + private TransportInterface $transport; + + public function __construct(TransportInterface $transport) + { + $this->transport = $transport; + } + + /** + * @param iterable<mixed, ReadableLogRecord> $batch + */ + public function export(iterable $batch, ?CancellationInterface $cancellation = null): FutureInterface + { + $resource = null; + $scopes = []; + foreach ($batch as $record) { + if (!$resource) { + $resource = $this->convertResource($record->getResource()); + } + $key = $this->scopeKey($record->getInstrumentationScope()); + if (!array_key_exists($key, $scopes)) { + $scopes[$key] = $this->convertInstrumentationScope($record->getInstrumentationScope()); + } + $scopes[$key]['logs'][] = $this->convertLogRecord($record); + } + $output = [ + 'resource' => $resource, + 'scopes' => array_values($scopes), + ]; + $this->transport->send(json_encode($output, JSON_PRETTY_PRINT)); + + return new CompletedFuture(true); + } + + public function forceFlush(?CancellationInterface $cancellation = null): bool + { + return true; + } + + public function shutdown(?CancellationInterface $cancellation = null): bool + { + return true; + } + private function convertLogRecord(ReadableLogRecord $record): array + { + $spanContext = $record->getSpanContext(); + + return [ + 'timestamp' => $record->getTimestamp(), + 'observed_timestamp' => $record->getObservedTimestamp(), + 'severity_number' => $record->getSeverityNumber(), + 'severity_text' => $record->getSeverityText(), + 'body' => $record->getBody(), + 'trace_id' => $spanContext !== null ? $spanContext->getTraceId() : '', + 'span_id' => $spanContext !== null ? $spanContext->getSpanId() : '', + 'trace_flags' => $spanContext !== null ? $spanContext->getTraceFlags() : null, + 'attributes' => $record->getAttributes()->toArray(), + 'dropped_attributes_count' => $record->getAttributes()->getDroppedAttributesCount(), + ]; + } + + private function convertResource(ResourceInfo $resource): array + { + return [ + 'attributes' => $resource->getAttributes()->toArray(), + 'dropped_attributes_count' => $resource->getAttributes()->getDroppedAttributesCount(), + ]; + } + + private function scopeKey(InstrumentationScopeInterface $scope): string + { + return serialize([$scope->getName(), $scope->getVersion(), $scope->getSchemaUrl(), $scope->getAttributes()]); + } + + private function convertInstrumentationScope(InstrumentationScopeInterface $scope): array + { + return [ + 'name' => $scope->getName(), + 'version' => $scope->getVersion(), + 'attributes' => $scope->getAttributes()->toArray(), + 'dropped_attributes_count' => $scope->getAttributes()->getDroppedAttributesCount(), + 'schema_url' => $scope->getSchemaUrl(), + 'logs' => [], + ]; + } +} diff --git a/vendor/open-telemetry/sdk/Logs/Exporter/ConsoleExporterFactory.php b/vendor/open-telemetry/sdk/Logs/Exporter/ConsoleExporterFactory.php new file mode 100644 index 000000000..a959540a0 --- /dev/null +++ b/vendor/open-telemetry/sdk/Logs/Exporter/ConsoleExporterFactory.php @@ -0,0 +1,19 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Logs\Exporter; + +use OpenTelemetry\SDK\Logs\LogRecordExporterFactoryInterface; +use OpenTelemetry\SDK\Logs\LogRecordExporterInterface; +use OpenTelemetry\SDK\Registry; + +class ConsoleExporterFactory implements LogRecordExporterFactoryInterface +{ + public function create(): LogRecordExporterInterface + { + $transport = Registry::transportFactory('stream')->create('php://stdout', 'application/json'); + + return new ConsoleExporter($transport); + } +} diff --git a/vendor/open-telemetry/sdk/Logs/Exporter/InMemoryExporter.php b/vendor/open-telemetry/sdk/Logs/Exporter/InMemoryExporter.php new file mode 100644 index 000000000..dca0531f3 --- /dev/null +++ b/vendor/open-telemetry/sdk/Logs/Exporter/InMemoryExporter.php @@ -0,0 +1,48 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Logs\Exporter; + +use ArrayObject; +use OpenTelemetry\SDK\Common\Future\CancellationInterface; +use OpenTelemetry\SDK\Common\Future\CompletedFuture; +use OpenTelemetry\SDK\Common\Future\FutureInterface; +use OpenTelemetry\SDK\Logs\LogRecordExporterInterface; + +class InMemoryExporter implements LogRecordExporterInterface +{ + private ArrayObject $storage; + + public function __construct(?ArrayObject $storage = null) + { + $this->storage = $storage ?? new ArrayObject(); + } + + /** + * @inheritDoc + */ + public function export(iterable $batch, ?CancellationInterface $cancellation = null): FutureInterface + { + foreach ($batch as $record) { + $this->storage[] = $record; + } + + return new CompletedFuture(true); + } + + public function forceFlush(?CancellationInterface $cancellation = null): bool + { + return true; + } + + public function shutdown(?CancellationInterface $cancellation = null): bool + { + return true; + } + + public function getStorage(): ArrayObject + { + return $this->storage; + } +} diff --git a/vendor/open-telemetry/sdk/Logs/Exporter/InMemoryExporterFactory.php b/vendor/open-telemetry/sdk/Logs/Exporter/InMemoryExporterFactory.php new file mode 100644 index 000000000..6f24defe0 --- /dev/null +++ b/vendor/open-telemetry/sdk/Logs/Exporter/InMemoryExporterFactory.php @@ -0,0 +1,16 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Logs\Exporter; + +use OpenTelemetry\SDK\Logs\LogRecordExporterFactoryInterface; +use OpenTelemetry\SDK\Logs\LogRecordExporterInterface; + +class InMemoryExporterFactory implements LogRecordExporterFactoryInterface +{ + public function create(): LogRecordExporterInterface + { + return new InMemoryExporter(); + } +} diff --git a/vendor/open-telemetry/sdk/Logs/Exporter/NoopExporter.php b/vendor/open-telemetry/sdk/Logs/Exporter/NoopExporter.php new file mode 100644 index 000000000..8eeff62bd --- /dev/null +++ b/vendor/open-telemetry/sdk/Logs/Exporter/NoopExporter.php @@ -0,0 +1,28 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Logs\Exporter; + +use OpenTelemetry\SDK\Common\Future\CancellationInterface; +use OpenTelemetry\SDK\Common\Future\CompletedFuture; +use OpenTelemetry\SDK\Common\Future\FutureInterface; +use OpenTelemetry\SDK\Logs\LogRecordExporterInterface; + +class NoopExporter implements LogRecordExporterInterface +{ + public function export(iterable $batch, ?CancellationInterface $cancellation = null): FutureInterface + { + return new CompletedFuture(true); + } + + 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/Logs/Exporter/_register.php b/vendor/open-telemetry/sdk/Logs/Exporter/_register.php new file mode 100644 index 000000000..96958baa8 --- /dev/null +++ b/vendor/open-telemetry/sdk/Logs/Exporter/_register.php @@ -0,0 +1,6 @@ +<?php + +declare(strict_types=1); + +\OpenTelemetry\SDK\Registry::registerLogRecordExporterFactory('console', \OpenTelemetry\SDK\Logs\Exporter\ConsoleExporterFactory::class); +\OpenTelemetry\SDK\Registry::registerLogRecordExporterFactory('memory', \OpenTelemetry\SDK\Logs\Exporter\InMemoryExporterFactory::class); diff --git a/vendor/open-telemetry/sdk/Logs/ExporterFactory.php b/vendor/open-telemetry/sdk/Logs/ExporterFactory.php new file mode 100644 index 000000000..2a560ae95 --- /dev/null +++ b/vendor/open-telemetry/sdk/Logs/ExporterFactory.php @@ -0,0 +1,29 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Logs; + +use InvalidArgumentException; +use OpenTelemetry\SDK\Common\Configuration\Configuration; +use OpenTelemetry\SDK\Common\Configuration\Variables; +use OpenTelemetry\SDK\Logs\Exporter\NoopExporter; +use OpenTelemetry\SDK\Registry; + +class ExporterFactory +{ + public function create(): LogRecordExporterInterface + { + $exporters = Configuration::getList(Variables::OTEL_LOGS_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 new NoopExporter(); + } + $factory = Registry::logRecordExporterFactory($exporter); + + return $factory->create(); + } +} diff --git a/vendor/open-telemetry/sdk/Logs/LogRecordExporterFactoryInterface.php b/vendor/open-telemetry/sdk/Logs/LogRecordExporterFactoryInterface.php new file mode 100644 index 000000000..523bec1ba --- /dev/null +++ b/vendor/open-telemetry/sdk/Logs/LogRecordExporterFactoryInterface.php @@ -0,0 +1,10 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Logs; + +interface LogRecordExporterFactoryInterface +{ + public function create(): LogRecordExporterInterface; +} diff --git a/vendor/open-telemetry/sdk/Logs/LogRecordExporterInterface.php b/vendor/open-telemetry/sdk/Logs/LogRecordExporterInterface.php new file mode 100644 index 000000000..cf9e1aca8 --- /dev/null +++ b/vendor/open-telemetry/sdk/Logs/LogRecordExporterInterface.php @@ -0,0 +1,18 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Logs; + +use OpenTelemetry\SDK\Common\Future\CancellationInterface; +use OpenTelemetry\SDK\Common\Future\FutureInterface; + +interface LogRecordExporterInterface +{ + /** + * @param iterable<ReadableLogRecord> $batch + */ + public function export(iterable $batch, ?CancellationInterface $cancellation = null): FutureInterface; + public function forceFlush(?CancellationInterface $cancellation = null): bool; + public function shutdown(?CancellationInterface $cancellation = null): bool; +} diff --git a/vendor/open-telemetry/sdk/Logs/LogRecordLimits.php b/vendor/open-telemetry/sdk/Logs/LogRecordLimits.php new file mode 100644 index 000000000..9f71e62ee --- /dev/null +++ b/vendor/open-telemetry/sdk/Logs/LogRecordLimits.php @@ -0,0 +1,29 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Logs; + +use OpenTelemetry\SDK\Common\Attribute\AttributesFactoryInterface; + +/** + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/logs/sdk.md#logrecord-limits + */ +class LogRecordLimits +{ + private AttributesFactoryInterface $attributesFactory; + + /** + * @internal Use {@see SpanLimitsBuilder} to create {@see SpanLimits} instance. + */ + public function __construct( + AttributesFactoryInterface $attributesFactory + ) { + $this->attributesFactory = $attributesFactory; + } + + public function getAttributeFactory(): AttributesFactoryInterface + { + return $this->attributesFactory; + } +} diff --git a/vendor/open-telemetry/sdk/Logs/LogRecordLimitsBuilder.php b/vendor/open-telemetry/sdk/Logs/LogRecordLimitsBuilder.php new file mode 100644 index 000000000..3aa5217ef --- /dev/null +++ b/vendor/open-telemetry/sdk/Logs/LogRecordLimitsBuilder.php @@ -0,0 +1,58 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Logs; + +use OpenTelemetry\SDK\Common\Attribute\Attributes; +use OpenTelemetry\SDK\Common\Configuration\Configuration; +use OpenTelemetry\SDK\Common\Configuration\Variables; +use const PHP_INT_MAX; + +class LogRecordLimitsBuilder +{ + /** @var ?int Maximum allowed attribute count per record */ + private ?int $attributeCountLimit = null; + + /** @var ?int Maximum allowed attribute value length */ + private ?int $attributeValueLengthLimit = null; + + /** + * @param int $attributeCountLimit Maximum allowed attribute count per record + */ + public function setAttributeCountLimit(int $attributeCountLimit): LogRecordLimitsBuilder + { + $this->attributeCountLimit = $attributeCountLimit; + + return $this; + } + + /** + * @param int $attributeValueLengthLimit Maximum allowed attribute value length + */ + public function setAttributeValueLengthLimit(int $attributeValueLengthLimit): LogRecordLimitsBuilder + { + $this->attributeValueLengthLimit = $attributeValueLengthLimit; + + return $this; + } + + /** + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/configuration/sdk-environment-variables.md#attribute-limits + */ + public function build(): LogRecordLimits + { + $attributeCountLimit = $this->attributeCountLimit + ?: Configuration::getInt(Variables::OTEL_LOGRECORD_ATTRIBUTE_COUNT_LIMIT); + $attributeValueLengthLimit = $this->attributeValueLengthLimit + ?: Configuration::getInt(Variables::OTEL_LOGRECORD_ATTRIBUTE_VALUE_LENGTH_LIMIT); + + if ($attributeValueLengthLimit === PHP_INT_MAX) { + $attributeValueLengthLimit = null; + } + + $attributesFactory = Attributes::factory($attributeCountLimit, $attributeValueLengthLimit); + + return new LogRecordLimits($attributesFactory); + } +} diff --git a/vendor/open-telemetry/sdk/Logs/LogRecordProcessorFactory.php b/vendor/open-telemetry/sdk/Logs/LogRecordProcessorFactory.php new file mode 100644 index 000000000..dec463735 --- /dev/null +++ b/vendor/open-telemetry/sdk/Logs/LogRecordProcessorFactory.php @@ -0,0 +1,62 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Logs; + +use InvalidArgumentException; +use OpenTelemetry\API\Metrics\MeterProviderInterface; +use OpenTelemetry\SDK\Common\Configuration\Configuration; +use OpenTelemetry\SDK\Common\Configuration\KnownValues; +use OpenTelemetry\SDK\Common\Configuration\KnownValues as Values; +use OpenTelemetry\SDK\Common\Configuration\Variables; +use OpenTelemetry\SDK\Common\Time\ClockFactory; +use OpenTelemetry\SDK\Logs\Processor\BatchLogRecordProcessor; +use OpenTelemetry\SDK\Logs\Processor\MultiLogRecordProcessor; +use OpenTelemetry\SDK\Logs\Processor\NoopLogRecordProcessor; +use OpenTelemetry\SDK\Logs\Processor\SimpleLogRecordProcessor; + +class LogRecordProcessorFactory +{ + public function create(LogRecordExporterInterface $exporter, ?MeterProviderInterface $meterProvider = null): LogRecordProcessorInterface + { + $processors = []; + $list = Configuration::getList(Variables::OTEL_PHP_LOGS_PROCESSOR); + foreach ($list as $name) { + $processors[] = $this->createProcessor($name, $exporter, $meterProvider); + } + + switch (count($processors)) { + case 0: + return NoopLogRecordProcessor::getInstance(); + case 1: + return $processors[0]; + default: + return new MultiLogRecordProcessor($processors); + } + } + + private function createProcessor(string $name, LogRecordExporterInterface $exporter, ?MeterProviderInterface $meterProvider = null): LogRecordProcessorInterface + { + switch ($name) { + case KnownValues::VALUE_BATCH: + return new BatchLogRecordProcessor( + $exporter, + ClockFactory::getDefault(), + Configuration::getInt(Variables::OTEL_BLRP_MAX_QUEUE_SIZE), + Configuration::getInt(Variables::OTEL_BLRP_SCHEDULE_DELAY), + Configuration::getInt(Variables::OTEL_BLRP_EXPORT_TIMEOUT), + Configuration::getInt(Variables::OTEL_BLRP_MAX_EXPORT_BATCH_SIZE), + true, + $meterProvider, + ); + case KnownValues::VALUE_SIMPLE: + return new SimpleLogRecordProcessor($exporter); + case Values::VALUE_NOOP: + case Values::VALUE_NONE: + return NoopLogRecordProcessor::getInstance(); + default: + throw new InvalidArgumentException('Unknown processor: ' . $name); + } + } +} diff --git a/vendor/open-telemetry/sdk/Logs/LogRecordProcessorInterface.php b/vendor/open-telemetry/sdk/Logs/LogRecordProcessorInterface.php new file mode 100644 index 000000000..1977d48fd --- /dev/null +++ b/vendor/open-telemetry/sdk/Logs/LogRecordProcessorInterface.php @@ -0,0 +1,15 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Logs; + +use OpenTelemetry\Context\ContextInterface; +use OpenTelemetry\SDK\Common\Future\CancellationInterface; + +interface LogRecordProcessorInterface +{ + public function onEmit(ReadWriteLogRecord $record, ?ContextInterface $context = null): void; + public function shutdown(?CancellationInterface $cancellation = null): bool; + public function forceFlush(?CancellationInterface $cancellation = null): bool; +} diff --git a/vendor/open-telemetry/sdk/Logs/Logger.php b/vendor/open-telemetry/sdk/Logs/Logger.php new file mode 100644 index 000000000..0b8db152d --- /dev/null +++ b/vendor/open-telemetry/sdk/Logs/Logger.php @@ -0,0 +1,37 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Logs; + +use OpenTelemetry\API\Logs\LoggerInterface; +use OpenTelemetry\API\Logs\LogRecord; +use OpenTelemetry\SDK\Common\Instrumentation\InstrumentationScopeInterface; + +/** + * Note that this logger class is deliberately NOT psr-3 compatible, per spec: "Note: this document defines a log + * backend API. The API is not intended to be called by application developers directly." + * + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/logs/bridge-api.md + */ +class Logger implements LoggerInterface +{ + private InstrumentationScopeInterface $scope; + private LoggerSharedState $loggerSharedState; + + public function __construct(LoggerSharedState $loggerSharedState, InstrumentationScopeInterface $scope) + { + $this->loggerSharedState = $loggerSharedState; + $this->scope = $scope; + } + + public function emit(LogRecord $logRecord): void + { + $readWriteLogRecord = new ReadWriteLogRecord($this->scope, $this->loggerSharedState, $logRecord); + // @see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/logs/sdk.md#onemit + $this->loggerSharedState->getProcessor()->onEmit( + $readWriteLogRecord, + $readWriteLogRecord->getContext(), + ); + } +} diff --git a/vendor/open-telemetry/sdk/Logs/LoggerProvider.php b/vendor/open-telemetry/sdk/Logs/LoggerProvider.php new file mode 100644 index 000000000..f0a8266c1 --- /dev/null +++ b/vendor/open-telemetry/sdk/Logs/LoggerProvider.php @@ -0,0 +1,56 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Logs; + +use OpenTelemetry\API\Logs\LoggerInterface; +use OpenTelemetry\API\Logs\NoopLogger; +use OpenTelemetry\SDK\Common\Future\CancellationInterface; +use OpenTelemetry\SDK\Common\Instrumentation\InstrumentationScopeFactoryInterface; +use OpenTelemetry\SDK\Resource\ResourceInfo; +use OpenTelemetry\SDK\Resource\ResourceInfoFactory; + +class LoggerProvider implements LoggerProviderInterface +{ + private LoggerSharedState $loggerSharedState; + private InstrumentationScopeFactoryInterface $instrumentationScopeFactory; + + public function __construct(LogRecordProcessorInterface $processor, InstrumentationScopeFactoryInterface $instrumentationScopeFactory, ?ResourceInfo $resource = null) + { + $this->loggerSharedState = new LoggerSharedState( + $resource ?? ResourceInfoFactory::defaultResource(), + (new LogRecordLimitsBuilder())->build(), + $processor + ); + $this->instrumentationScopeFactory = $instrumentationScopeFactory; + } + + /** + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/logs/sdk.md#logger-creation + */ + public function getLogger(string $name, ?string $version = null, ?string $schemaUrl = null, iterable $attributes = []): LoggerInterface + { + if ($this->loggerSharedState->hasShutdown()) { + return NoopLogger::getInstance(); + } + $scope = $this->instrumentationScopeFactory->create($name, $version, $schemaUrl, $attributes); + + return new Logger($this->loggerSharedState, $scope); + } + + public function shutdown(CancellationInterface $cancellation = null): bool + { + return $this->loggerSharedState->shutdown($cancellation); + } + + public function forceFlush(CancellationInterface $cancellation = null): bool + { + return $this->loggerSharedState->forceFlush($cancellation); + } + + public static function builder(): LoggerProviderBuilder + { + return new LoggerProviderBuilder(); + } +} diff --git a/vendor/open-telemetry/sdk/Logs/LoggerProviderBuilder.php b/vendor/open-telemetry/sdk/Logs/LoggerProviderBuilder.php new file mode 100644 index 000000000..37c56245c --- /dev/null +++ b/vendor/open-telemetry/sdk/Logs/LoggerProviderBuilder.php @@ -0,0 +1,55 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Logs; + +use OpenTelemetry\SDK\Common\Attribute\Attributes; +use OpenTelemetry\SDK\Common\Instrumentation\InstrumentationScopeFactory; +use OpenTelemetry\SDK\Logs\Processor\MultiLogRecordProcessor; +use OpenTelemetry\SDK\Logs\Processor\NoopLogRecordProcessor; +use OpenTelemetry\SDK\Resource\ResourceInfo; + +class LoggerProviderBuilder +{ + /** + * @var array<LogRecordProcessorInterface> + */ + private array $processors = []; + private ?ResourceInfo $resource = null; + + public function addLogRecordProcessor(LogRecordProcessorInterface $processor): self + { + $this->processors[] = $processor; + + return $this; + } + + public function setResource(ResourceInfo $resource): self + { + $this->resource = $resource; + + return $this; + } + + public function build(): LoggerProviderInterface + { + return new LoggerProvider( + $this->buildProcessor(), + new InstrumentationScopeFactory(Attributes::factory()), + $this->resource + ); + } + + private function buildProcessor(): LogRecordProcessorInterface + { + switch (count($this->processors)) { + case 0: + return NoopLogRecordProcessor::getInstance(); + case 1: + return $this->processors[0]; + default: + return new MultiLogRecordProcessor($this->processors); + } + } +} diff --git a/vendor/open-telemetry/sdk/Logs/LoggerProviderFactory.php b/vendor/open-telemetry/sdk/Logs/LoggerProviderFactory.php new file mode 100644 index 000000000..3d0e965fd --- /dev/null +++ b/vendor/open-telemetry/sdk/Logs/LoggerProviderFactory.php @@ -0,0 +1,24 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Logs; + +use OpenTelemetry\SDK\Common\Instrumentation\InstrumentationScopeFactory; +use OpenTelemetry\SDK\Metrics\MeterProviderInterface; +use OpenTelemetry\SDK\Sdk; + +class LoggerProviderFactory +{ + public function create(?MeterProviderInterface $meterProvider = null): LoggerProviderInterface + { + if (Sdk::isDisabled()) { + return NoopLoggerProvider::getInstance(); + } + $exporter = (new ExporterFactory())->create(); + $processor = (new LogRecordProcessorFactory())->create($exporter, $meterProvider); + $instrumentationScopeFactory = new InstrumentationScopeFactory((new LogRecordLimitsBuilder())->build()->getAttributeFactory()); + + return new LoggerProvider($processor, $instrumentationScopeFactory); + } +} diff --git a/vendor/open-telemetry/sdk/Logs/LoggerProviderInterface.php b/vendor/open-telemetry/sdk/Logs/LoggerProviderInterface.php new file mode 100644 index 000000000..5debb13cc --- /dev/null +++ b/vendor/open-telemetry/sdk/Logs/LoggerProviderInterface.php @@ -0,0 +1,13 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Logs; + +use OpenTelemetry\API\Logs as API; + +interface LoggerProviderInterface extends API\LoggerProviderInterface +{ + public function shutdown(): bool; + public function forceFlush(): bool; +} diff --git a/vendor/open-telemetry/sdk/Logs/LoggerSharedState.php b/vendor/open-telemetry/sdk/Logs/LoggerSharedState.php new file mode 100644 index 000000000..aeeb45518 --- /dev/null +++ b/vendor/open-telemetry/sdk/Logs/LoggerSharedState.php @@ -0,0 +1,60 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Logs; + +use OpenTelemetry\SDK\Common\Future\CancellationInterface; +use OpenTelemetry\SDK\Resource\ResourceInfo; + +class LoggerSharedState +{ + private ResourceInfo $resource; + private LogRecordProcessorInterface $processor; + private LogRecordLimits $limits; + private ?bool $shutdownResult = null; + + public function __construct( + ResourceInfo $resource, + LogRecordLimits $limits, + LogRecordProcessorInterface $processor + ) { + $this->resource = $resource; + $this->limits = $limits; + $this->processor = $processor; + } + public function hasShutdown(): bool + { + return null !== $this->shutdownResult; + } + + public function getResource(): ResourceInfo + { + return $this->resource; + } + + public function getProcessor(): LogRecordProcessorInterface + { + return $this->processor; + } + + public function getLogRecordLimits(): LogRecordLimits + { + return $this->limits; + } + + public function shutdown(?CancellationInterface $cancellation = null): bool + { + if ($this->shutdownResult !== null) { + return $this->shutdownResult; + } + $this->shutdownResult = $this->processor->shutdown($cancellation); + + return $this->shutdownResult; + } + + public function forceFlush(?CancellationInterface $cancellation = null): bool + { + return $this->processor->forceFlush($cancellation); + } +} diff --git a/vendor/open-telemetry/sdk/Logs/NoopLoggerProvider.php b/vendor/open-telemetry/sdk/Logs/NoopLoggerProvider.php new file mode 100644 index 000000000..819e02ee5 --- /dev/null +++ b/vendor/open-telemetry/sdk/Logs/NoopLoggerProvider.php @@ -0,0 +1,33 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Logs; + +use OpenTelemetry\API\Logs\LoggerInterface; +use OpenTelemetry\API\Logs\NoopLogger; + +class NoopLoggerProvider implements LoggerProviderInterface +{ + public static function getInstance(): self + { + static $instance; + + return $instance ??= new self(); + } + + public function getLogger(string $name, ?string $version = null, ?string $schemaUrl = null, iterable $attributes = []): LoggerInterface + { + return NoopLogger::getInstance(); + } + + public function shutdown(): bool + { + return true; + } + + public function forceFlush(): bool + { + return true; + } +} diff --git a/vendor/open-telemetry/sdk/Logs/Processor/BatchLogRecordProcessor.php b/vendor/open-telemetry/sdk/Logs/Processor/BatchLogRecordProcessor.php new file mode 100644 index 000000000..fc6faca54 --- /dev/null +++ b/vendor/open-telemetry/sdk/Logs/Processor/BatchLogRecordProcessor.php @@ -0,0 +1,273 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Logs\Processor; + +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\Logs\LogRecordExporterInterface; +use OpenTelemetry\SDK\Logs\LogRecordProcessorInterface; +use OpenTelemetry\SDK\Logs\ReadWriteLogRecord; +use SplQueue; +use Throwable; + +class BatchLogRecordProcessor implements LogRecordProcessorInterface +{ + use LogsMessagesTrait; + + public const DEFAULT_SCHEDULE_DELAY = 1000; + 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 LogRecordExporterInterface $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<ReadWriteLogRecord> */ + private array $batch = []; + /** @var SplQueue<list<ReadWriteLogRecord>> */ + private SplQueue $queue; + /** @var SplQueue<array{int, string, ?CancellationInterface, bool, ContextInterface}> */ + private SplQueue $flush; + + private bool $closed = false; + + public function __construct( + LogRecordExporterInterface $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.logs.log_processor.logs', + '{logs}', + 'The number of log records received by the 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.logs.log_processor.queue.limit', + '{logs}', + 'The queue size limit', + ) + ->observe(function (ObserverInterface $observer): void { + $observer->observe($this->maxQueueSize, self::ATTRIBUTES_PROCESSOR); + }); + $meter + ->createObservableUpDownCounter( + 'otel.logs.log_processor.queue.usage', + '{logs}', + '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 onEmit(ReadWriteLogRecord $record, ?ContextInterface $context = null): void + { + if ($this->closed) { + return; + } + + if ($this->queueSize === $this->maxQueueSize) { + $this->dropped++; + + return; + } + + $this->queueSize++; + $this->batch[] = $record; + $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); + } + + 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/Logs/Processor/MultiLogRecordProcessor.php b/vendor/open-telemetry/sdk/Logs/Processor/MultiLogRecordProcessor.php new file mode 100644 index 000000000..753a75df8 --- /dev/null +++ b/vendor/open-telemetry/sdk/Logs/Processor/MultiLogRecordProcessor.php @@ -0,0 +1,62 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Logs\Processor; + +use OpenTelemetry\Context\ContextInterface; +use OpenTelemetry\SDK\Common\Future\CancellationInterface; +use OpenTelemetry\SDK\Logs\LogRecordProcessorInterface; +use OpenTelemetry\SDK\Logs\ReadWriteLogRecord; + +class MultiLogRecordProcessor implements LogRecordProcessorInterface +{ + // @var LogRecordProcessorInterface[] + private array $processors = []; + + public function __construct(array $processors) + { + foreach ($processors as $processor) { + assert($processor instanceof LogRecordProcessorInterface); + $this->processors[] = $processor; + } + } + + public function onEmit(ReadWriteLogRecord $record, ?ContextInterface $context = null): void + { + foreach ($this->processors as $processor) { + $processor->onEmit($record, $context); + } + } + + /** + * Returns `true` if all processors shut down successfully, else `false` + * Subsequent calls to `shutdown` are a no-op. + */ + public function shutdown(?CancellationInterface $cancellation = null): bool + { + $result = true; + foreach ($this->processors as $processor) { + if (!$processor->shutdown($cancellation)) { + $result = false; + } + } + + return $result; + } + + /** + * Returns `true` if all processors flush successfully, else `false`. + */ + public function forceFlush(?CancellationInterface $cancellation = null): bool + { + $result = true; + foreach ($this->processors as $processor) { + if (!$processor->forceFlush($cancellation)) { + $result = false; + } + } + + return $result; + } +} diff --git a/vendor/open-telemetry/sdk/Logs/Processor/NoopLogRecordProcessor.php b/vendor/open-telemetry/sdk/Logs/Processor/NoopLogRecordProcessor.php new file mode 100644 index 000000000..7028052e1 --- /dev/null +++ b/vendor/open-telemetry/sdk/Logs/Processor/NoopLogRecordProcessor.php @@ -0,0 +1,37 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Logs\Processor; + +use OpenTelemetry\Context\ContextInterface; +use OpenTelemetry\SDK\Common\Future\CancellationInterface; +use OpenTelemetry\SDK\Logs\LogRecordProcessorInterface; +use OpenTelemetry\SDK\Logs\ReadWriteLogRecord; + +class NoopLogRecordProcessor implements LogRecordProcessorInterface +{ + public static function getInstance(): self + { + static $instance; + + return $instance ??= new self(); + } + + /** + * @codeCoverageIgnore + */ + public function onEmit(ReadWriteLogRecord $record, ?ContextInterface $context = null): void + { + } + + public function shutdown(?CancellationInterface $cancellation = null): bool + { + return true; + } + + public function forceFlush(?CancellationInterface $cancellation = null): bool + { + return true; + } +} diff --git a/vendor/open-telemetry/sdk/Logs/Processor/SimpleLogRecordProcessor.php b/vendor/open-telemetry/sdk/Logs/Processor/SimpleLogRecordProcessor.php new file mode 100644 index 000000000..f26f6607c --- /dev/null +++ b/vendor/open-telemetry/sdk/Logs/Processor/SimpleLogRecordProcessor.php @@ -0,0 +1,38 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Logs\Processor; + +use OpenTelemetry\Context\ContextInterface; +use OpenTelemetry\SDK\Common\Future\CancellationInterface; +use OpenTelemetry\SDK\Logs\LogRecordExporterInterface; +use OpenTelemetry\SDK\Logs\LogRecordProcessorInterface; +use OpenTelemetry\SDK\Logs\ReadWriteLogRecord; + +class SimpleLogRecordProcessor implements LogRecordProcessorInterface +{ + private LogRecordExporterInterface $exporter; + public function __construct(LogRecordExporterInterface $exporter) + { + $this->exporter = $exporter; + } + + /** + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/logs/sdk.md#onemit + */ + public function onEmit(ReadWriteLogRecord $record, ?ContextInterface $context = null): void + { + $this->exporter->export([$record]); + } + + public function shutdown(?CancellationInterface $cancellation = null): bool + { + return $this->exporter->shutdown($cancellation); + } + + public function forceFlush(?CancellationInterface $cancellation = null): bool + { + return $this->exporter->forceFlush($cancellation); + } +} diff --git a/vendor/open-telemetry/sdk/Logs/PsrSeverityMapperInterface.php b/vendor/open-telemetry/sdk/Logs/PsrSeverityMapperInterface.php new file mode 100644 index 000000000..3bb288c56 --- /dev/null +++ b/vendor/open-telemetry/sdk/Logs/PsrSeverityMapperInterface.php @@ -0,0 +1,50 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Logs; + +use Psr\Log\LogLevel as PsrLogLevel; + +interface PsrSeverityMapperInterface +{ + /** + * Severity code according to rfc5424 (Syslog Protocol) + * @see : https://datatracker.ietf.org/doc/html/rfc5424#page-10 + */ + public const RFC_CODE = [ + // Detailed debug information. + PsrLogLevel::DEBUG => 7, + // Interesting events. Examples: User logs in, SQL logs. + PsrLogLevel::INFO => 6, + // Normal but significant events. + PsrLogLevel::NOTICE => 5, + // Exceptional occurrences that are not errors. Examples: Use of deprecated APIs, poor use of an API, + // undesirable things that are not necessarily wrong. + PsrLogLevel::WARNING => 4, + // Runtime errors that do not require immediate action but should typically be logged and monitored. + PsrLogLevel::ERROR => 3, + // Critical conditions. Example: Application component unavailable, unexpected exception. + PsrLogLevel::CRITICAL => 2, + // Action must be taken immediately. Example: Entire website down, database unavailable, etc. + // This should trigger the alerts and wake you up. + PsrLogLevel::ALERT => 1, + // Emergency: system is unusable. + PsrLogLevel::EMERGENCY => 0, + ]; + + /** + * Mappig of OpenTelemetry SeverityNumber to PsrLogLevel. + * @see: https://github.com/open-telemetry/opentelemetry-specification/blob/v1.7.0/specification/logs/data-model.md#field-severitynumber + */ + public const SEVERITY_NUMBER = [ + PsrLogLevel::DEBUG => 5, + PsrLogLevel::INFO => 9, + PsrLogLevel::NOTICE => 10, + PsrLogLevel::WARNING => 13, + PsrLogLevel::ERROR => 17, + PsrLogLevel::CRITICAL => 18, + PsrLogLevel::ALERT => 21, + PsrLogLevel::EMERGENCY => 22, + ]; +} diff --git a/vendor/open-telemetry/sdk/Logs/ReadWriteLogRecord.php b/vendor/open-telemetry/sdk/Logs/ReadWriteLogRecord.php new file mode 100644 index 000000000..9bb4b1564 --- /dev/null +++ b/vendor/open-telemetry/sdk/Logs/ReadWriteLogRecord.php @@ -0,0 +1,9 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Logs; + +class ReadWriteLogRecord extends ReadableLogRecord +{ +} diff --git a/vendor/open-telemetry/sdk/Logs/ReadableLogRecord.php b/vendor/open-telemetry/sdk/Logs/ReadableLogRecord.php new file mode 100644 index 000000000..5c6531477 --- /dev/null +++ b/vendor/open-telemetry/sdk/Logs/ReadableLogRecord.php @@ -0,0 +1,103 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Logs; + +use OpenTelemetry\API\Logs\LogRecord; +use OpenTelemetry\API\Trace\Span; +use OpenTelemetry\API\Trace\SpanContextInterface; +use OpenTelemetry\Context\Context; +use OpenTelemetry\Context\ContextInterface; +use OpenTelemetry\SDK\Common\Attribute\AttributesInterface; +use OpenTelemetry\SDK\Common\Attribute\LogRecordAttributeValidator; +use OpenTelemetry\SDK\Common\Instrumentation\InstrumentationScopeInterface; +use OpenTelemetry\SDK\Resource\ResourceInfo; + +/** + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/logs/data-model.md#log-and-event-record-definition + * "Note: Typically this will be implemented with a new interface or (immutable) value type." + */ +class ReadableLogRecord extends LogRecord +{ + private InstrumentationScopeInterface $scope; + private LoggerSharedState $loggerSharedState; + protected AttributesInterface $convertedAttributes; + protected SpanContextInterface $spanContext; + + public function __construct(InstrumentationScopeInterface $scope, LoggerSharedState $loggerSharedState, LogRecord $logRecord) + { + $this->scope = $scope; + $this->loggerSharedState = $loggerSharedState; + + parent::__construct($logRecord->body); + $this->timestamp = $logRecord->timestamp; + $this->observedTimestamp = $logRecord->observedTimestamp + ?? (int) (microtime(true) * LogRecord::NANOS_PER_SECOND); + $this->context = $logRecord->context; + $context = $this->context ?? Context::getCurrent(); + $this->spanContext = Span::fromContext($context)->getContext(); + $this->severityNumber = $logRecord->severityNumber; + $this->severityText = $logRecord->severityText; + + //convert attributes now so that excess data is not sent to processors + $this->convertedAttributes = $this->loggerSharedState + ->getLogRecordLimits() + ->getAttributeFactory() + ->builder($logRecord->attributes, new LogRecordAttributeValidator()) + ->build(); + } + + public function getInstrumentationScope(): InstrumentationScopeInterface + { + return $this->scope; + } + + public function getResource(): ResourceInfo + { + return $this->loggerSharedState->getResource(); + } + + public function getTimestamp(): ?int + { + return $this->timestamp; + } + + public function getObservedTimestamp(): ?int + { + return $this->observedTimestamp; + } + + public function getContext(): ?ContextInterface + { + return $this->context; + } + + public function getSpanContext(): ?SpanContextInterface + { + return $this->spanContext; + } + + public function getSeverityNumber(): ?int + { + return $this->severityNumber; + } + + public function getSeverityText(): ?string + { + return $this->severityText; + } + + /** + * @return mixed|null + */ + public function getBody() + { + return $this->body; + } + + public function getAttributes(): AttributesInterface + { + return $this->convertedAttributes; + } +} diff --git a/vendor/open-telemetry/sdk/Logs/SimplePsrFileLogger.php b/vendor/open-telemetry/sdk/Logs/SimplePsrFileLogger.php new file mode 100644 index 000000000..9d9d55de6 --- /dev/null +++ b/vendor/open-telemetry/sdk/Logs/SimplePsrFileLogger.php @@ -0,0 +1,83 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Logs; + +use Psr\Log\InvalidArgumentException; +use Psr\Log\LoggerInterface; +use Psr\Log\LoggerTrait; +use Psr\Log\LogLevel; +use ReflectionClass; +use Throwable; + +class SimplePsrFileLogger implements LoggerInterface +{ + use LoggerTrait; + + private const DEFAULT_LOGGER_NAME = 'otel'; + + private static ?array $logLevels = null; + + private string $filename; + + private string $loggerName ; + + /** + * @param string $filename + */ + public function __construct(string $filename, string $loggerName = self::DEFAULT_LOGGER_NAME) + { + $this->filename = $filename; + $this->loggerName = $loggerName; + } + + /** + * @psalm-suppress MoreSpecificImplementedParamType + */ + public function log($level, $message, array $context = []): void + { + $level = strtolower($level); + + if (!in_array($level, self::getLogLevels(), true)) { + throw new InvalidArgumentException( + sprintf('Invalid Log level: "%s"', $level) + ); + } + + file_put_contents($this->filename, $this->formatLog((string) $level, (string) $message, $context), FILE_APPEND); + } + + /** + * @param string $level + * @param string $message + * @param array $context + * @return string + */ + private function formatLog(string $level, string $message, array $context = []): string + { + try { + $encodedContext = json_encode($context, JSON_THROW_ON_ERROR); + } catch (Throwable $t) { + $encodedContext = sprintf('(Could not encode context: %s)', $t->getMessage()); + } + + return sprintf( + '[%s] %s %s: %s %s%s', + date(DATE_RFC3339_EXTENDED), + $this->loggerName, + $level, + $message, + $encodedContext, + PHP_EOL + ); + } + + /** + * @return array + */ + private static function getLogLevels(): array + { + return self::$logLevels ?? self::$logLevels = (new ReflectionClass(LogLevel::class))->getConstants(); + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/Aggregation/ExplicitBucketHistogramAggregation.php b/vendor/open-telemetry/sdk/Metrics/Aggregation/ExplicitBucketHistogramAggregation.php new file mode 100644 index 000000000..d68ecd830 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/Aggregation/ExplicitBucketHistogramAggregation.php @@ -0,0 +1,167 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\Aggregation; + +use function array_fill; +use function count; +use const INF; +use const NAN; +use OpenTelemetry\Context\ContextInterface; +use OpenTelemetry\SDK\Common\Attribute\AttributesInterface; +use OpenTelemetry\SDK\Metrics\AggregationInterface; +use OpenTelemetry\SDK\Metrics\Data; + +/** + * @implements AggregationInterface<ExplicitBucketHistogramSummary> + */ +final class ExplicitBucketHistogramAggregation implements AggregationInterface +{ + /** + * @var list<float|int> + * @readonly + */ + public array $boundaries; + + /** + * @param list<float|int> $boundaries strictly ascending histogram bucket boundaries + */ + public function __construct(array $boundaries) + { + $this->boundaries = $boundaries; + } + + public function initialize(): ExplicitBucketHistogramSummary + { + return new ExplicitBucketHistogramSummary( + 0, + 0, + +INF, + -INF, + array_fill(0, count($this->boundaries) + 1, 0), + ); + } + + /** + * @param ExplicitBucketHistogramSummary $summary + */ + public function record($summary, $value, AttributesInterface $attributes, ContextInterface $context, int $timestamp): void + { + $boundariesCount = count($this->boundaries); + for ($i = 0; $i < $boundariesCount && $this->boundaries[$i] < $value; $i++) { + } + $summary->count++; + $summary->sum += $value; + $summary->min = self::min($value, $summary->min); + $summary->max = self::max($value, $summary->max); + $summary->buckets[$i]++; + } + + /** + * @param ExplicitBucketHistogramSummary $left + * @param ExplicitBucketHistogramSummary $right + */ + public function merge($left, $right): ExplicitBucketHistogramSummary + { + $count = $left->count + $right->count; + $sum = $left->sum + $right->sum; + $min = self::min($left->min, $right->min); + $max = self::max($left->max, $right->max); + $buckets = $right->buckets; + foreach ($left->buckets as $i => $bucketCount) { + $buckets[$i] += $bucketCount; + } + + return new ExplicitBucketHistogramSummary( + $count, + $sum, + $min, + $max, + $buckets, + ); + } + + /** + * @param ExplicitBucketHistogramSummary $left + * @param ExplicitBucketHistogramSummary $right + */ + public function diff($left, $right): ExplicitBucketHistogramSummary + { + $count = -$left->count + $right->count; + $sum = -$left->sum + $right->sum; + $min = $left->min > $right->min ? $right->min : NAN; + $max = $left->max < $right->max ? $right->max : NAN; + $buckets = $right->buckets; + foreach ($left->buckets as $i => $bucketCount) { + $buckets[$i] -= $bucketCount; + } + + return new ExplicitBucketHistogramSummary( + $count, + $sum, + $min, + $max, + $buckets, + ); + } + + /** + * @param array<ExplicitBucketHistogramSummary> $summaries + */ + public function toData( + array $attributes, + array $summaries, + array $exemplars, + int $startTimestamp, + int $timestamp, + $temporality + ): Data\Histogram { + $dataPoints = []; + foreach ($attributes as $key => $dataPointAttributes) { + if ($summaries[$key]->count === 0) { + continue; + } + + $dataPoints[] = new Data\HistogramDataPoint( + $summaries[$key]->count, + $summaries[$key]->sum, + $summaries[$key]->min, + $summaries[$key]->max, + $summaries[$key]->buckets, + $this->boundaries, + $dataPointAttributes, + $startTimestamp, + $timestamp, + $exemplars[$key] ?? [], + ); + } + + return new Data\Histogram( + $dataPoints, + $temporality, + ); + } + + /** + * @param float|int $left + * @param float|int $right + * @return float|int + */ + private static function min($left, $right) + { + /** @noinspection PhpConditionAlreadyCheckedInspection */ + return $left <= $right ? $left : ($right <= $left ? $right : NAN); + } + + /** + * @param float|int $left + * @param float|int $right + * @return float|int + */ + private static function max($left, $right) + { + /** @noinspection PhpConditionAlreadyCheckedInspection */ + return $left >= $right ? $left : ($right >= $left ? $right : NAN); + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/Aggregation/ExplicitBucketHistogramSummary.php b/vendor/open-telemetry/sdk/Metrics/Aggregation/ExplicitBucketHistogramSummary.php new file mode 100644 index 000000000..1878a34a0 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/Aggregation/ExplicitBucketHistogramSummary.php @@ -0,0 +1,40 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\Aggregation; + +final class ExplicitBucketHistogramSummary +{ + public int $count; + /** + * @var float|int + */ + public $sum; + /** + * @var float|int + */ + public $min; + /** + * @var float|int + */ + public $max; + /** + * @var int[] + */ + public array $buckets; + /** + * @param float|int $sum + * @param float|int $min + * @param float|int $max + * @param int[] $buckets + */ + public function __construct(int $count, $sum, $min, $max, array $buckets) + { + $this->count = $count; + $this->sum = $sum; + $this->min = $min; + $this->max = $max; + $this->buckets = $buckets; + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/Aggregation/LastValueAggregation.php b/vendor/open-telemetry/sdk/Metrics/Aggregation/LastValueAggregation.php new file mode 100644 index 000000000..aff04e315 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/Aggregation/LastValueAggregation.php @@ -0,0 +1,81 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\Aggregation; + +use OpenTelemetry\Context\ContextInterface; +use OpenTelemetry\SDK\Common\Attribute\AttributesInterface; +use OpenTelemetry\SDK\Metrics\AggregationInterface; +use OpenTelemetry\SDK\Metrics\Data; + +/** + * @implements AggregationInterface<LastValueSummary> + */ +final class LastValueAggregation implements AggregationInterface +{ + public function initialize(): LastValueSummary + { + return new LastValueSummary(null, 0); + } + + /** + * @param LastValueSummary $summary + */ + public function record($summary, $value, AttributesInterface $attributes, ContextInterface $context, int $timestamp): void + { + if ($summary->value === null || $timestamp >= $summary->timestamp) { + $summary->value = $value; + $summary->timestamp = $timestamp; + } + } + + /** + * @param LastValueSummary $left + * @param LastValueSummary $right + */ + public function merge($left, $right): LastValueSummary + { + return $right->timestamp >= $left->timestamp ? $right : $left; + } + + /** + * @param LastValueSummary $left + * @param LastValueSummary $right + */ + public function diff($left, $right): LastValueSummary + { + return $right->timestamp >= $left->timestamp ? $right : $left; + } + + /** + * @param array<LastValueSummary> $summaries + */ + public function toData( + array $attributes, + array $summaries, + array $exemplars, + int $startTimestamp, + int $timestamp, + $temporality + ): Data\Gauge { + $dataPoints = []; + foreach ($attributes as $key => $dataPointAttributes) { + if ($summaries[$key]->value === null) { + continue; + } + + $dataPoints[] = new Data\NumberDataPoint( + $summaries[$key]->value, + $dataPointAttributes, + $startTimestamp, + $timestamp, + $exemplars[$key] ?? [], + ); + } + + return new Data\Gauge( + $dataPoints, + ); + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/Aggregation/LastValueSummary.php b/vendor/open-telemetry/sdk/Metrics/Aggregation/LastValueSummary.php new file mode 100644 index 000000000..6cdb5ac9f --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/Aggregation/LastValueSummary.php @@ -0,0 +1,22 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\Aggregation; + +final class LastValueSummary +{ + /** + * @var float|int|null + */ + public $value; + public int $timestamp; + /** + * @param float|int|null $value + */ + public function __construct($value, int $timestamp) + { + $this->value = $value; + $this->timestamp = $timestamp; + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/Aggregation/SumAggregation.php b/vendor/open-telemetry/sdk/Metrics/Aggregation/SumAggregation.php new file mode 100644 index 000000000..dc317ce73 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/Aggregation/SumAggregation.php @@ -0,0 +1,91 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\Aggregation; + +use OpenTelemetry\Context\ContextInterface; +use OpenTelemetry\SDK\Common\Attribute\AttributesInterface; +use OpenTelemetry\SDK\Metrics\AggregationInterface; +use OpenTelemetry\SDK\Metrics\Data; + +/** + * @implements AggregationInterface<SumSummary> + */ +final class SumAggregation implements AggregationInterface +{ + private bool $monotonic; + + public function __construct(bool $monotonic = false) + { + $this->monotonic = $monotonic; + } + + public function initialize(): SumSummary + { + return new SumSummary(0); + } + + /** + * @param SumSummary $summary + */ + public function record($summary, $value, AttributesInterface $attributes, ContextInterface $context, int $timestamp): void + { + $summary->value += $value; + } + + /** + * @param SumSummary $left + * @param SumSummary $right + */ + public function merge($left, $right): SumSummary + { + $sum = $left->value + $right->value; + + return new SumSummary( + $sum, + ); + } + + /** + * @param SumSummary $left + * @param SumSummary $right + */ + public function diff($left, $right): SumSummary + { + $sum = -$left->value + $right->value; + + return new SumSummary( + $sum, + ); + } + + /** + * @param array<SumSummary> $summaries + */ + public function toData( + array $attributes, + array $summaries, + array $exemplars, + int $startTimestamp, + int $timestamp, + $temporality + ): Data\Sum { + $dataPoints = []; + foreach ($attributes as $key => $dataPointAttributes) { + $dataPoints[] = new Data\NumberDataPoint( + $summaries[$key]->value, + $dataPointAttributes, + $startTimestamp, + $timestamp, + $exemplars[$key] ?? [], + ); + } + + return new Data\Sum( + $dataPoints, + $temporality, + $this->monotonic, + ); + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/Aggregation/SumSummary.php b/vendor/open-telemetry/sdk/Metrics/Aggregation/SumSummary.php new file mode 100644 index 000000000..9b257193c --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/Aggregation/SumSummary.php @@ -0,0 +1,20 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\Aggregation; + +final class SumSummary +{ + /** + * @var float|int + */ + public $value; + /** + * @param float|int $value + */ + public function __construct($value) + { + $this->value = $value; + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/AggregationInterface.php b/vendor/open-telemetry/sdk/Metrics/AggregationInterface.php new file mode 100644 index 000000000..0a85207e0 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/AggregationInterface.php @@ -0,0 +1,57 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics; + +use OpenTelemetry\Context\ContextInterface; +use OpenTelemetry\SDK\Common\Attribute\AttributesInterface; +use OpenTelemetry\SDK\Metrics\Data\DataInterface; +use OpenTelemetry\SDK\Metrics\Data\Exemplar; +use OpenTelemetry\SDK\Metrics\Data\Temporality; + +/** + * @psalm-template T + */ +interface AggregationInterface +{ + /** + * @psalm-return T + */ + public function initialize(); + + /** + * @psalm-param T $summary + * @psalm-param float|int $value + */ + public function record($summary, $value, AttributesInterface $attributes, ContextInterface $context, int $timestamp): void; + + /** + * @psalm-param T $left + * @psalm-param T $right + * @psalm-return T + */ + public function merge($left, $right); + + /** + * @psalm-param T $left + * @psalm-param T $right + * @psalm-return T + */ + public function diff($left, $right); + + /** + * @param array<AttributesInterface> $attributes + * @psalm-param array<T> $summaries + * @param array<list<Exemplar>> $exemplars + * @param string|Temporality $temporality + */ + public function toData( + array $attributes, + array $summaries, + array $exemplars, + int $startTimestamp, + int $timestamp, + $temporality + ): DataInterface; +} diff --git a/vendor/open-telemetry/sdk/Metrics/AggregationTemporalitySelectorInterface.php b/vendor/open-telemetry/sdk/Metrics/AggregationTemporalitySelectorInterface.php new file mode 100644 index 000000000..f046d033d --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/AggregationTemporalitySelectorInterface.php @@ -0,0 +1,21 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics; + +use OpenTelemetry\SDK\Metrics\Data\Temporality; + +interface AggregationTemporalitySelectorInterface +{ + /** + * Returns the temporality to use for the given metric. + * + * It is recommended to return {@see MetricMetadataInterface::temporality()} + * if the exporter does not require a specific temporality. + * + * @return string|Temporality|null temporality to use, or null to signal + * that the given metric should not be exported by this exporter + */ + public function temporality(MetricMetadataInterface $metric); +} diff --git a/vendor/open-telemetry/sdk/Metrics/AttributeProcessor/FilteredAttributeProcessor.php b/vendor/open-telemetry/sdk/Metrics/AttributeProcessor/FilteredAttributeProcessor.php new file mode 100644 index 000000000..c4df8e878 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/AttributeProcessor/FilteredAttributeProcessor.php @@ -0,0 +1,33 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\AttributeProcessor; + +use OpenTelemetry\Context\ContextInterface; +use OpenTelemetry\SDK\Common\Attribute\Attributes; +use OpenTelemetry\SDK\Common\Attribute\AttributesInterface; +use OpenTelemetry\SDK\Metrics\AttributeProcessorInterface; + +/** + * @internal + */ +final class FilteredAttributeProcessor implements AttributeProcessorInterface +{ + private array $attributeKeys; + + public function __construct(array $attributeKeys) + { + $this->attributeKeys = $attributeKeys; + } + + public function process(AttributesInterface $attributes, ContextInterface $context): AttributesInterface + { + $filtered = []; + foreach ($this->attributeKeys as $key) { + $filtered[$key] = $attributes->get($key); + } + + return new Attributes($filtered, 0); + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/AttributeProcessor/IdentityAttributeProcessor.php b/vendor/open-telemetry/sdk/Metrics/AttributeProcessor/IdentityAttributeProcessor.php new file mode 100644 index 000000000..f261563ea --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/AttributeProcessor/IdentityAttributeProcessor.php @@ -0,0 +1,20 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\AttributeProcessor; + +use OpenTelemetry\Context\ContextInterface; +use OpenTelemetry\SDK\Common\Attribute\AttributesInterface; +use OpenTelemetry\SDK\Metrics\AttributeProcessorInterface; + +/** + * @internal + */ +final class IdentityAttributeProcessor implements AttributeProcessorInterface +{ + public function process(AttributesInterface $attributes, ContextInterface $context): AttributesInterface + { + return $attributes; + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/AttributeProcessorInterface.php b/vendor/open-telemetry/sdk/Metrics/AttributeProcessorInterface.php new file mode 100644 index 000000000..d2077aa39 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/AttributeProcessorInterface.php @@ -0,0 +1,16 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics; + +use OpenTelemetry\Context\ContextInterface; +use OpenTelemetry\SDK\Common\Attribute\AttributesInterface; + +/** + * @internal + */ +interface AttributeProcessorInterface +{ + public function process(AttributesInterface $attributes, ContextInterface $context): AttributesInterface; +} diff --git a/vendor/open-telemetry/sdk/Metrics/Counter.php b/vendor/open-telemetry/sdk/Metrics/Counter.php new file mode 100644 index 000000000..9cc6b75f9 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/Counter.php @@ -0,0 +1,37 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics; + +use OpenTelemetry\API\Metrics\CounterInterface; +use OpenTelemetry\SDK\Metrics\MetricRegistry\MetricWriterInterface; + +/** + * @internal + */ +final class Counter implements CounterInterface +{ + private MetricWriterInterface $writer; + private Instrument $instrument; + private ReferenceCounterInterface $referenceCounter; + + public function __construct(MetricWriterInterface $writer, Instrument $instrument, ReferenceCounterInterface $referenceCounter) + { + $this->writer = $writer; + $this->instrument = $instrument; + $this->referenceCounter = $referenceCounter; + + $this->referenceCounter->acquire(); + } + + public function __destruct() + { + $this->referenceCounter->release(); + } + + public function add($amount, iterable $attributes = [], $context = null): void + { + $this->writer->record($this->instrument, $amount, $attributes, $context); + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/Data/DataInterface.php b/vendor/open-telemetry/sdk/Metrics/Data/DataInterface.php new file mode 100644 index 000000000..7aa0c0e20 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/Data/DataInterface.php @@ -0,0 +1,9 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\Data; + +interface DataInterface +{ +} diff --git a/vendor/open-telemetry/sdk/Metrics/Data/Exemplar.php b/vendor/open-telemetry/sdk/Metrics/Data/Exemplar.php new file mode 100644 index 000000000..bd2034f75 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/Data/Exemplar.php @@ -0,0 +1,65 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\Data; + +use OpenTelemetry\SDK\Common\Attribute\AttributesInterface; + +final class Exemplar +{ + + /** + * @var int|string + */ + private $index; + /** + * @var float|int + * @readonly + */ + public $value; + /** + * @readonly + */ + public int $timestamp; + /** + * @readonly + */ + public AttributesInterface $attributes; + /** + * @readonly + */ + public ?string $traceId; + /** + * @readonly + */ + public ?string $spanId; + + /** + * @param int|string $index + * @param float|int $value + */ + public function __construct($index, $value, int $timestamp, AttributesInterface $attributes, ?string $traceId, ?string $spanId) + { + $this->index = $index; + $this->value = $value; + $this->timestamp = $timestamp; + $this->attributes = $attributes; + $this->traceId = $traceId; + $this->spanId = $spanId; + } + + /** + * @param iterable<Exemplar> $exemplars + * @return array<list<Exemplar>> + */ + public static function groupByIndex(iterable $exemplars): array + { + $grouped = []; + foreach ($exemplars as $exemplar) { + $grouped[$exemplar->index][] = $exemplar; + } + + return $grouped; + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/Data/Gauge.php b/vendor/open-telemetry/sdk/Metrics/Data/Gauge.php new file mode 100644 index 000000000..00eb50939 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/Data/Gauge.php @@ -0,0 +1,22 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\Data; + +final class Gauge implements DataInterface +{ + + /** + * @var iterable<NumberDataPoint> + * @readonly + */ + public iterable $dataPoints; + /** + * @param iterable<NumberDataPoint> $dataPoints + */ + public function __construct(iterable $dataPoints) + { + $this->dataPoints = $dataPoints; + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/Data/Histogram.php b/vendor/open-telemetry/sdk/Metrics/Data/Histogram.php new file mode 100644 index 000000000..782698026 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/Data/Histogram.php @@ -0,0 +1,29 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\Data; + +final class Histogram implements DataInterface +{ + + /** + * @var iterable<HistogramDataPoint> + * @readonly + */ + public iterable $dataPoints; + /** + * @var string|Temporality + * @readonly + */ + public $temporality; + /** + * @param iterable<HistogramDataPoint> $dataPoints + * @param string|Temporality $temporality + */ + public function __construct(iterable $dataPoints, $temporality) + { + $this->dataPoints = $dataPoints; + $this->temporality = $temporality; + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/Data/HistogramDataPoint.php b/vendor/open-telemetry/sdk/Metrics/Data/HistogramDataPoint.php new file mode 100644 index 000000000..4c9df07b4 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/Data/HistogramDataPoint.php @@ -0,0 +1,76 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\Data; + +use OpenTelemetry\SDK\Common\Attribute\AttributesInterface; + +final class HistogramDataPoint +{ + /** + * @readonly + */ + public int $count; + /** + * @var float|int + * @readonly + */ + public $sum; + /** + * @var float|int + * @readonly + */ + public $min; + /** + * @var float|int + * @readonly + */ + public $max; + /** + * @var int[] + * @readonly + */ + public array $bucketCounts; + /** + * @var list<float|int> + * @readonly + */ + public array $explicitBounds; + /** + * @readonly + */ + public AttributesInterface $attributes; + /** + * @readonly + */ + public int $startTimestamp; + /** + * @readonly + */ + public int $timestamp; + /** + * @readonly + */ + public iterable $exemplars = []; + /** + * @param float|int $sum + * @param float|int $min + * @param float|int $max + * @param int[] $bucketCounts + * @param list<float|int> $explicitBounds + */ + public function __construct(int $count, $sum, $min, $max, array $bucketCounts, array $explicitBounds, AttributesInterface $attributes, int $startTimestamp, int $timestamp, iterable $exemplars = []) + { + $this->count = $count; + $this->sum = $sum; + $this->min = $min; + $this->max = $max; + $this->bucketCounts = $bucketCounts; + $this->explicitBounds = $explicitBounds; + $this->attributes = $attributes; + $this->startTimestamp = $startTimestamp; + $this->timestamp = $timestamp; + $this->exemplars = $exemplars; + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/Data/Metric.php b/vendor/open-telemetry/sdk/Metrics/Data/Metric.php new file mode 100644 index 000000000..41fcb52dd --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/Data/Metric.php @@ -0,0 +1,46 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\Data; + +use OpenTelemetry\SDK\Common\Instrumentation\InstrumentationScopeInterface; +use OpenTelemetry\SDK\Resource\ResourceInfo; + +final class Metric +{ + /** + * @readonly + */ + public InstrumentationScopeInterface $instrumentationScope; + /** + * @readonly + */ + public ResourceInfo $resource; + /** + * @readonly + */ + public string $name; + /** + * @readonly + */ + public ?string $description; + /** + * @readonly + */ + public ?string $unit; + /** + * @readonly + */ + public DataInterface $data; + + public function __construct(InstrumentationScopeInterface $instrumentationScope, ResourceInfo $resource, string $name, ?string $unit, ?string $description, DataInterface $data) + { + $this->instrumentationScope = $instrumentationScope; + $this->resource = $resource; + $this->name = $name; + $this->description = $description; + $this->unit = $unit; + $this->data = $data; + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/Data/NumberDataPoint.php b/vendor/open-telemetry/sdk/Metrics/Data/NumberDataPoint.php new file mode 100644 index 000000000..1d00e783a --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/Data/NumberDataPoint.php @@ -0,0 +1,43 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\Data; + +use OpenTelemetry\SDK\Common\Attribute\AttributesInterface; + +final class NumberDataPoint +{ + /** + * @var float|int + * @readonly + */ + public $value; + /** + * @readonly + */ + public AttributesInterface $attributes; + /** + * @readonly + */ + public int $startTimestamp; + /** + * @readonly + */ + public int $timestamp; + /** + * @readonly + */ + public iterable $exemplars = []; + /** + * @param float|int $value + */ + public function __construct($value, AttributesInterface $attributes, int $startTimestamp, int $timestamp, iterable $exemplars = []) + { + $this->value = $value; + $this->attributes = $attributes; + $this->startTimestamp = $startTimestamp; + $this->timestamp = $timestamp; + $this->exemplars = $exemplars; + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/Data/Sum.php b/vendor/open-telemetry/sdk/Metrics/Data/Sum.php new file mode 100644 index 000000000..77c4c1021 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/Data/Sum.php @@ -0,0 +1,34 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\Data; + +final class Sum implements DataInterface +{ + + /** + * @var iterable<NumberDataPoint> + * @readonly + */ + public iterable $dataPoints; + /** + * @var string|Temporality + * @readonly + */ + public $temporality; + /** + * @readonly + */ + public bool $monotonic; + /** + * @param iterable<NumberDataPoint> $dataPoints + * @param string|Temporality $temporality + */ + public function __construct(iterable $dataPoints, $temporality, bool $monotonic) + { + $this->dataPoints = $dataPoints; + $this->temporality = $temporality; + $this->monotonic = $monotonic; + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/Data/Temporality.php b/vendor/open-telemetry/sdk/Metrics/Data/Temporality.php new file mode 100644 index 000000000..b6642ebd0 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/Data/Temporality.php @@ -0,0 +1,20 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\Data; + +/** + * Metric aggregation temporality. + * + * Has to be type-hinted as `string|Temporality` to be forward compatible. + */ +final class Temporality +{ + public const DELTA = 'Delta'; + public const CUMULATIVE = 'Cumulative'; + + private function __construct() + { + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/DefaultAggregationProviderInterface.php b/vendor/open-telemetry/sdk/Metrics/DefaultAggregationProviderInterface.php new file mode 100644 index 000000000..e5c2fcc0c --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/DefaultAggregationProviderInterface.php @@ -0,0 +1,13 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics; + +interface DefaultAggregationProviderInterface +{ + /** + * @param string|InstrumentType $instrumentType + */ + public function defaultAggregation($instrumentType): ?AggregationInterface; +} diff --git a/vendor/open-telemetry/sdk/Metrics/DefaultAggregationProviderTrait.php b/vendor/open-telemetry/sdk/Metrics/DefaultAggregationProviderTrait.php new file mode 100644 index 000000000..37c5cb110 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/DefaultAggregationProviderTrait.php @@ -0,0 +1,28 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics; + +trait DefaultAggregationProviderTrait +{ + public function defaultAggregation($instrumentType): ?AggregationInterface + { + switch ($instrumentType) { + case InstrumentType::COUNTER: + case InstrumentType::ASYNCHRONOUS_COUNTER: + return new Aggregation\SumAggregation(true); + case InstrumentType::UP_DOWN_COUNTER: + case InstrumentType::ASYNCHRONOUS_UP_DOWN_COUNTER: + return new Aggregation\SumAggregation(); + case InstrumentType::HISTOGRAM: + return new Aggregation\ExplicitBucketHistogramAggregation([0, 5, 10, 25, 50, 75, 100, 250, 500, 1000]); + case InstrumentType::ASYNCHRONOUS_GAUGE: + return new Aggregation\LastValueAggregation(); + } + + // @codeCoverageIgnoreStart + return null; + // @codeCoverageIgnoreEnd + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/Exemplar/BucketEntry.php b/vendor/open-telemetry/sdk/Metrics/Exemplar/BucketEntry.php new file mode 100644 index 000000000..3a50430ed --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/Exemplar/BucketEntry.php @@ -0,0 +1,26 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\Exemplar; + +use OpenTelemetry\SDK\Common\Attribute\AttributesInterface; + +/** + * @internal + */ +final class BucketEntry +{ + /** + * @var int|string + */ + public $index; + /** + * @var float|int + */ + public $value; + public int $timestamp; + public AttributesInterface $attributes; + public ?string $traceId = null; + public ?string $spanId = null; +} diff --git a/vendor/open-telemetry/sdk/Metrics/Exemplar/BucketStorage.php b/vendor/open-telemetry/sdk/Metrics/Exemplar/BucketStorage.php new file mode 100644 index 000000000..574ce92af --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/Exemplar/BucketStorage.php @@ -0,0 +1,92 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\Exemplar; + +use function array_fill; +use function assert; +use function count; +use OpenTelemetry\API\Trace\Span; +use OpenTelemetry\Context\ContextInterface; +use OpenTelemetry\SDK\Common\Attribute\Attributes; +use OpenTelemetry\SDK\Common\Attribute\AttributesInterface; +use OpenTelemetry\SDK\Metrics\Data\Exemplar; + +/** + * @internal + */ +final class BucketStorage +{ + /** @var array<int, BucketEntry|null> */ + private array $buckets; + + public function __construct(int $size = 0) + { + $this->buckets = array_fill(0, $size, null); + } + + /** + * @param int|string $index + * @param float|int $value + */ + public function store(int $bucket, $index, $value, AttributesInterface $attributes, ContextInterface $context, int $timestamp): void + { + assert($bucket <= count($this->buckets)); + + $exemplar = $this->buckets[$bucket] ??= new BucketEntry(); + $exemplar->index = $index; + $exemplar->value = $value; + $exemplar->timestamp = $timestamp; + $exemplar->attributes = $attributes; + + if (($spanContext = Span::fromContext($context)->getContext())->isValid()) { + $exemplar->traceId = $spanContext->getTraceId(); + $exemplar->spanId = $spanContext->getSpanId(); + } else { + $exemplar->traceId = null; + $exemplar->spanId = null; + } + } + + /** + * @param array<AttributesInterface> $dataPointAttributes + * @return array<Exemplar> + */ + public function collect(array $dataPointAttributes): array + { + $exemplars = []; + foreach ($this->buckets as $index => &$exemplar) { + if (!$exemplar) { + continue; + } + + $exemplars[$index] = new Exemplar( + $exemplar->index, + $exemplar->value, + $exemplar->timestamp, + $this->filterExemplarAttributes( + $dataPointAttributes[$exemplar->index], + $exemplar->attributes, + ), + $exemplar->traceId, + $exemplar->spanId, + ); + $exemplar = null; + } + + return $exemplars; + } + + private function filterExemplarAttributes(AttributesInterface $dataPointAttributes, AttributesInterface $exemplarAttributes): AttributesInterface + { + $attributes = []; + foreach ($exemplarAttributes as $key => $value) { + if ($dataPointAttributes->get($key) === null) { + $attributes[$key] = $value; + } + } + + return new Attributes($attributes, $exemplarAttributes->getDroppedAttributesCount()); + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/Exemplar/ExemplarFilter/AllExemplarFilter.php b/vendor/open-telemetry/sdk/Metrics/Exemplar/ExemplarFilter/AllExemplarFilter.php new file mode 100644 index 000000000..b74e738aa --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/Exemplar/ExemplarFilter/AllExemplarFilter.php @@ -0,0 +1,21 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\Exemplar\ExemplarFilter; + +use OpenTelemetry\Context\ContextInterface; +use OpenTelemetry\SDK\Common\Attribute\AttributesInterface; +use OpenTelemetry\SDK\Metrics\Exemplar\ExemplarFilterInterface; + +/** + * The exemplar spec is not yet stable, and can change at any time. + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/sdk.md#exemplar + */ +final class AllExemplarFilter implements ExemplarFilterInterface +{ + public function accepts($value, AttributesInterface $attributes, ContextInterface $context, int $timestamp): bool + { + return true; + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/Exemplar/ExemplarFilter/NoneExemplarFilter.php b/vendor/open-telemetry/sdk/Metrics/Exemplar/ExemplarFilter/NoneExemplarFilter.php new file mode 100644 index 000000000..91fdf3b55 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/Exemplar/ExemplarFilter/NoneExemplarFilter.php @@ -0,0 +1,21 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\Exemplar\ExemplarFilter; + +use OpenTelemetry\Context\ContextInterface; +use OpenTelemetry\SDK\Common\Attribute\AttributesInterface; +use OpenTelemetry\SDK\Metrics\Exemplar\ExemplarFilterInterface; + +/** + * The exemplar spec is not yet stable, and can change at any time. + * see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/sdk.md#exemplar + */ +final class NoneExemplarFilter implements ExemplarFilterInterface +{ + public function accepts($value, AttributesInterface $attributes, ContextInterface $context, int $timestamp): bool + { + return false; + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/Exemplar/ExemplarFilter/WithSampledTraceExemplarFilter.php b/vendor/open-telemetry/sdk/Metrics/Exemplar/ExemplarFilter/WithSampledTraceExemplarFilter.php new file mode 100644 index 000000000..3e800b416 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/Exemplar/ExemplarFilter/WithSampledTraceExemplarFilter.php @@ -0,0 +1,22 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\Exemplar\ExemplarFilter; + +use OpenTelemetry\API\Trace\Span; +use OpenTelemetry\Context\ContextInterface; +use OpenTelemetry\SDK\Common\Attribute\AttributesInterface; +use OpenTelemetry\SDK\Metrics\Exemplar\ExemplarFilterInterface; + +/** + * The exemplar spec is not yet stable, and can change at any time. + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/sdk.md#exemplar + */ +final class WithSampledTraceExemplarFilter implements ExemplarFilterInterface +{ + public function accepts($value, AttributesInterface $attributes, ContextInterface $context, int $timestamp): bool + { + return Span::fromContext($context)->getContext()->isSampled(); + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/Exemplar/ExemplarFilterInterface.php b/vendor/open-telemetry/sdk/Metrics/Exemplar/ExemplarFilterInterface.php new file mode 100644 index 000000000..1d5dec7b8 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/Exemplar/ExemplarFilterInterface.php @@ -0,0 +1,20 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\Exemplar; + +use OpenTelemetry\Context\ContextInterface; +use OpenTelemetry\SDK\Common\Attribute\AttributesInterface; + +/** + * The exemplar spec is not yet stable, and can change at any time. + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/sdk.md#exemplar + */ +interface ExemplarFilterInterface +{ + /** + * @param float|int $value + */ + public function accepts($value, AttributesInterface $attributes, ContextInterface $context, int $timestamp): bool; +} diff --git a/vendor/open-telemetry/sdk/Metrics/Exemplar/ExemplarReservoirInterface.php b/vendor/open-telemetry/sdk/Metrics/Exemplar/ExemplarReservoirInterface.php new file mode 100644 index 000000000..70648b919 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/Exemplar/ExemplarReservoirInterface.php @@ -0,0 +1,24 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\Exemplar; + +use OpenTelemetry\Context\ContextInterface; +use OpenTelemetry\SDK\Common\Attribute\AttributesInterface; +use OpenTelemetry\SDK\Metrics\Data\Exemplar; + +interface ExemplarReservoirInterface +{ + /** + * @param int|string $index + * @param float|int $value + */ + public function offer($index, $value, AttributesInterface $attributes, ContextInterface $context, int $timestamp): void; + + /** + * @param array<AttributesInterface> $dataPointAttributes + * @return array<Exemplar> + */ + public function collect(array $dataPointAttributes): array; +} diff --git a/vendor/open-telemetry/sdk/Metrics/Exemplar/FilteredReservoir.php b/vendor/open-telemetry/sdk/Metrics/Exemplar/FilteredReservoir.php new file mode 100644 index 000000000..0e4f24357 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/Exemplar/FilteredReservoir.php @@ -0,0 +1,36 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\Exemplar; + +use OpenTelemetry\Context\ContextInterface; +use OpenTelemetry\SDK\Common\Attribute\AttributesInterface; + +/** + * The exemplar spec is not yet stable, and can change at any time. + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/sdk.md#exemplar + */ +final class FilteredReservoir implements ExemplarReservoirInterface +{ + private ExemplarReservoirInterface $reservoir; + private ExemplarFilterInterface $filter; + + public function __construct(ExemplarReservoirInterface $reservoir, ExemplarFilterInterface $filter) + { + $this->reservoir = $reservoir; + $this->filter = $filter; + } + + public function offer($index, $value, AttributesInterface $attributes, ContextInterface $context, int $timestamp): void + { + if ($this->filter->accepts($value, $attributes, $context, $timestamp)) { + $this->reservoir->offer($index, $value, $attributes, $context, $timestamp); + } + } + + public function collect(array $dataPointAttributes): array + { + return $this->reservoir->collect($dataPointAttributes); + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/Exemplar/FixedSizeReservoir.php b/vendor/open-telemetry/sdk/Metrics/Exemplar/FixedSizeReservoir.php new file mode 100644 index 000000000..479292a4c --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/Exemplar/FixedSizeReservoir.php @@ -0,0 +1,38 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\Exemplar; + +use OpenTelemetry\Context\ContextInterface; +use OpenTelemetry\SDK\Common\Attribute\AttributesInterface; +use function random_int; + +final class FixedSizeReservoir implements ExemplarReservoirInterface +{ + private BucketStorage $storage; + private int $size; + private int $measurements = 0; + + public function __construct(int $size = 4) + { + $this->storage = new BucketStorage($size); + $this->size = $size; + } + + public function offer($index, $value, AttributesInterface $attributes, ContextInterface $context, int $timestamp): void + { + $bucket = random_int(0, $this->measurements); + $this->measurements++; + if ($bucket < $this->size) { + $this->storage->store($bucket, $index, $value, $attributes, $context, $timestamp); + } + } + + public function collect(array $dataPointAttributes): array + { + $this->measurements = 0; + + return $this->storage->collect($dataPointAttributes); + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/Exemplar/HistogramBucketReservoir.php b/vendor/open-telemetry/sdk/Metrics/Exemplar/HistogramBucketReservoir.php new file mode 100644 index 000000000..b56a1b2be --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/Exemplar/HistogramBucketReservoir.php @@ -0,0 +1,40 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\Exemplar; + +use function count; +use OpenTelemetry\Context\ContextInterface; +use OpenTelemetry\SDK\Common\Attribute\AttributesInterface; + +final class HistogramBucketReservoir implements ExemplarReservoirInterface +{ + private BucketStorage $storage; + /** + * @var list<float|int> + */ + private array $boundaries; + + /** + * @param list<float|int> $boundaries + */ + public function __construct(array $boundaries) + { + $this->storage = new BucketStorage(count($boundaries) + 1); + $this->boundaries = $boundaries; + } + + public function offer($index, $value, AttributesInterface $attributes, ContextInterface $context, int $timestamp): void + { + $boundariesCount = count($this->boundaries); + for ($i = 0; $i < $boundariesCount && $this->boundaries[$i] < $value; $i++) { + } + $this->storage->store($i, $index, $value, $attributes, $context, $timestamp); + } + + public function collect(array $dataPointAttributes): array + { + return $this->storage->collect($dataPointAttributes); + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/Exemplar/NoopReservoir.php b/vendor/open-telemetry/sdk/Metrics/Exemplar/NoopReservoir.php new file mode 100644 index 000000000..010aeff20 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/Exemplar/NoopReservoir.php @@ -0,0 +1,21 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\Exemplar; + +use OpenTelemetry\Context\ContextInterface; +use OpenTelemetry\SDK\Common\Attribute\AttributesInterface; + +final class NoopReservoir implements ExemplarReservoirInterface +{ + public function offer($index, $value, AttributesInterface $attributes, ContextInterface $context, int $timestamp): void + { + // no-op + } + + public function collect(array $dataPointAttributes): array + { + return []; + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/Histogram.php b/vendor/open-telemetry/sdk/Metrics/Histogram.php new file mode 100644 index 000000000..532b1b4bf --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/Histogram.php @@ -0,0 +1,37 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics; + +use OpenTelemetry\API\Metrics\HistogramInterface; +use OpenTelemetry\SDK\Metrics\MetricRegistry\MetricWriterInterface; + +/** + * @internal + */ +final class Histogram implements HistogramInterface +{ + private MetricWriterInterface $writer; + private Instrument $instrument; + private ReferenceCounterInterface $referenceCounter; + + public function __construct(MetricWriterInterface $writer, Instrument $instrument, ReferenceCounterInterface $referenceCounter) + { + $this->writer = $writer; + $this->instrument = $instrument; + $this->referenceCounter = $referenceCounter; + + $this->referenceCounter->acquire(); + } + + public function __destruct() + { + $this->referenceCounter->release(); + } + + public function record($amount, iterable $attributes = [], $context = null): void + { + $this->writer->record($this->instrument, $amount, $attributes, $context); + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/Instrument.php b/vendor/open-telemetry/sdk/Metrics/Instrument.php new file mode 100644 index 000000000..3543604c0 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/Instrument.php @@ -0,0 +1,36 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics; + +final class Instrument +{ + /** + * @var string|InstrumentType + * @readonly + */ + public $type; + /** + * @readonly + */ + public string $name; + /** + * @readonly + */ + public ?string $unit; + /** + * @readonly + */ + public ?string $description; + /** + * @param string|InstrumentType $type + */ + public function __construct($type, string $name, ?string $unit, ?string $description) + { + $this->type = $type; + $this->name = $name; + $this->unit = $unit; + $this->description = $description; + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/InstrumentType.php b/vendor/open-telemetry/sdk/Metrics/InstrumentType.php new file mode 100644 index 000000000..ae603b2fe --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/InstrumentType.php @@ -0,0 +1,25 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics; + +/** + * Instrument type. + * + * Has to be type-hinted as `string|InstrumentType` to be forward compatible. + */ +final class InstrumentType +{ + public const COUNTER = 'Counter'; + public const UP_DOWN_COUNTER = 'UpDownCounter'; + public const HISTOGRAM = 'Histogram'; + + public const ASYNCHRONOUS_COUNTER = 'AsynchronousCounter'; + public const ASYNCHRONOUS_UP_DOWN_COUNTER = 'AsynchronousUpDownCounter'; + public const ASYNCHRONOUS_GAUGE = 'AsynchronousGauge'; + + private function __construct() + { + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/Meter.php b/vendor/open-telemetry/sdk/Metrics/Meter.php new file mode 100644 index 000000000..902284839 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/Meter.php @@ -0,0 +1,314 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics; + +use ArrayAccess; +use OpenTelemetry\API\Metrics\CounterInterface; +use OpenTelemetry\API\Metrics\HistogramInterface; +use OpenTelemetry\API\Metrics\MeterInterface; +use OpenTelemetry\API\Metrics\ObservableCounterInterface; +use OpenTelemetry\API\Metrics\ObservableGaugeInterface; +use OpenTelemetry\API\Metrics\ObservableUpDownCounterInterface; +use OpenTelemetry\API\Metrics\UpDownCounterInterface; +use OpenTelemetry\SDK\Common\Instrumentation\InstrumentationScopeInterface; +use OpenTelemetry\SDK\Common\Time\ClockInterface; +use function OpenTelemetry\SDK\Common\Util\closure; +use OpenTelemetry\SDK\Common\Util\WeakMap; +use OpenTelemetry\SDK\Metrics\Exemplar\ExemplarFilterInterface; +use OpenTelemetry\SDK\Metrics\MetricRegistration\MultiRegistryRegistration; +use OpenTelemetry\SDK\Metrics\MetricRegistration\RegistryRegistration; +use OpenTelemetry\SDK\Metrics\MetricRegistry\MetricRegistryInterface; +use OpenTelemetry\SDK\Metrics\MetricRegistry\MetricWriterInterface; +use OpenTelemetry\SDK\Resource\ResourceInfo; +use const PHP_VERSION_ID; +use function serialize; + +/** + * @internal + */ +final class Meter implements MeterInterface +{ + private MetricFactoryInterface $metricFactory; + private ResourceInfo $resource; + private ClockInterface $clock; + private StalenessHandlerFactoryInterface $stalenessHandlerFactory; + /** @var iterable<MetricSourceRegistryInterface&DefaultAggregationProviderInterface> */ + private iterable $metricRegistries; + private ViewRegistryInterface $viewRegistry; + private ?ExemplarFilterInterface $exemplarFilter; + private MeterInstruments $instruments; + private InstrumentationScopeInterface $instrumentationScope; + + private MetricRegistryInterface $registry; + private MetricWriterInterface $writer; + + private ?string $instrumentationScopeId = null; + + /** + * @param iterable<MetricSourceRegistryInterface&DefaultAggregationProviderInterface> $metricRegistries + */ + public function __construct( + MetricFactoryInterface $metricFactory, + ResourceInfo $resource, + ClockInterface $clock, + StalenessHandlerFactoryInterface $stalenessHandlerFactory, + iterable $metricRegistries, + ViewRegistryInterface $viewRegistry, + ?ExemplarFilterInterface $exemplarFilter, + MeterInstruments $instruments, + InstrumentationScopeInterface $instrumentationScope, + MetricRegistryInterface $registry, + MetricWriterInterface $writer + ) { + $this->metricFactory = $metricFactory; + $this->resource = $resource; + $this->clock = $clock; + $this->stalenessHandlerFactory = $stalenessHandlerFactory; + $this->metricRegistries = $metricRegistries; + $this->viewRegistry = $viewRegistry; + $this->exemplarFilter = $exemplarFilter; + $this->instruments = $instruments; + $this->instrumentationScope = $instrumentationScope; + $this->registry = $registry; + $this->writer = $writer; + } + + public function createCounter(string $name, ?string $unit = null, ?string $description = null): CounterInterface + { + [$instrument, $referenceCounter] = $this->createSynchronousWriter( + InstrumentType::COUNTER, + $name, + $unit, + $description, + ); + + return new Counter($this->writer, $instrument, $referenceCounter); + } + + public function createObservableCounter(string $name, ?string $unit = null, ?string $description = null, callable ...$callbacks): ObservableCounterInterface + { + [$instrument, $referenceCounter, $destructors] = $this->createAsynchronousObserver( + InstrumentType::ASYNCHRONOUS_COUNTER, + $name, + $unit, + $description, + ); + + foreach ($callbacks as $callback) { + $this->writer->registerCallback(closure($callback), $instrument); + $referenceCounter->acquire(true); + } + + return new ObservableCounter($this->writer, $instrument, $referenceCounter, $destructors); + } + + public function createHistogram(string $name, ?string $unit = null, ?string $description = null): HistogramInterface + { + [$instrument, $referenceCounter] = $this->createSynchronousWriter( + InstrumentType::HISTOGRAM, + $name, + $unit, + $description, + ); + + return new Histogram($this->writer, $instrument, $referenceCounter); + } + + public function createObservableGauge(string $name, ?string $unit = null, ?string $description = null, callable ...$callbacks): ObservableGaugeInterface + { + [$instrument, $referenceCounter, $destructors] = $this->createAsynchronousObserver( + InstrumentType::ASYNCHRONOUS_GAUGE, + $name, + $unit, + $description, + ); + + foreach ($callbacks as $callback) { + $this->writer->registerCallback(closure($callback), $instrument); + $referenceCounter->acquire(true); + } + + return new ObservableGauge($this->writer, $instrument, $referenceCounter, $destructors); + } + + public function createUpDownCounter(string $name, ?string $unit = null, ?string $description = null): UpDownCounterInterface + { + [$instrument, $referenceCounter] = $this->createSynchronousWriter( + InstrumentType::UP_DOWN_COUNTER, + $name, + $unit, + $description, + ); + + return new UpDownCounter($this->writer, $instrument, $referenceCounter); + } + + public function createObservableUpDownCounter(string $name, ?string $unit = null, ?string $description = null, callable ...$callbacks): ObservableUpDownCounterInterface + { + [$instrument, $referenceCounter, $destructors] = $this->createAsynchronousObserver( + InstrumentType::ASYNCHRONOUS_UP_DOWN_COUNTER, + $name, + $unit, + $description, + ); + + foreach ($callbacks as $callback) { + $this->writer->registerCallback(closure($callback), $instrument); + $referenceCounter->acquire(true); + } + + return new ObservableUpDownCounter($this->writer, $instrument, $referenceCounter, $destructors); + } + + /** + * @param string|InstrumentType $instrumentType + * @return array{Instrument, ReferenceCounterInterface} + */ + private function createSynchronousWriter($instrumentType, string $name, ?string $unit, ?string $description): array + { + $instrument = new Instrument($instrumentType, $name, $unit, $description); + + $instrumentationScopeId = $this->instrumentationScopeId($this->instrumentationScope); + $instrumentId = $this->instrumentId($instrument); + + $instruments = $this->instruments; + if ($writer = $instruments->writers[$instrumentationScopeId][$instrumentId] ?? null) { + return $writer; + } + + $stalenessHandler = $this->stalenessHandlerFactory->create(); + $instruments->startTimestamp ??= $this->clock->now(); + $streamIds = $this->metricFactory->createSynchronousWriter( + $this->registry, + $this->resource, + $this->instrumentationScope, + $instrument, + $instruments->startTimestamp, + $this->viewRegistrationRequests($instrument, $stalenessHandler), + $this->exemplarFilter, + ); + + $registry = $this->registry; + $stalenessHandler->onStale(static function () use ($instruments, $instrumentationScopeId, $instrumentId, $registry, $streamIds): void { + unset($instruments->writers[$instrumentationScopeId][$instrumentId]); + if (!$instruments->writers[$instrumentationScopeId]) { + unset($instruments->writers[$instrumentationScopeId]); + } + foreach ($streamIds as $streamId) { + $registry->unregisterStream($streamId); + } + + $instruments->startTimestamp = null; + }); + + return $instruments->writers[$instrumentationScopeId][$instrumentId] = [ + $instrument, + $stalenessHandler, + ]; + } + + /** + * @param string|InstrumentType $instrumentType + * @return array{Instrument, ReferenceCounterInterface, ArrayAccess<object, ObservableCallbackDestructor>} + */ + private function createAsynchronousObserver($instrumentType, string $name, ?string $unit, ?string $description): array + { + $instrument = new Instrument($instrumentType, $name, $unit, $description); + + $instrumentationScopeId = $this->instrumentationScopeId($this->instrumentationScope); + $instrumentId = $this->instrumentId($instrument); + + $instruments = $this->instruments; + /** @phan-suppress-next-line PhanDeprecatedProperty */ + $instruments->staleObservers = []; + if ($observer = $instruments->observers[$instrumentationScopeId][$instrumentId] ?? null) { + return $observer; + } + + $stalenessHandler = $this->stalenessHandlerFactory->create(); + $instruments->startTimestamp ??= $this->clock->now(); + $streamIds = $this->metricFactory->createAsynchronousObserver( + $this->registry, + $this->resource, + $this->instrumentationScope, + $instrument, + $instruments->startTimestamp, + $this->viewRegistrationRequests($instrument, $stalenessHandler), + ); + + $registry = $this->registry; + $stalenessHandler->onStale(static function () use ($instruments, $instrumentationScopeId, $instrumentId, $registry, $streamIds): void { + if (PHP_VERSION_ID < 80000) { + /** @phan-suppress-next-line PhanDeprecatedProperty */ + $instruments->staleObservers[] = $instruments->observers[$instrumentationScopeId][$instrumentId][2]; + } + + unset($instruments->observers[$instrumentationScopeId][$instrumentId]); + if (!$instruments->observers[$instrumentationScopeId]) { + unset($instruments->observers[$instrumentationScopeId]); + } + foreach ($streamIds as $streamId) { + $registry->unregisterStream($streamId); + } + + $instruments->startTimestamp = null; + }); + + /** @var ArrayAccess<object, ObservableCallbackDestructor> $destructors */ + $destructors = WeakMap::create(); + + return $instruments->observers[$instrumentationScopeId][$instrumentId] = [ + $instrument, + $stalenessHandler, + $destructors, + ]; + } + + /** + * @return iterable<array{ViewProjection, MetricRegistrationInterface}> + */ + private function viewRegistrationRequests(Instrument $instrument, StalenessHandlerInterface $stalenessHandler): iterable + { + $views = $this->viewRegistry->find($instrument, $this->instrumentationScope) ?? [ + new ViewProjection( + $instrument->name, + $instrument->unit, + $instrument->description, + null, + null, + ), + ]; + + $compositeRegistration = new MultiRegistryRegistration($this->metricRegistries, $stalenessHandler); + foreach ($views as $view) { + if ($view->aggregation !== null) { + yield [$view, $compositeRegistration]; + } else { + foreach ($this->metricRegistries as $metricRegistry) { + yield [ + new ViewProjection( + $view->name, + $view->unit, + $view->description, + $view->attributeKeys, + $metricRegistry->defaultAggregation($instrument->type), + ), + new RegistryRegistration($metricRegistry, $stalenessHandler), + ]; + } + } + } + } + + private function instrumentationScopeId(InstrumentationScopeInterface $instrumentationScope): string + { + return $this->instrumentationScopeId ??= serialize($instrumentationScope); + } + + private function instrumentId(Instrument $instrument): string + { + return serialize($instrument); + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/MeterInstruments.php b/vendor/open-telemetry/sdk/Metrics/MeterInstruments.php new file mode 100644 index 000000000..c331cb608 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/MeterInstruments.php @@ -0,0 +1,29 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics; + +use ArrayAccess; + +/** + * @internal + */ +final class MeterInstruments +{ + public ?int $startTimestamp = null; + /** + * @var array<string, array<string, array{Instrument, ReferenceCounterInterface, ArrayAccess<object, ObservableCallbackDestructor>}>> + */ + public array $observers = []; + /** + * @var array<string, array<string, array{Instrument, ReferenceCounterInterface}>> + */ + public array $writers = []; + + /** + * @var list<ArrayAccess<object, ObservableCallbackDestructor>> + * @deprecated + */ + public array $staleObservers = []; +} diff --git a/vendor/open-telemetry/sdk/Metrics/MeterProvider.php b/vendor/open-telemetry/sdk/Metrics/MeterProvider.php new file mode 100644 index 000000000..36c17cf81 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/MeterProvider.php @@ -0,0 +1,130 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics; + +use OpenTelemetry\API\Metrics\MeterInterface; +use OpenTelemetry\API\Metrics\Noop\NoopMeter; +use OpenTelemetry\Context\ContextStorageInterface; +use OpenTelemetry\SDK\Common\Attribute\AttributesFactoryInterface; +use OpenTelemetry\SDK\Common\Instrumentation\InstrumentationScopeFactoryInterface; +use OpenTelemetry\SDK\Common\Time\ClockInterface; +use OpenTelemetry\SDK\Metrics\Exemplar\ExemplarFilterInterface; +use OpenTelemetry\SDK\Metrics\MetricFactory\StreamFactory; +use OpenTelemetry\SDK\Metrics\MetricRegistry\MetricRegistry; +use OpenTelemetry\SDK\Metrics\MetricRegistry\MetricRegistryInterface; +use OpenTelemetry\SDK\Metrics\MetricRegistry\MetricWriterInterface; +use OpenTelemetry\SDK\Resource\ResourceInfo; +use OpenTelemetry\SDK\Sdk; + +final class MeterProvider implements MeterProviderInterface +{ + private MetricFactoryInterface $metricFactory; + private ResourceInfo $resource; + private ClockInterface $clock; + private InstrumentationScopeFactoryInterface $instrumentationScopeFactory; + private iterable $metricReaders; + private ViewRegistryInterface $viewRegistry; + private ?ExemplarFilterInterface $exemplarFilter; + private StalenessHandlerFactoryInterface $stalenessHandlerFactory; + private MeterInstruments $instruments; + private MetricRegistryInterface $registry; + private MetricWriterInterface $writer; + + private bool $closed = false; + + /** + * @param iterable<MetricReaderInterface&MetricSourceRegistryInterface&DefaultAggregationProviderInterface> $metricReaders + */ + public function __construct( + ?ContextStorageInterface $contextStorage, + ResourceInfo $resource, + ClockInterface $clock, + AttributesFactoryInterface $attributesFactory, + InstrumentationScopeFactoryInterface $instrumentationScopeFactory, + iterable $metricReaders, + ViewRegistryInterface $viewRegistry, + ?ExemplarFilterInterface $exemplarFilter, + StalenessHandlerFactoryInterface $stalenessHandlerFactory, + MetricFactoryInterface $metricFactory = null + ) { + $this->metricFactory = $metricFactory ?? new StreamFactory(); + $this->resource = $resource; + $this->clock = $clock; + $this->instrumentationScopeFactory = $instrumentationScopeFactory; + $this->metricReaders = $metricReaders; + $this->viewRegistry = $viewRegistry; + $this->exemplarFilter = $exemplarFilter; + $this->stalenessHandlerFactory = $stalenessHandlerFactory; + $this->instruments = new MeterInstruments(); + + $registry = new MetricRegistry($contextStorage, $attributesFactory, $clock); + $this->registry = $registry; + $this->writer = $registry; + } + + public function getMeter( + string $name, + ?string $version = null, + ?string $schemaUrl = null, + iterable $attributes = [] + ): MeterInterface { + if ($this->closed || Sdk::isDisabled()) { //@todo create meter provider from factory, and move Sdk::isDisabled() there + return new NoopMeter(); + } + + return new Meter( + $this->metricFactory, + $this->resource, + $this->clock, + $this->stalenessHandlerFactory, + $this->metricReaders, + $this->viewRegistry, + $this->exemplarFilter, + $this->instruments, + $this->instrumentationScopeFactory->create($name, $version, $schemaUrl, $attributes), + $this->registry, + $this->writer, + ); + } + + public function shutdown(): bool + { + if ($this->closed) { + return false; + } + + $this->closed = true; + + $success = true; + foreach ($this->metricReaders as $metricReader) { + if (!$metricReader->shutdown()) { + $success = false; + } + } + + return $success; + } + + public function forceFlush(): bool + { + if ($this->closed) { + return false; + } + + $success = true; + foreach ($this->metricReaders as $metricReader) { + if (!$metricReader->forceFlush()) { + $success = false; + } + } + + return $success; + } + + public static function builder(): MeterProviderBuilder + { + return new MeterProviderBuilder(); + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/MeterProviderBuilder.php b/vendor/open-telemetry/sdk/Metrics/MeterProviderBuilder.php new file mode 100644 index 000000000..17f0be895 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/MeterProviderBuilder.php @@ -0,0 +1,62 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics; + +use OpenTelemetry\SDK\Common\Attribute\Attributes; +use OpenTelemetry\SDK\Common\Instrumentation\InstrumentationScopeFactory; +use OpenTelemetry\SDK\Common\Time\ClockFactory; +use OpenTelemetry\SDK\Metrics\Exemplar\ExemplarFilter\WithSampledTraceExemplarFilter; +use OpenTelemetry\SDK\Metrics\Exemplar\ExemplarFilterInterface; +use OpenTelemetry\SDK\Metrics\StalenessHandler\NoopStalenessHandlerFactory; +use OpenTelemetry\SDK\Metrics\View\CriteriaViewRegistry; +use OpenTelemetry\SDK\Resource\ResourceInfo; +use OpenTelemetry\SDK\Resource\ResourceInfoFactory; + +class MeterProviderBuilder +{ + // @var array<MetricReaderInterface> + private array $metricReaders = []; + private ?ResourceInfo $resource = null; + private ?ExemplarFilterInterface $exemplarFilter = null; + + public function setResource(ResourceInfo $resource): self + { + $this->resource = $resource; + + return $this; + } + + public function setExemplarFilter(ExemplarFilterInterface $exemplarFilter): self + { + $this->exemplarFilter = $exemplarFilter; + + return $this; + } + + public function addReader(MetricReaderInterface $reader): self + { + $this->metricReaders[] = $reader; + + return $this; + } + + /** + * @psalm-suppress PossiblyInvalidArgument + */ + public function build(): MeterProviderInterface + { + return new MeterProvider( + null, + $this->resource ?? ResourceInfoFactory::emptyResource(), + ClockFactory::getDefault(), + Attributes::factory(), + new InstrumentationScopeFactory(Attributes::factory()), + $this->metricReaders, + new CriteriaViewRegistry(), + $this->exemplarFilter ?? new WithSampledTraceExemplarFilter(), + new NoopStalenessHandlerFactory(), + ); + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/MeterProviderFactory.php b/vendor/open-telemetry/sdk/Metrics/MeterProviderFactory.php new file mode 100644 index 000000000..5f7f9988d --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/MeterProviderFactory.php @@ -0,0 +1,78 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics; + +use InvalidArgumentException; +use OpenTelemetry\API\Behavior\LogsMessagesTrait; +use OpenTelemetry\SDK\Common\Configuration\Configuration; +use OpenTelemetry\SDK\Common\Configuration\KnownValues; +use OpenTelemetry\SDK\Common\Configuration\Variables; +use OpenTelemetry\SDK\Metrics\Exemplar\ExemplarFilter\AllExemplarFilter; +use OpenTelemetry\SDK\Metrics\Exemplar\ExemplarFilter\NoneExemplarFilter; +use OpenTelemetry\SDK\Metrics\Exemplar\ExemplarFilter\WithSampledTraceExemplarFilter; +use OpenTelemetry\SDK\Metrics\Exemplar\ExemplarFilterInterface; +use OpenTelemetry\SDK\Metrics\MetricExporter\NoopMetricExporter; +use OpenTelemetry\SDK\Metrics\MetricReader\ExportingReader; +use OpenTelemetry\SDK\Registry; +use OpenTelemetry\SDK\Resource\ResourceInfoFactory; +use OpenTelemetry\SDK\Sdk; + +class MeterProviderFactory +{ + use LogsMessagesTrait; + + /** + * @todo https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/sdk_exporters/otlp.md#general + * - "The exporter MUST configure the default aggregation on the basis of instrument kind using the + * OTEL_EXPORTER_OTLP_METRICS_DEFAULT_HISTOGRAM_AGGREGATION variable as described below if it is implemented." + */ + public function create(): MeterProviderInterface + { + if (Sdk::isDisabled()) { + return new NoopMeterProvider(); + } + $exporters = Configuration::getList(Variables::OTEL_METRICS_EXPORTER); + //TODO "The SDK MAY accept a comma-separated list to enable setting multiple exporters" + if (count($exporters) !== 1) { + throw new InvalidArgumentException(sprintf('Configuration %s requires exactly 1 exporter', Variables::OTEL_METRICS_EXPORTER)); + } + $exporterName = $exporters[0]; + + try { + $factory = Registry::metricExporterFactory($exporterName); + $exporter = $factory->create(); + } catch (\Throwable $t) { + self::logWarning(sprintf('Unable to create %s meter provider: %s', $exporterName, $t->getMessage())); + $exporter = new NoopMetricExporter(); + } + + // @todo "The exporter MUST be paired with a periodic exporting MetricReader" + $reader = new ExportingReader($exporter); + $resource = ResourceInfoFactory::defaultResource(); + $exemplarFilter = $this->createExemplarFilter(Configuration::getEnum(Variables::OTEL_METRICS_EXEMPLAR_FILTER)); + + return MeterProvider::builder() + ->setResource($resource) + ->addReader($reader) + ->setExemplarFilter($exemplarFilter) + ->build(); + } + + private function createExemplarFilter(string $name): ExemplarFilterInterface + { + switch ($name) { + case KnownValues::VALUE_WITH_SAMPLED_TRACE: + return new WithSampledTraceExemplarFilter(); + case KnownValues::VALUE_ALL: + return new AllExemplarFilter(); + case KnownValues::VALUE_NONE: + return new NoneExemplarFilter(); + default: + self::logWarning('Unknown exemplar filter: ' . $name); + + return new NoneExemplarFilter(); + } + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/MeterProviderInterface.php b/vendor/open-telemetry/sdk/Metrics/MeterProviderInterface.php new file mode 100644 index 000000000..fcb951106 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/MeterProviderInterface.php @@ -0,0 +1,12 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics; + +interface MeterProviderInterface extends \OpenTelemetry\API\Metrics\MeterProviderInterface +{ + public function shutdown(): bool; + + public function forceFlush(): bool; +} diff --git a/vendor/open-telemetry/sdk/Metrics/MetricExporter/ConsoleMetricExporter.php b/vendor/open-telemetry/sdk/Metrics/MetricExporter/ConsoleMetricExporter.php new file mode 100644 index 000000000..62ea7b535 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/MetricExporter/ConsoleMetricExporter.php @@ -0,0 +1,105 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\MetricExporter; + +use OpenTelemetry\SDK\Common\Instrumentation\InstrumentationScopeInterface; +use OpenTelemetry\SDK\Metrics\AggregationTemporalitySelectorInterface; +use OpenTelemetry\SDK\Metrics\Data\Metric; +use OpenTelemetry\SDK\Metrics\Data\Temporality; +use OpenTelemetry\SDK\Metrics\MetricMetadataInterface; +use OpenTelemetry\SDK\Metrics\PushMetricExporterInterface; +use OpenTelemetry\SDK\Resource\ResourceInfo; + +/** + * Console metrics exporter. + * Note that the output is human-readable JSON, not compatible with OTLP. + */ +class ConsoleMetricExporter implements PushMetricExporterInterface, AggregationTemporalitySelectorInterface +{ + /** + * @var string|Temporality|null + */ + private $temporality; + + /** + * @param string|Temporality|null $temporality + */ + public function __construct($temporality = null) + { + $this->temporality = $temporality; + } + /** + * @inheritDoc + */ + public function temporality(MetricMetadataInterface $metric) + { + return $this->temporality ?? $metric->temporality(); + } + + /** + * @inheritDoc + */ + public function export(iterable $batch): bool + { + $resource = null; + $scope = null; + foreach ($batch as $metric) { + /** @var Metric $metric */ + if (!$resource) { + $resource = $this->convertResource($metric->resource); + } + if (!$scope) { + $scope = $this->convertInstrumentationScope($metric->instrumentationScope); + $scope['metrics'] = []; + } + $scope['metrics'][] = $this->convertMetric($metric); + } + $output = [ + 'resource' => $resource, + 'scope' => $scope, + ]; + echo json_encode($output, JSON_PRETTY_PRINT) . PHP_EOL; + + return true; + } + + public function shutdown(): bool + { + return true; + } + + public function forceFlush(): bool + { + return true; + } + + private function convertMetric(Metric $metric): array + { + return [ + 'name' => $metric->name, + 'description' => $metric->description, + 'unit' => $metric->unit, + 'data' => $metric->data, + ]; + } + + private function convertResource(ResourceInfo $resource): array + { + return [ + 'attributes' => $resource->getAttributes()->toArray(), + 'dropped_attributes_count' => $resource->getAttributes()->getDroppedAttributesCount(), + ]; + } + private function convertInstrumentationScope(InstrumentationScopeInterface $scope): array + { + return [ + 'name' => $scope->getName(), + 'version' => $scope->getVersion(), + 'attributes' => $scope->getAttributes()->toArray(), + 'dropped_attributes_count' => $scope->getAttributes()->getDroppedAttributesCount(), + 'schema_url' => $scope->getSchemaUrl(), + ]; + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/MetricExporter/ConsoleMetricExporterFactory.php b/vendor/open-telemetry/sdk/Metrics/MetricExporter/ConsoleMetricExporterFactory.php new file mode 100644 index 000000000..19088738d --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/MetricExporter/ConsoleMetricExporterFactory.php @@ -0,0 +1,16 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\MetricExporter; + +use OpenTelemetry\SDK\Metrics\MetricExporterFactoryInterface; +use OpenTelemetry\SDK\Metrics\MetricExporterInterface; + +class ConsoleMetricExporterFactory implements MetricExporterFactoryInterface +{ + public function create(): MetricExporterInterface + { + return new ConsoleMetricExporter(); + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/MetricExporter/InMemoryExporter.php b/vendor/open-telemetry/sdk/Metrics/MetricExporter/InMemoryExporter.php new file mode 100644 index 000000000..6bbab8b79 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/MetricExporter/InMemoryExporter.php @@ -0,0 +1,78 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\MetricExporter; + +use function array_push; +use OpenTelemetry\SDK\Metrics\AggregationTemporalitySelectorInterface; +use OpenTelemetry\SDK\Metrics\Data\Metric; +use OpenTelemetry\SDK\Metrics\Data\Temporality; +use OpenTelemetry\SDK\Metrics\MetricExporterInterface; +use OpenTelemetry\SDK\Metrics\MetricMetadataInterface; + +/** + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/sdk_exporters/in-memory.md + */ +final class InMemoryExporter implements MetricExporterInterface, AggregationTemporalitySelectorInterface +{ + /** + * @var list<Metric> + */ + private array $metrics = []; + /** + * @var string|Temporality|null + */ + private $temporality; + + private bool $closed = false; + + /** + * @param string|Temporality|null $temporality + */ + public function __construct($temporality = null) + { + $this->temporality = $temporality; + } + + public function temporality(MetricMetadataInterface $metric) + { + return $this->temporality ?? $metric->temporality(); + } + + /** + * @return list<Metric> + */ + public function collect(bool $reset = false): array + { + $metrics = $this->metrics; + if ($reset) { + $this->metrics = []; + } + + return $metrics; + } + + public function export(iterable $batch): bool + { + if ($this->closed) { + return false; + } + + /** @psalm-suppress InvalidPropertyAssignmentValue */ + array_push($this->metrics, ...$batch); + + return true; + } + + public function shutdown(): bool + { + if ($this->closed) { + return false; + } + + $this->closed = true; + + return true; + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/MetricExporter/InMemoryExporterFactory.php b/vendor/open-telemetry/sdk/Metrics/MetricExporter/InMemoryExporterFactory.php new file mode 100644 index 000000000..c72c7b169 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/MetricExporter/InMemoryExporterFactory.php @@ -0,0 +1,16 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\MetricExporter; + +use OpenTelemetry\SDK\Metrics\MetricExporterFactoryInterface; +use OpenTelemetry\SDK\Metrics\MetricExporterInterface; + +class InMemoryExporterFactory implements MetricExporterFactoryInterface +{ + public function create(): MetricExporterInterface + { + return new InMemoryExporter(); + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/MetricExporter/NoopMetricExporter.php b/vendor/open-telemetry/sdk/Metrics/MetricExporter/NoopMetricExporter.php new file mode 100644 index 000000000..0cac12fae --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/MetricExporter/NoopMetricExporter.php @@ -0,0 +1,23 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\MetricExporter; + +use OpenTelemetry\SDK\Metrics\MetricExporterInterface; + +class NoopMetricExporter implements MetricExporterInterface +{ + /** + * @inheritDoc + */ + public function export(iterable $batch): bool + { + return true; + } + + public function shutdown(): bool + { + return true; + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/MetricExporter/NoopMetricExporterFactory.php b/vendor/open-telemetry/sdk/Metrics/MetricExporter/NoopMetricExporterFactory.php new file mode 100644 index 000000000..ab2ab2af3 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/MetricExporter/NoopMetricExporterFactory.php @@ -0,0 +1,16 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\MetricExporter; + +use OpenTelemetry\SDK\Metrics\MetricExporterFactoryInterface; +use OpenTelemetry\SDK\Metrics\MetricExporterInterface; + +class NoopMetricExporterFactory implements MetricExporterFactoryInterface +{ + public function create(): MetricExporterInterface + { + return new NoopMetricExporter(); + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/MetricExporter/_register.php b/vendor/open-telemetry/sdk/Metrics/MetricExporter/_register.php new file mode 100644 index 000000000..fba543d02 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/MetricExporter/_register.php @@ -0,0 +1,7 @@ +<?php + +declare(strict_types=1); + +\OpenTelemetry\SDK\Registry::registerMetricExporterFactory('memory', \OpenTelemetry\SDK\Metrics\MetricExporter\InMemoryExporterFactory::class); +\OpenTelemetry\SDK\Registry::registerMetricExporterFactory('console', \OpenTelemetry\SDK\Metrics\MetricExporter\ConsoleMetricExporterFactory::class); +\OpenTelemetry\SDK\Registry::registerMetricExporterFactory('none', \OpenTelemetry\SDK\Metrics\MetricExporter\NoopMetricExporterFactory::class); diff --git a/vendor/open-telemetry/sdk/Metrics/MetricExporterFactoryInterface.php b/vendor/open-telemetry/sdk/Metrics/MetricExporterFactoryInterface.php new file mode 100644 index 000000000..0d2541821 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/MetricExporterFactoryInterface.php @@ -0,0 +1,10 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics; + +interface MetricExporterFactoryInterface +{ + public function create(): MetricExporterInterface; +} diff --git a/vendor/open-telemetry/sdk/Metrics/MetricExporterInterface.php b/vendor/open-telemetry/sdk/Metrics/MetricExporterInterface.php new file mode 100644 index 000000000..fa47fbf9e --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/MetricExporterInterface.php @@ -0,0 +1,17 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics; + +use OpenTelemetry\SDK\Metrics\Data\Metric; + +interface MetricExporterInterface +{ + /** + * @param iterable<int, Metric> $batch + */ + public function export(iterable $batch): bool; + + public function shutdown(): bool; +} diff --git a/vendor/open-telemetry/sdk/Metrics/MetricFactory/StreamFactory.php b/vendor/open-telemetry/sdk/Metrics/MetricFactory/StreamFactory.php new file mode 100644 index 000000000..2c3af4c06 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/MetricFactory/StreamFactory.php @@ -0,0 +1,187 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\MetricFactory; + +use function array_keys; +use OpenTelemetry\SDK\Common\Instrumentation\InstrumentationScopeInterface; +use OpenTelemetry\SDK\Metrics\Aggregation\ExplicitBucketHistogramAggregation; +use OpenTelemetry\SDK\Metrics\AggregationInterface; +use OpenTelemetry\SDK\Metrics\AttributeProcessor\FilteredAttributeProcessor; +use OpenTelemetry\SDK\Metrics\AttributeProcessorInterface; +use OpenTelemetry\SDK\Metrics\Exemplar\ExemplarFilterInterface; +use OpenTelemetry\SDK\Metrics\Exemplar\ExemplarReservoirInterface; +use OpenTelemetry\SDK\Metrics\Exemplar\FilteredReservoir; +use OpenTelemetry\SDK\Metrics\Exemplar\FixedSizeReservoir; +use OpenTelemetry\SDK\Metrics\Exemplar\HistogramBucketReservoir; +use OpenTelemetry\SDK\Metrics\Instrument; +use OpenTelemetry\SDK\Metrics\MetricFactoryInterface; +use OpenTelemetry\SDK\Metrics\MetricRegistrationInterface; +use OpenTelemetry\SDK\Metrics\MetricRegistry\MetricCollectorInterface; +use OpenTelemetry\SDK\Metrics\MetricRegistry\MetricRegistryInterface; +use OpenTelemetry\SDK\Metrics\Stream\AsynchronousMetricStream; +use OpenTelemetry\SDK\Metrics\Stream\MetricAggregator; +use OpenTelemetry\SDK\Metrics\Stream\MetricAggregatorFactory; +use OpenTelemetry\SDK\Metrics\Stream\MetricStreamInterface; +use OpenTelemetry\SDK\Metrics\Stream\SynchronousMetricStream; +use OpenTelemetry\SDK\Metrics\ViewProjection; +use OpenTelemetry\SDK\Resource\ResourceInfo; +use function serialize; +use function spl_object_id; +use Throwable; + +/** + * @internal + */ +final class StreamFactory implements MetricFactoryInterface +{ + public function createAsynchronousObserver( + MetricRegistryInterface $registry, + ResourceInfo $resource, + InstrumentationScopeInterface $instrumentationScope, + Instrument $instrument, + int $timestamp, + iterable $views + ): array { + $streams = []; + $dedup = []; + foreach ($views as [$view, $registration]) { + if ($view->aggregation === null) { + continue; + } + + $dedupId = $this->streamId($view->aggregation, $view->attributeKeys); + if (($streamId = $dedup[$dedupId] ?? null) === null) { + $stream = new AsynchronousMetricStream($view->aggregation, $timestamp); + $streamId = $registry->registerAsynchronousStream($instrument, $stream, new MetricAggregatorFactory( + $this->attributeProcessor($view->attributeKeys), + $view->aggregation, + )); + + $streams[$streamId] = $stream; + $dedup[$dedupId] = $streamId; + } + + $this->registerSource( + $view, + $instrument, + $instrumentationScope, + $resource, + $streams[$streamId], + $registry, + $registration, + $streamId, + ); + } + + return array_keys($streams); + } + + public function createSynchronousWriter( + MetricRegistryInterface $registry, + ResourceInfo $resource, + InstrumentationScopeInterface $instrumentationScope, + Instrument $instrument, + int $timestamp, + iterable $views, + ?ExemplarFilterInterface $exemplarFilter = null + ): array { + $streams = []; + $dedup = []; + foreach ($views as [$view, $registration]) { + if ($view->aggregation === null) { + continue; + } + + $dedupId = $this->streamId($view->aggregation, $view->attributeKeys); + if (($streamId = $dedup[$dedupId] ?? null) === null) { + $stream = new SynchronousMetricStream($view->aggregation, $timestamp); + $streamId = $registry->registerSynchronousStream($instrument, $stream, new MetricAggregator( + $this->attributeProcessor($view->attributeKeys), + $view->aggregation, + $this->createExemplarReservoir($view->aggregation, $exemplarFilter), + )); + + $streams[$streamId] = $stream; + $dedup[$dedupId] = $streamId; + } + + $this->registerSource( + $view, + $instrument, + $instrumentationScope, + $resource, + $streams[$streamId], + $registry, + $registration, + $streamId, + ); + } + + return array_keys($streams); + } + + private function attributeProcessor( + ?array $attributeKeys + ): ?AttributeProcessorInterface { + return $attributeKeys !== null + ? new FilteredAttributeProcessor($attributeKeys) + : null; + } + + private function createExemplarReservoir( + AggregationInterface $aggregation, + ?ExemplarFilterInterface $exemplarFilter + ): ?ExemplarReservoirInterface { + if (!$exemplarFilter) { + return null; + } + + if ($aggregation instanceof ExplicitBucketHistogramAggregation && $aggregation->boundaries) { + $exemplarReservoir = new HistogramBucketReservoir($aggregation->boundaries); + } else { + $exemplarReservoir = new FixedSizeReservoir(); + } + + return new FilteredReservoir($exemplarReservoir, $exemplarFilter); + } + + private function registerSource( + ViewProjection $view, + Instrument $instrument, + InstrumentationScopeInterface $instrumentationScope, + ResourceInfo $resource, + MetricStreamInterface $stream, + MetricCollectorInterface $metricCollector, + MetricRegistrationInterface $metricRegistration, + int $streamId + ): void { + $provider = new StreamMetricSourceProvider( + $view, + $instrument, + $instrumentationScope, + $resource, + $stream, + $metricCollector, + $streamId, + ); + + $metricRegistration->register($provider, $provider); + } + + private function streamId(AggregationInterface $aggregation, ?array $attributeKeys): string + { + return $this->trySerialize($aggregation) . serialize($attributeKeys); + } + + private function trySerialize(object $object) + { + try { + return serialize($object); + } catch (Throwable $e) { + } + + return spl_object_id($object); + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/MetricFactory/StreamMetricSource.php b/vendor/open-telemetry/sdk/Metrics/MetricFactory/StreamMetricSource.php new file mode 100644 index 000000000..4939a5341 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/MetricFactory/StreamMetricSource.php @@ -0,0 +1,44 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\MetricFactory; + +use OpenTelemetry\SDK\Metrics\Data\Metric; +use OpenTelemetry\SDK\Metrics\MetricSourceInterface; + +/** + * @internal + */ +final class StreamMetricSource implements MetricSourceInterface +{ + private StreamMetricSourceProvider $provider; + private int $reader; + public function __construct(StreamMetricSourceProvider $provider, int $reader) + { + $this->provider = $provider; + $this->reader = $reader; + } + + public function collectionTimestamp(): int + { + return $this->provider->stream->timestamp(); + } + + public function collect(): Metric + { + return new Metric( + $this->provider->instrumentationLibrary, + $this->provider->resource, + $this->provider->view->name, + $this->provider->view->unit, + $this->provider->view->description, + $this->provider->stream->collect($this->reader), + ); + } + + public function __destruct() + { + $this->provider->stream->unregister($this->reader); + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/MetricFactory/StreamMetricSourceProvider.php b/vendor/open-telemetry/sdk/Metrics/MetricFactory/StreamMetricSourceProvider.php new file mode 100644 index 000000000..657c3ce62 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/MetricFactory/StreamMetricSourceProvider.php @@ -0,0 +1,98 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\MetricFactory; + +use OpenTelemetry\SDK\Common\Instrumentation\InstrumentationScopeInterface; +use OpenTelemetry\SDK\Metrics\Instrument; +use OpenTelemetry\SDK\Metrics\MetricMetadataInterface; +use OpenTelemetry\SDK\Metrics\MetricRegistry\MetricCollectorInterface; +use OpenTelemetry\SDK\Metrics\MetricSourceInterface; +use OpenTelemetry\SDK\Metrics\MetricSourceProviderInterface; +use OpenTelemetry\SDK\Metrics\Stream\MetricStreamInterface; +use OpenTelemetry\SDK\Metrics\ViewProjection; +use OpenTelemetry\SDK\Resource\ResourceInfo; + +/** + * @internal + */ +final class StreamMetricSourceProvider implements MetricSourceProviderInterface, MetricMetadataInterface +{ + /** + * @readonly + */ + public ViewProjection $view; + /** + * @readonly + */ + public Instrument $instrument; + /** + * @readonly + */ + public InstrumentationScopeInterface $instrumentationLibrary; + /** + * @readonly + */ + public ResourceInfo $resource; + /** + * @readonly + */ + public MetricStreamInterface $stream; + /** + * @readonly + */ + public MetricCollectorInterface $metricCollector; + /** + * @readonly + */ + public int $streamId; + + public function __construct( + ViewProjection $view, + Instrument $instrument, + InstrumentationScopeInterface $instrumentationLibrary, + ResourceInfo $resource, + MetricStreamInterface $stream, + MetricCollectorInterface $metricCollector, + int $streamId + ) { + $this->view = $view; + $this->instrument = $instrument; + $this->instrumentationLibrary = $instrumentationLibrary; + $this->resource = $resource; + $this->stream = $stream; + $this->metricCollector = $metricCollector; + $this->streamId = $streamId; + } + + public function create($temporality): MetricSourceInterface + { + return new StreamMetricSource($this, $this->stream->register($temporality)); + } + + public function instrumentType() + { + return $this->instrument->type; + } + + public function name(): string + { + return $this->view->name; + } + + public function unit(): ?string + { + return $this->view->unit; + } + + public function description(): ?string + { + return $this->view->description; + } + + public function temporality() + { + return $this->stream->temporality(); + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/MetricFactoryInterface.php b/vendor/open-telemetry/sdk/Metrics/MetricFactoryInterface.php new file mode 100644 index 000000000..a1e228eef --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/MetricFactoryInterface.php @@ -0,0 +1,41 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics; + +use OpenTelemetry\SDK\Common\Instrumentation\InstrumentationScopeInterface; +use OpenTelemetry\SDK\Metrics\Exemplar\ExemplarFilterInterface; +use OpenTelemetry\SDK\Metrics\MetricRegistry\MetricRegistryInterface; +use OpenTelemetry\SDK\Resource\ResourceInfo; + +/** + * @internal + */ +interface MetricFactoryInterface +{ + /** + * @param iterable<array{ViewProjection, MetricRegistrationInterface}> $views + */ + public function createAsynchronousObserver( + MetricRegistryInterface $registry, + ResourceInfo $resource, + InstrumentationScopeInterface $instrumentationScope, + Instrument $instrument, + int $timestamp, + iterable $views + ): array; + + /** + * @param iterable<array{ViewProjection, MetricRegistrationInterface}> $views + */ + public function createSynchronousWriter( + MetricRegistryInterface $registry, + ResourceInfo $resource, + InstrumentationScopeInterface $instrumentationScope, + Instrument $instrument, + int $timestamp, + iterable $views, + ?ExemplarFilterInterface $exemplarFilter = null + ): array; +} diff --git a/vendor/open-telemetry/sdk/Metrics/MetricMetadataInterface.php b/vendor/open-telemetry/sdk/Metrics/MetricMetadataInterface.php new file mode 100644 index 000000000..aa1a02d60 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/MetricMetadataInterface.php @@ -0,0 +1,28 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics; + +use OpenTelemetry\SDK\Metrics\Data\Temporality; + +interface MetricMetadataInterface +{ + /** + * @return string|InstrumentType + */ + public function instrumentType(); + + public function name(): string; + + public function unit(): ?string; + + public function description(): ?string; + + /** + * Returns the underlying temporality of this metric. + * + * @return string|Temporality internal temporality + */ + public function temporality(); +} diff --git a/vendor/open-telemetry/sdk/Metrics/MetricReader/ExportingReader.php b/vendor/open-telemetry/sdk/Metrics/MetricReader/ExportingReader.php new file mode 100644 index 000000000..3c2eff9f1 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/MetricReader/ExportingReader.php @@ -0,0 +1,156 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\MetricReader; + +use function array_keys; +use OpenTelemetry\SDK\Metrics\AggregationInterface; +use OpenTelemetry\SDK\Metrics\AggregationTemporalitySelectorInterface; +use OpenTelemetry\SDK\Metrics\DefaultAggregationProviderInterface; +use OpenTelemetry\SDK\Metrics\DefaultAggregationProviderTrait; +use OpenTelemetry\SDK\Metrics\MetricExporterInterface; +use OpenTelemetry\SDK\Metrics\MetricFactory\StreamMetricSourceProvider; +use OpenTelemetry\SDK\Metrics\MetricMetadataInterface; +use OpenTelemetry\SDK\Metrics\MetricReaderInterface; +use OpenTelemetry\SDK\Metrics\MetricRegistry\MetricCollectorInterface; +use OpenTelemetry\SDK\Metrics\MetricSourceInterface; +use OpenTelemetry\SDK\Metrics\MetricSourceProviderInterface; +use OpenTelemetry\SDK\Metrics\MetricSourceRegistryInterface; +use OpenTelemetry\SDK\Metrics\PushMetricExporterInterface; +use OpenTelemetry\SDK\Metrics\StalenessHandlerInterface; +use function spl_object_id; + +final class ExportingReader implements MetricReaderInterface, MetricSourceRegistryInterface, DefaultAggregationProviderInterface +{ + use DefaultAggregationProviderTrait { defaultAggregation as private _defaultAggregation; } + + private MetricExporterInterface $exporter; + /** @var array<int, MetricSourceInterface> */ + private array $sources = []; + + /** @var array<int, MetricCollectorInterface> */ + private array $registries = []; + /** @var array<int, array<int, int>> */ + private array $streamIds = []; + + private bool $closed = false; + + public function __construct(MetricExporterInterface $exporter) + { + $this->exporter = $exporter; + } + + public function defaultAggregation($instrumentType): ?AggregationInterface + { + if ($this->exporter instanceof DefaultAggregationProviderInterface) { + return $this->exporter->defaultAggregation($instrumentType); + } + + return $this->_defaultAggregation($instrumentType); + } + + public function add(MetricSourceProviderInterface $provider, MetricMetadataInterface $metadata, StalenessHandlerInterface $stalenessHandler): void + { + if ($this->closed) { + return; + } + if (!$this->exporter instanceof AggregationTemporalitySelectorInterface) { + return; + } + if (!$temporality = $this->exporter->temporality($metadata)) { + return; + } + + $source = $provider->create($temporality); + $sourceId = spl_object_id($source); + + $this->sources[$sourceId] = $source; + $stalenessHandler->onStale(function () use ($sourceId): void { + unset($this->sources[$sourceId]); + }); + + if (!$provider instanceof StreamMetricSourceProvider) { + return; + } + + $streamId = $provider->streamId; + $registry = $provider->metricCollector; + $registryId = spl_object_id($registry); + + $this->registries[$registryId] = $registry; + $this->streamIds[$registryId][$streamId] ??= 0; + $this->streamIds[$registryId][$streamId]++; + + $stalenessHandler->onStale(function () use ($streamId, $registryId): void { + if (!--$this->streamIds[$registryId][$streamId]) { + unset($this->streamIds[$registryId][$streamId]); + if (!$this->streamIds[$registryId]) { + unset( + $this->registries[$registryId], + $this->streamIds[$registryId], + ); + } + } + }); + } + + private function doCollect(): bool + { + foreach ($this->registries as $registryId => $registry) { + $streamIds = $this->streamIds[$registryId] ?? []; + $registry->collectAndPush(array_keys($streamIds)); + } + + $metrics = []; + foreach ($this->sources as $source) { + $metrics[] = $source->collect(); + } + + if ($metrics === []) { + return true; + } + + return $this->exporter->export($metrics); + } + + public function collect(): bool + { + if ($this->closed) { + return false; + } + + return $this->doCollect(); + } + + public function shutdown(): bool + { + if ($this->closed) { + return false; + } + + $this->closed = true; + + $collect = $this->doCollect(); + $shutdown = $this->exporter->shutdown(); + + $this->sources = []; + + return $collect && $shutdown; + } + + public function forceFlush(): bool + { + if ($this->closed) { + return false; + } + if ($this->exporter instanceof PushMetricExporterInterface) { + $collect = $this->doCollect(); + $forceFlush = $this->exporter->forceFlush(); + + return $collect && $forceFlush; + } + + return true; + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/MetricReaderInterface.php b/vendor/open-telemetry/sdk/Metrics/MetricReaderInterface.php new file mode 100644 index 000000000..f5900eef5 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/MetricReaderInterface.php @@ -0,0 +1,14 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics; + +interface MetricReaderInterface +{ + public function collect(): bool; + + public function shutdown(): bool; + + public function forceFlush(): bool; +} diff --git a/vendor/open-telemetry/sdk/Metrics/MetricRegistration/MultiRegistryRegistration.php b/vendor/open-telemetry/sdk/Metrics/MetricRegistration/MultiRegistryRegistration.php new file mode 100644 index 000000000..2472c096f --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/MetricRegistration/MultiRegistryRegistration.php @@ -0,0 +1,36 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\MetricRegistration; + +use OpenTelemetry\SDK\Metrics\MetricMetadataInterface; +use OpenTelemetry\SDK\Metrics\MetricRegistrationInterface; +use OpenTelemetry\SDK\Metrics\MetricSourceProviderInterface; +use OpenTelemetry\SDK\Metrics\MetricSourceRegistryInterface; +use OpenTelemetry\SDK\Metrics\StalenessHandlerInterface; + +/** + * @internal + */ +final class MultiRegistryRegistration implements MetricRegistrationInterface +{ + private iterable $registries; + private StalenessHandlerInterface $stalenessHandler; + + /** + * @param iterable<MetricSourceRegistryInterface> $registries + */ + public function __construct(iterable $registries, StalenessHandlerInterface $stalenessHandler) + { + $this->registries = $registries; + $this->stalenessHandler = $stalenessHandler; + } + + public function register(MetricSourceProviderInterface $provider, MetricMetadataInterface $metadata): void + { + foreach ($this->registries as $registry) { + $registry->add($provider, $metadata, $this->stalenessHandler); + } + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/MetricRegistration/RegistryRegistration.php b/vendor/open-telemetry/sdk/Metrics/MetricRegistration/RegistryRegistration.php new file mode 100644 index 000000000..3c1108902 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/MetricRegistration/RegistryRegistration.php @@ -0,0 +1,31 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\MetricRegistration; + +use OpenTelemetry\SDK\Metrics\MetricMetadataInterface; +use OpenTelemetry\SDK\Metrics\MetricRegistrationInterface; +use OpenTelemetry\SDK\Metrics\MetricSourceProviderInterface; +use OpenTelemetry\SDK\Metrics\MetricSourceRegistryInterface; +use OpenTelemetry\SDK\Metrics\StalenessHandlerInterface; + +/** + * @internal + */ +final class RegistryRegistration implements MetricRegistrationInterface +{ + private MetricSourceRegistryInterface $registry; + private StalenessHandlerInterface $stalenessHandler; + + public function __construct(MetricSourceRegistryInterface $registry, StalenessHandlerInterface $stalenessHandler) + { + $this->registry = $registry; + $this->stalenessHandler = $stalenessHandler; + } + + public function register(MetricSourceProviderInterface $provider, MetricMetadataInterface $metadata): void + { + $this->registry->add($provider, $metadata, $this->stalenessHandler); + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/MetricRegistrationInterface.php b/vendor/open-telemetry/sdk/Metrics/MetricRegistrationInterface.php new file mode 100644 index 000000000..b0cc2484e --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/MetricRegistrationInterface.php @@ -0,0 +1,13 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics; + +/** + * @internal + */ +interface MetricRegistrationInterface +{ + public function register(MetricSourceProviderInterface $provider, MetricMetadataInterface $metadata): void; +} diff --git a/vendor/open-telemetry/sdk/Metrics/MetricRegistry/MetricCollectorInterface.php b/vendor/open-telemetry/sdk/Metrics/MetricRegistry/MetricCollectorInterface.php new file mode 100644 index 000000000..4e8e91ced --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/MetricRegistry/MetricCollectorInterface.php @@ -0,0 +1,13 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\MetricRegistry; + +/** + * @internal + */ +interface MetricCollectorInterface +{ + public function collectAndPush(iterable $streamIds): void; +} diff --git a/vendor/open-telemetry/sdk/Metrics/MetricRegistry/MetricRegistry.php b/vendor/open-telemetry/sdk/Metrics/MetricRegistry/MetricRegistry.php new file mode 100644 index 000000000..9a18d2a84 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/MetricRegistry/MetricRegistry.php @@ -0,0 +1,184 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\MetricRegistry; + +use function array_key_last; +use Closure; +use OpenTelemetry\Context\Context; +use OpenTelemetry\Context\ContextStorageInterface; +use OpenTelemetry\SDK\Common\Attribute\AttributesFactoryInterface; +use OpenTelemetry\SDK\Common\Time\ClockInterface; +use OpenTelemetry\SDK\Metrics\Instrument; +use OpenTelemetry\SDK\Metrics\Stream\MetricAggregatorFactoryInterface; +use OpenTelemetry\SDK\Metrics\Stream\MetricAggregatorInterface; +use OpenTelemetry\SDK\Metrics\Stream\MetricStreamInterface; +use function spl_object_id; + +/** + * @internal + */ +final class MetricRegistry implements MetricRegistryInterface, MetricWriterInterface +{ + private ?ContextStorageInterface $contextStorage; + private AttributesFactoryInterface $attributesFactory; + private ClockInterface $clock; + + /** @var array<int, MetricStreamInterface> */ + private array $streams = []; + /** @var array<int, MetricAggregatorInterface> */ + private array $synchronousAggregators = []; + /** @var array<int, MetricAggregatorFactoryInterface> */ + private array $asynchronousAggregatorFactories = []; + + /** @var array<int, array<int, int>> */ + private array $instrumentToStreams = []; + /** @var array<int, int> */ + private array $streamToInstrument = []; + /** @var array<int, array<int, int>> */ + private array $instrumentToCallbacks = []; + /** @var array<int, Closure> */ + private array $asynchronousCallbacks = []; + /** @var array<int, list<int>> */ + private array $asynchronousCallbackArguments = []; + + public function __construct( + ?ContextStorageInterface $contextStorage, + AttributesFactoryInterface $attributesFactory, + ClockInterface $clock + ) { + $this->contextStorage = $contextStorage; + $this->attributesFactory = $attributesFactory; + $this->clock = $clock; + } + + public function registerSynchronousStream(Instrument $instrument, MetricStreamInterface $stream, MetricAggregatorInterface $aggregator): int + { + $this->streams[] = $stream; + $streamId = array_key_last($this->streams); + $instrumentId = spl_object_id($instrument); + + $this->synchronousAggregators[$streamId] = $aggregator; + $this->instrumentToStreams[$instrumentId][$streamId] = $streamId; + $this->streamToInstrument[$streamId] = $instrumentId; + + return $streamId; + } + + public function registerAsynchronousStream(Instrument $instrument, MetricStreamInterface $stream, MetricAggregatorFactoryInterface $aggregatorFactory): int + { + $this->streams[] = $stream; + $streamId = array_key_last($this->streams); + $instrumentId = spl_object_id($instrument); + + $this->asynchronousAggregatorFactories[$streamId] = $aggregatorFactory; + $this->instrumentToStreams[$instrumentId][$streamId] = $streamId; + $this->streamToInstrument[$streamId] = $instrumentId; + + return $streamId; + } + + public function unregisterStream(int $streamId): void + { + $instrumentId = $this->streamToInstrument[$streamId]; + unset( + $this->streams[$streamId], + $this->synchronousAggregators[$streamId], + $this->asynchronousAggregatorFactories[$streamId], + $this->instrumentToStreams[$instrumentId][$streamId], + $this->streamToInstrument[$streamId], + ); + if (!$this->instrumentToStreams[$instrumentId]) { + unset($this->instrumentToStreams[$instrumentId]); + } + } + + public function record(Instrument $instrument, $value, iterable $attributes = [], $context = null): void + { + $context = Context::resolve($context, $this->contextStorage); + $attributes = $this->attributesFactory->builder($attributes)->build(); + $timestamp = $this->clock->now(); + $instrumentId = spl_object_id($instrument); + foreach ($this->instrumentToStreams[$instrumentId] ?? [] as $streamId) { + if ($aggregator = $this->synchronousAggregators[$streamId] ?? null) { + $aggregator->record($value, $attributes, $context, $timestamp); + } + } + } + + public function registerCallback(Closure $callback, Instrument $instrument, Instrument ...$instruments): int + { + $callbackId = array_key_last($this->asynchronousCallbacks) + 1; + $this->asynchronousCallbacks[$callbackId] = $callback; + + $instrumentId = spl_object_id($instrument); + $this->asynchronousCallbackArguments[$callbackId] = [$instrumentId]; + $this->instrumentToCallbacks[$instrumentId][$callbackId] = $callbackId; + foreach ($instruments as $instrument) { + $instrumentId = spl_object_id($instrument); + $this->asynchronousCallbackArguments[$callbackId][] = $instrumentId; + $this->instrumentToCallbacks[$instrumentId][$callbackId] = $callbackId; + } + + return $callbackId; + } + + public function unregisterCallback(int $callbackId): void + { + $instrumentIds = $this->asynchronousCallbackArguments[$callbackId]; + unset( + $this->asynchronousCallbacks[$callbackId], + $this->asynchronousCallbackArguments[$callbackId], + ); + foreach ($instrumentIds as $instrumentId) { + unset($this->instrumentToCallbacks[$instrumentId][$callbackId]); + if (!$this->instrumentToCallbacks[$instrumentId]) { + unset($this->instrumentToCallbacks[$instrumentId]); + } + } + } + + public function collectAndPush(iterable $streamIds): void + { + $timestamp = $this->clock->now(); + $aggregators = []; + $observers = []; + $callbackIds = []; + foreach ($streamIds as $streamId) { + if (!$aggregator = $this->synchronousAggregators[$streamId] ?? null) { + $aggregator = $this->asynchronousAggregatorFactories[$streamId]->create(); + + $instrumentId = $this->streamToInstrument[$streamId]; + $observers[$instrumentId] ??= new MultiObserver($this->attributesFactory, $timestamp); + $observers[$instrumentId]->writers[] = $aggregator; + foreach ($this->instrumentToCallbacks[$instrumentId] ?? [] as $callbackId) { + $callbackIds[$callbackId] = $callbackId; + } + } + + $aggregators[$streamId] = $aggregator; + } + + $noopObserver = new NoopObserver(); + $callbacks = []; + foreach ($callbackIds as $callbackId) { + $args = []; + foreach ($this->asynchronousCallbackArguments[$callbackId] as $instrumentId) { + $args[] = $observers[$instrumentId] ?? $noopObserver; + } + $callback = $this->asynchronousCallbacks[$callbackId]; + $callbacks[] = static fn () => $callback(...$args); + } + foreach ($callbacks as $callback) { + $callback(); + } + + $timestamp = $this->clock->now(); + foreach ($aggregators as $streamId => $aggregator) { + if ($stream = $this->streams[$streamId] ?? null) { + $stream->push($aggregator->collect($timestamp)); + } + } + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/MetricRegistry/MetricRegistryInterface.php b/vendor/open-telemetry/sdk/Metrics/MetricRegistry/MetricRegistryInterface.php new file mode 100644 index 000000000..e86731138 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/MetricRegistry/MetricRegistryInterface.php @@ -0,0 +1,22 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\MetricRegistry; + +use OpenTelemetry\SDK\Metrics\Instrument; +use OpenTelemetry\SDK\Metrics\Stream\MetricAggregatorFactoryInterface; +use OpenTelemetry\SDK\Metrics\Stream\MetricAggregatorInterface; +use OpenTelemetry\SDK\Metrics\Stream\MetricStreamInterface; + +/** + * @internal + */ +interface MetricRegistryInterface extends MetricCollectorInterface +{ + public function registerSynchronousStream(Instrument $instrument, MetricStreamInterface $stream, MetricAggregatorInterface $aggregator): int; + + public function registerAsynchronousStream(Instrument $instrument, MetricStreamInterface $stream, MetricAggregatorFactoryInterface $aggregatorFactory): int; + + public function unregisterStream(int $streamId): void; +} diff --git a/vendor/open-telemetry/sdk/Metrics/MetricRegistry/MetricWriterInterface.php b/vendor/open-telemetry/sdk/Metrics/MetricRegistry/MetricWriterInterface.php new file mode 100644 index 000000000..e5ff7eb5c --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/MetricRegistry/MetricWriterInterface.php @@ -0,0 +1,20 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\MetricRegistry; + +use Closure; +use OpenTelemetry\SDK\Metrics\Instrument; + +/** + * @internal + */ +interface MetricWriterInterface +{ + public function record(Instrument $instrument, $value, iterable $attributes = [], $context = null): void; + + public function registerCallback(Closure $callback, Instrument $instrument, Instrument ...$instruments): int; + + public function unregisterCallback(int $callbackId): void; +} diff --git a/vendor/open-telemetry/sdk/Metrics/MetricRegistry/MultiObserver.php b/vendor/open-telemetry/sdk/Metrics/MetricRegistry/MultiObserver.php new file mode 100644 index 000000000..f36f74a2a --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/MetricRegistry/MultiObserver.php @@ -0,0 +1,37 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\MetricRegistry; + +use OpenTelemetry\API\Metrics\ObserverInterface; +use OpenTelemetry\Context\Context; +use OpenTelemetry\SDK\Common\Attribute\AttributesFactoryInterface; +use OpenTelemetry\SDK\Metrics\Stream\WritableMetricStreamInterface; + +/** + * @internal + */ +final class MultiObserver implements ObserverInterface +{ + private AttributesFactoryInterface $attributesFactory; + private int $timestamp; + + /** @var list<WritableMetricStreamInterface> */ + public array $writers = []; + + public function __construct(AttributesFactoryInterface $attributesFactory, int $timestamp) + { + $this->attributesFactory = $attributesFactory; + $this->timestamp = $timestamp; + } + + public function observe($amount, iterable $attributes = []): void + { + $context = Context::getRoot(); + $attributes = $this->attributesFactory->builder($attributes)->build(); + foreach ($this->writers as $writer) { + $writer->record($amount, $attributes, $context, $this->timestamp); + } + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/MetricRegistry/NoopObserver.php b/vendor/open-telemetry/sdk/Metrics/MetricRegistry/NoopObserver.php new file mode 100644 index 000000000..efbd94dac --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/MetricRegistry/NoopObserver.php @@ -0,0 +1,18 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\MetricRegistry; + +use OpenTelemetry\API\Metrics\ObserverInterface; + +/** + * @internal + */ +final class NoopObserver implements ObserverInterface +{ + public function observe($amount, iterable $attributes = []): void + { + // no-op + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/MetricSourceInterface.php b/vendor/open-telemetry/sdk/Metrics/MetricSourceInterface.php new file mode 100644 index 000000000..5f00a0717 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/MetricSourceInterface.php @@ -0,0 +1,24 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics; + +use OpenTelemetry\SDK\Metrics\Data\Metric; + +interface MetricSourceInterface +{ + /** + * Returns the last metric collection timestamp. + * + * @return int last collection timestamp + */ + public function collectionTimestamp(): int; + + /** + * Collects metric data from the underlying provider. + * + * @return Metric collected metric + */ + public function collect(): Metric; +} diff --git a/vendor/open-telemetry/sdk/Metrics/MetricSourceProviderInterface.php b/vendor/open-telemetry/sdk/Metrics/MetricSourceProviderInterface.php new file mode 100644 index 000000000..f8b6ea438 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/MetricSourceProviderInterface.php @@ -0,0 +1,15 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics; + +use OpenTelemetry\SDK\Metrics\Data\Temporality; + +interface MetricSourceProviderInterface +{ + /** + * @param string|Temporality $temporality + */ + public function create($temporality): MetricSourceInterface; +} diff --git a/vendor/open-telemetry/sdk/Metrics/MetricSourceRegistryInterface.php b/vendor/open-telemetry/sdk/Metrics/MetricSourceRegistryInterface.php new file mode 100644 index 000000000..dd7ff53ac --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/MetricSourceRegistryInterface.php @@ -0,0 +1,10 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics; + +interface MetricSourceRegistryInterface +{ + public function add(MetricSourceProviderInterface $provider, MetricMetadataInterface $metadata, StalenessHandlerInterface $stalenessHandler): void; +} diff --git a/vendor/open-telemetry/sdk/Metrics/NoopMeterProvider.php b/vendor/open-telemetry/sdk/Metrics/NoopMeterProvider.php new file mode 100644 index 000000000..2efb484d3 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/NoopMeterProvider.php @@ -0,0 +1,26 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics; + +use OpenTelemetry\API\Metrics\MeterInterface; +use OpenTelemetry\API\Metrics\Noop\NoopMeter; + +class NoopMeterProvider implements MeterProviderInterface +{ + public function shutdown(): bool + { + return true; + } + + public function forceFlush(): bool + { + return true; + } + + public function getMeter(string $name, ?string $version = null, ?string $schemaUrl = null, iterable $attributes = []): MeterInterface + { + return new NoopMeter(); + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/ObservableCallback.php b/vendor/open-telemetry/sdk/Metrics/ObservableCallback.php new file mode 100644 index 000000000..ffe5ead87 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/ObservableCallback.php @@ -0,0 +1,58 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics; + +use OpenTelemetry\API\Metrics\ObservableCallbackInterface; +use OpenTelemetry\SDK\Metrics\MetricRegistry\MetricWriterInterface; + +/** + * @internal + */ +final class ObservableCallback implements ObservableCallbackInterface +{ + private MetricWriterInterface $writer; + private ReferenceCounterInterface $referenceCounter; + private ?int $callbackId; + private ?ObservableCallbackDestructor $callbackDestructor; + /** @phpstan-ignore-next-line */ + private ?object $target; + + public function __construct(MetricWriterInterface $writer, ReferenceCounterInterface $referenceCounter, int $callbackId, ?ObservableCallbackDestructor $callbackDestructor, ?object $target) + { + $this->writer = $writer; + $this->referenceCounter = $referenceCounter; + $this->callbackId = $callbackId; + $this->callbackDestructor = $callbackDestructor; + $this->target = $target; + } + + public function detach(): void + { + if ($this->callbackId === null) { + return; + } + + $this->writer->unregisterCallback($this->callbackId); + $this->referenceCounter->release(); + if ($this->callbackDestructor !== null) { + unset($this->callbackDestructor->callbackIds[$this->callbackId]); + } + + $this->callbackId = null; + } + + public function __destruct() + { + if ($this->callbackDestructor !== null) { + return; + } + if ($this->callbackId === null) { + return; + } + + $this->referenceCounter->acquire(true); + $this->referenceCounter->release(); + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/ObservableCallbackDestructor.php b/vendor/open-telemetry/sdk/Metrics/ObservableCallbackDestructor.php new file mode 100644 index 000000000..0dfea3907 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/ObservableCallbackDestructor.php @@ -0,0 +1,32 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics; + +use OpenTelemetry\SDK\Metrics\MetricRegistry\MetricWriterInterface; + +/** + * @internal + */ +final class ObservableCallbackDestructor +{ + /** @var array<int, int> */ + public array $callbackIds = []; + private MetricWriterInterface $writer; + private ReferenceCounterInterface $referenceCounter; + + public function __construct(MetricWriterInterface $writer, ReferenceCounterInterface $referenceCounter) + { + $this->writer = $writer; + $this->referenceCounter = $referenceCounter; + } + + public function __destruct() + { + foreach ($this->callbackIds as $callbackId) { + $this->writer->unregisterCallback($callbackId); + $this->referenceCounter->release(); + } + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/ObservableCounter.php b/vendor/open-telemetry/sdk/Metrics/ObservableCounter.php new file mode 100644 index 000000000..99ae43eee --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/ObservableCounter.php @@ -0,0 +1,15 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics; + +use OpenTelemetry\API\Metrics\ObservableCounterInterface; + +/** + * @internal + */ +final class ObservableCounter implements ObservableCounterInterface +{ + use ObservableInstrumentTrait; +} diff --git a/vendor/open-telemetry/sdk/Metrics/ObservableGauge.php b/vendor/open-telemetry/sdk/Metrics/ObservableGauge.php new file mode 100644 index 000000000..88c1a546c --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/ObservableGauge.php @@ -0,0 +1,15 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics; + +use OpenTelemetry\API\Metrics\ObservableGaugeInterface; + +/** + * @internal + */ +final class ObservableGauge implements ObservableGaugeInterface +{ + use ObservableInstrumentTrait; +} diff --git a/vendor/open-telemetry/sdk/Metrics/ObservableInstrumentTrait.php b/vendor/open-telemetry/sdk/Metrics/ObservableInstrumentTrait.php new file mode 100644 index 000000000..b7fdcf5f8 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/ObservableInstrumentTrait.php @@ -0,0 +1,61 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics; + +use ArrayAccess; +use OpenTelemetry\API\Metrics\ObservableCallbackInterface; +use OpenTelemetry\API\Metrics\ObserverInterface; +use function OpenTelemetry\SDK\Common\Util\closure; +use function OpenTelemetry\SDK\Common\Util\weaken; +use OpenTelemetry\SDK\Metrics\MetricRegistry\MetricWriterInterface; + +/** + * @internal + */ +trait ObservableInstrumentTrait +{ + private MetricWriterInterface $writer; + private Instrument $instrument; + private ReferenceCounterInterface $referenceCounter; + private ArrayAccess $destructors; + + public function __construct( + MetricWriterInterface $writer, + Instrument $instrument, + ReferenceCounterInterface $referenceCounter, + ArrayAccess $destructors + ) { + $this->writer = $writer; + $this->instrument = $instrument; + $this->referenceCounter = $referenceCounter; + $this->destructors = $destructors; + + $this->referenceCounter->acquire(); + } + + public function __destruct() + { + $this->referenceCounter->release(); + } + + /** + * @param callable(ObserverInterface): void $callback + */ + public function observe(callable $callback): ObservableCallbackInterface + { + $callback = weaken(closure($callback), $target); + + $callbackId = $this->writer->registerCallback($callback, $this->instrument); + $this->referenceCounter->acquire(); + + $destructor = null; + if ($target) { + $destructor = $this->destructors[$target] ??= new ObservableCallbackDestructor($this->writer, $this->referenceCounter); + $destructor->callbackIds[$callbackId] = $callbackId; + } + + return new ObservableCallback($this->writer, $this->referenceCounter, $callbackId, $destructor, $target); + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/ObservableUpDownCounter.php b/vendor/open-telemetry/sdk/Metrics/ObservableUpDownCounter.php new file mode 100644 index 000000000..8d21be734 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/ObservableUpDownCounter.php @@ -0,0 +1,15 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics; + +use OpenTelemetry\API\Metrics\ObservableUpDownCounterInterface; + +/** + * @internal + */ +final class ObservableUpDownCounter implements ObservableUpDownCounterInterface +{ + use ObservableInstrumentTrait; +} diff --git a/vendor/open-telemetry/sdk/Metrics/PushMetricExporterInterface.php b/vendor/open-telemetry/sdk/Metrics/PushMetricExporterInterface.php new file mode 100644 index 000000000..d24b0e396 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/PushMetricExporterInterface.php @@ -0,0 +1,12 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics; + +use OpenTelemetry\SDK\Metrics; + +interface PushMetricExporterInterface extends Metrics\MetricExporterInterface +{ + public function forceFlush(): bool; +} diff --git a/vendor/open-telemetry/sdk/Metrics/ReferenceCounterInterface.php b/vendor/open-telemetry/sdk/Metrics/ReferenceCounterInterface.php new file mode 100644 index 000000000..f7e70b644 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/ReferenceCounterInterface.php @@ -0,0 +1,15 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics; + +/** + * @internal + */ +interface ReferenceCounterInterface +{ + public function acquire(bool $persistent = false): void; + + public function release(): void; +} diff --git a/vendor/open-telemetry/sdk/Metrics/StalenessHandler/DelayedStalenessHandler.php b/vendor/open-telemetry/sdk/Metrics/StalenessHandler/DelayedStalenessHandler.php new file mode 100644 index 000000000..66b271018 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/StalenessHandler/DelayedStalenessHandler.php @@ -0,0 +1,71 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\StalenessHandler; + +use function assert; +use Closure; +use OpenTelemetry\SDK\Metrics\ReferenceCounterInterface; +use OpenTelemetry\SDK\Metrics\StalenessHandlerInterface; + +/** + * @internal + */ +final class DelayedStalenessHandler implements StalenessHandlerInterface, ReferenceCounterInterface +{ + private Closure $stale; + private Closure $freshen; + + /** @var Closure[]|null */ + private ?array $onStale = []; + private int $count = 0; + + public function __construct(Closure $stale, Closure $freshen) + { + $this->stale = $stale; + $this->freshen = $freshen; + } + + public function acquire(bool $persistent = false): void + { + if ($this->count === 0) { + ($this->freshen)($this); + } + + $this->count++; + + if ($persistent) { + $this->onStale = null; + } + } + + public function release(): void + { + if (--$this->count || $this->onStale === null) { + return; + } + + ($this->stale)($this); + } + + public function onStale(Closure $callback): void + { + if ($this->onStale === null) { + return; + } + + $this->onStale[] = $callback; + } + + public function triggerStale(): void + { + assert($this->onStale !== null); + + $callbacks = $this->onStale; + $this->onStale = []; + foreach ($callbacks as $callback) { + $callback(); + } + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/StalenessHandler/DelayedStalenessHandlerFactory.php b/vendor/open-telemetry/sdk/Metrics/StalenessHandler/DelayedStalenessHandlerFactory.php new file mode 100644 index 000000000..0d719c74f --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/StalenessHandler/DelayedStalenessHandlerFactory.php @@ -0,0 +1,64 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\StalenessHandler; + +use ArrayAccess; +use Closure; +use OpenTelemetry\SDK\Common\Time\ClockInterface; +use OpenTelemetry\SDK\Common\Util\WeakMap; +use OpenTelemetry\SDK\Metrics\StalenessHandlerFactoryInterface; +use OpenTelemetry\SDK\Metrics\StalenessHandlerInterface; +use Traversable; + +final class DelayedStalenessHandlerFactory implements StalenessHandlerFactoryInterface +{ + private ClockInterface $clock; + private int $nanoDelay; + + private Closure $stale; + private Closure $freshen; + + /** @var ArrayAccess<DelayedStalenessHandler, int>&Traversable<DelayedStalenessHandler, int> */ + private $staleHandlers; + + /** + * @param float $delay delay in seconds + */ + public function __construct(ClockInterface $clock, float $delay) + { + $this->clock = $clock; + $this->nanoDelay = (int) ($delay * 1e9); + + $this->stale = function (DelayedStalenessHandler $handler): void { + $this->staleHandlers[$handler] = $this->clock->now(); + }; + $this->freshen = function (DelayedStalenessHandler $handler): void { + unset($this->staleHandlers[$handler]); + }; + + $this->staleHandlers = WeakMap::create(); + } + + public function create(): StalenessHandlerInterface + { + $this->triggerStaleHandlers(); + + return new DelayedStalenessHandler($this->stale, $this->freshen); + } + + private function triggerStaleHandlers(): void + { + $expired = $this->clock->now() - $this->nanoDelay; + foreach ($this->staleHandlers as $handler => $timestamp) { + if ($timestamp > $expired) { + break; + } + + /** @var DelayedStalenessHandler $handler */ + unset($this->staleHandlers[$handler]); + $handler->triggerStale(); + } + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/StalenessHandler/ImmediateStalenessHandler.php b/vendor/open-telemetry/sdk/Metrics/StalenessHandler/ImmediateStalenessHandler.php new file mode 100644 index 000000000..a5b32d5c4 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/StalenessHandler/ImmediateStalenessHandler.php @@ -0,0 +1,50 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\StalenessHandler; + +use Closure; +use OpenTelemetry\SDK\Metrics\ReferenceCounterInterface; +use OpenTelemetry\SDK\Metrics\StalenessHandlerInterface; + +/** + * @internal + */ +final class ImmediateStalenessHandler implements StalenessHandlerInterface, ReferenceCounterInterface +{ + /** @var Closure[]|null */ + private ?array $onStale = []; + private int $count = 0; + + public function acquire(bool $persistent = false): void + { + $this->count++; + + if ($persistent) { + $this->onStale = null; + } + } + + public function release(): void + { + if (--$this->count !== 0 || !$this->onStale) { + return; + } + + $callbacks = $this->onStale; + $this->onStale = []; + foreach ($callbacks as $callback) { + $callback(); + } + } + + public function onStale(Closure $callback): void + { + if ($this->onStale === null) { + return; + } + + $this->onStale[] = $callback; + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/StalenessHandler/ImmediateStalenessHandlerFactory.php b/vendor/open-telemetry/sdk/Metrics/StalenessHandler/ImmediateStalenessHandlerFactory.php new file mode 100644 index 000000000..899615dea --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/StalenessHandler/ImmediateStalenessHandlerFactory.php @@ -0,0 +1,16 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\StalenessHandler; + +use OpenTelemetry\SDK\Metrics\StalenessHandlerFactoryInterface; +use OpenTelemetry\SDK\Metrics\StalenessHandlerInterface; + +final class ImmediateStalenessHandlerFactory implements StalenessHandlerFactoryInterface +{ + public function create(): StalenessHandlerInterface + { + return new ImmediateStalenessHandler(); + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/StalenessHandler/NoopStalenessHandler.php b/vendor/open-telemetry/sdk/Metrics/StalenessHandler/NoopStalenessHandler.php new file mode 100644 index 000000000..00d432b6b --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/StalenessHandler/NoopStalenessHandler.php @@ -0,0 +1,30 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\StalenessHandler; + +use Closure; +use OpenTelemetry\SDK\Metrics\ReferenceCounterInterface; +use OpenTelemetry\SDK\Metrics\StalenessHandlerInterface; + +/** + * @internal + */ +final class NoopStalenessHandler implements StalenessHandlerInterface, ReferenceCounterInterface +{ + public function acquire(bool $persistent = false): void + { + // no-op + } + + public function release(): void + { + // no-op + } + + public function onStale(Closure $callback): void + { + // no-op + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/StalenessHandler/NoopStalenessHandlerFactory.php b/vendor/open-telemetry/sdk/Metrics/StalenessHandler/NoopStalenessHandlerFactory.php new file mode 100644 index 000000000..07f34e3b0 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/StalenessHandler/NoopStalenessHandlerFactory.php @@ -0,0 +1,18 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\StalenessHandler; + +use OpenTelemetry\SDK\Metrics\StalenessHandlerFactoryInterface; +use OpenTelemetry\SDK\Metrics\StalenessHandlerInterface; + +final class NoopStalenessHandlerFactory implements StalenessHandlerFactoryInterface +{ + public function create(): StalenessHandlerInterface + { + static $instance; + + return $instance ??= new NoopStalenessHandler(); + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/StalenessHandlerFactoryInterface.php b/vendor/open-telemetry/sdk/Metrics/StalenessHandlerFactoryInterface.php new file mode 100644 index 000000000..e22385420 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/StalenessHandlerFactoryInterface.php @@ -0,0 +1,13 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics; + +interface StalenessHandlerFactoryInterface +{ + /** + * @return StalenessHandlerInterface&ReferenceCounterInterface + */ + public function create(): StalenessHandlerInterface; +} diff --git a/vendor/open-telemetry/sdk/Metrics/StalenessHandlerInterface.php b/vendor/open-telemetry/sdk/Metrics/StalenessHandlerInterface.php new file mode 100644 index 000000000..c85d86f8e --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/StalenessHandlerInterface.php @@ -0,0 +1,12 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics; + +use Closure; + +interface StalenessHandlerInterface +{ + public function onStale(Closure $callback): void; +} diff --git a/vendor/open-telemetry/sdk/Metrics/Stream/AsynchronousMetricStream.php b/vendor/open-telemetry/sdk/Metrics/Stream/AsynchronousMetricStream.php new file mode 100644 index 000000000..cb32f94df --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/Stream/AsynchronousMetricStream.php @@ -0,0 +1,111 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\Stream; + +use function array_search; +use function count; +use OpenTelemetry\SDK\Metrics\AggregationInterface; +use OpenTelemetry\SDK\Metrics\Data\DataInterface; +use OpenTelemetry\SDK\Metrics\Data\Exemplar; +use OpenTelemetry\SDK\Metrics\Data\Temporality; + +/** + * @internal + */ +final class AsynchronousMetricStream implements MetricStreamInterface +{ + private AggregationInterface $aggregation; + + private int $startTimestamp; + private Metric $metric; + + /** @var array<int, Metric|null> */ + private array $lastReads = []; + + public function __construct(AggregationInterface $aggregation, int $startTimestamp) + { + $this->aggregation = $aggregation; + $this->startTimestamp = $startTimestamp; + $this->metric = new Metric([], [], $startTimestamp); + } + + public function temporality() + { + return Temporality::CUMULATIVE; + } + + public function timestamp(): int + { + return $this->metric->timestamp; + } + + public function push(Metric $metric): void + { + $this->metric = $metric; + } + + public function register($temporality): int + { + if ($temporality === Temporality::CUMULATIVE) { + return -1; + } + + if (($reader = array_search(null, $this->lastReads, true)) === false) { + $reader = count($this->lastReads); + } + + $this->lastReads[$reader] = $this->metric; + + return $reader; + } + + public function unregister(int $reader): void + { + if (!isset($this->lastReads[$reader])) { + return; + } + + $this->lastReads[$reader] = null; + } + + public function collect(int $reader): DataInterface + { + $metric = $this->metric; + + if (($lastRead = $this->lastReads[$reader] ?? null) === null) { + $temporality = Temporality::CUMULATIVE; + $startTimestamp = $this->startTimestamp; + } else { + $temporality = Temporality::DELTA; + $startTimestamp = $lastRead->timestamp; + + $this->lastReads[$reader] = $metric; + $metric = $this->diff($lastRead, $metric); + } + + return $this->aggregation->toData( + $metric->attributes, + $metric->summaries, + Exemplar::groupByIndex($metric->exemplars), + $startTimestamp, + $metric->timestamp, + $temporality, + ); + } + + private function diff(Metric $lastRead, Metric $metric): Metric + { + $diff = clone $metric; + foreach ($metric->summaries as $k => $summary) { + if (!isset($lastRead->summaries[$k])) { + continue; + } + + $diff->summaries[$k] = $this->aggregation->diff($lastRead->summaries[$k], $summary); + } + + return $diff; + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/Stream/Delta.php b/vendor/open-telemetry/sdk/Metrics/Stream/Delta.php new file mode 100644 index 000000000..a4ff56d71 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/Stream/Delta.php @@ -0,0 +1,33 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\Stream; + +use GMP; + +/** + * @internal + */ +final class Delta +{ + public Metric $metric; + /** + * @psalm-suppress UndefinedDocblockClass + * @phan-suppress PhanUndeclaredTypeProperty + * @var int|GMP + */ + public $readers; + public ?self $prev; + /** + * @psalm-suppress UndefinedDocblockClass + * @phan-suppress PhanUndeclaredTypeParameter + * @param int|GMP $readers + */ + public function __construct(Metric $metric, $readers, ?self $prev = null) + { + $this->metric = $metric; + $this->readers = $readers; + $this->prev = $prev; + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/Stream/DeltaStorage.php b/vendor/open-telemetry/sdk/Metrics/Stream/DeltaStorage.php new file mode 100644 index 000000000..b46a28d65 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/Stream/DeltaStorage.php @@ -0,0 +1,110 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\Stream; + +use function assert; +use GMP; +use OpenTelemetry\SDK\Metrics\AggregationInterface; + +/** + * @internal + */ +final class DeltaStorage +{ + private AggregationInterface $aggregation; + private Delta $head; + + public function __construct(AggregationInterface $aggregation) + { + $this->aggregation = $aggregation; + $this->head = new Delta(new Metric([], [], 0), 0); + + /** @phan-suppress-next-line PhanTypeObjectUnsetDeclaredProperty */ + unset($this->head->metric); + } + + /** + * @psalm-suppress UndefinedDocblockClass + * @phan-suppress PhanUndeclaredTypeParameter + * @param int|GMP $readers + */ + public function add(Metric $metric, $readers): void + { + /** @phpstan-ignore-next-line */ + if ($readers == 0) { + return; + } + + if (($this->head->prev->readers ?? null) != $readers) { + $this->head->prev = new Delta($metric, $readers, $this->head->prev); + } else { + assert($this->head->prev !== null); + $this->mergeInto($this->head->prev->metric, $metric); + } + } + + public function collect(int $reader, bool $retain = false): ?Metric + { + $n = null; + for ($d = $this->head; $d->prev; $d = $d->prev) { + if (($d->prev->readers >> $reader & 1) != 0) { + if ($n !== null) { + assert($n->prev !== null); + $n->prev->readers ^= $d->prev->readers; + $this->mergeInto($d->prev->metric, $n->prev->metric); + $this->tryUnlink($n); + + if ($n->prev === $d->prev) { + continue; + } + } + + $n = $d; + } + } + + $metric = $n->prev->metric ?? null; + + if (!$retain && $n) { + assert($n->prev !== null); + $n->prev->readers ^= ($n->prev->readers & 1 | 1) << $reader; + $this->tryUnlink($n); + } + + return $metric; + } + + private function tryUnlink(Delta $n): void + { + assert($n->prev !== null); + /** @phpstan-ignore-next-line */ + if ($n->prev->readers == 0) { + $n->prev = $n->prev->prev; + + return; + } + + for ($c = $n->prev->prev; + $c && ($n->prev->readers & $c->readers) == 0; + $c = $c->prev) { + } + + if ($c && $n->prev->readers === $c->readers) { + $this->mergeInto($c->metric, $n->prev->metric); + $n->prev = $n->prev->prev; + } + } + + private function mergeInto(Metric $into, Metric $metric): void + { + foreach ($metric->summaries as $k => $summary) { + $into->attributes[$k] ??= $metric->attributes[$k]; + $into->summaries[$k] = isset($into->summaries[$k]) + ? $this->aggregation->merge($into->summaries[$k], $summary) + : $summary; + } + $into->exemplars += $metric->exemplars; + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/Stream/Metric.php b/vendor/open-telemetry/sdk/Metrics/Stream/Metric.php new file mode 100644 index 000000000..6b1db9eef --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/Stream/Metric.php @@ -0,0 +1,44 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\Stream; + +use OpenTelemetry\SDK\Common\Attribute\AttributesInterface; +use OpenTelemetry\SDK\Metrics\Data\Exemplar; + +/** + * @internal + * + * @template T + */ +final class Metric +{ + + /** + * @var array<AttributesInterface> + */ + public array $attributes; + /** + * @var array<T> + */ + public array $summaries; + public int $timestamp; + /** + * @var array<Exemplar> + */ + public array $exemplars; + + /** + * @param array<AttributesInterface> $attributes + * @param array<T> $summaries + * @param array<Exemplar> $exemplars + */ + public function __construct(array $attributes, array $summaries, int $timestamp, array $exemplars = []) + { + $this->attributes = $attributes; + $this->summaries = $summaries; + $this->timestamp = $timestamp; + $this->exemplars = $exemplars; + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/Stream/MetricAggregator.php b/vendor/open-telemetry/sdk/Metrics/Stream/MetricAggregator.php new file mode 100644 index 000000000..b1328eb07 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/Stream/MetricAggregator.php @@ -0,0 +1,73 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\Stream; + +use OpenTelemetry\Context\ContextInterface; +use OpenTelemetry\SDK\Common\Attribute\AttributesInterface; +use OpenTelemetry\SDK\Metrics\AggregationInterface; +use OpenTelemetry\SDK\Metrics\AttributeProcessorInterface; +use OpenTelemetry\SDK\Metrics\Exemplar\ExemplarReservoirInterface; +use function serialize; + +/** + * @internal + */ +final class MetricAggregator implements MetricAggregatorInterface +{ + private ?AttributeProcessorInterface $attributeProcessor; + private AggregationInterface $aggregation; + private ?ExemplarReservoirInterface $exemplarReservoir; + + /** @var array<AttributesInterface> */ + private array $attributes = []; + private array $summaries = []; + + public function __construct( + ?AttributeProcessorInterface $attributeProcessor, + AggregationInterface $aggregation, + ?ExemplarReservoirInterface $exemplarReservoir = null + ) { + $this->attributeProcessor = $attributeProcessor; + $this->aggregation = $aggregation; + $this->exemplarReservoir = $exemplarReservoir; + } + + /** + * @param float|int $value + */ + public function record($value, AttributesInterface $attributes, ContextInterface $context, int $timestamp): void + { + $filteredAttributes = $this->attributeProcessor !== null + ? $this->attributeProcessor->process($attributes, $context) + : $attributes; + $raw = $filteredAttributes->toArray(); + $index = $raw !== [] ? serialize($raw) : 0; + $this->attributes[$index] ??= $filteredAttributes; + $this->aggregation->record( + $this->summaries[$index] ??= $this->aggregation->initialize(), + $value, + $attributes, + $context, + $timestamp, + ); + + if ($this->exemplarReservoir !== null) { + $this->exemplarReservoir->offer($index, $value, $attributes, $context, $timestamp); + } + } + + public function collect(int $timestamp): Metric + { + $exemplars = $this->exemplarReservoir + ? $this->exemplarReservoir->collect($this->attributes) + : []; + $metric = new Metric($this->attributes, $this->summaries, $timestamp, $exemplars); + + $this->attributes = []; + $this->summaries = []; + + return $metric; + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/Stream/MetricAggregatorFactory.php b/vendor/open-telemetry/sdk/Metrics/Stream/MetricAggregatorFactory.php new file mode 100644 index 000000000..5866a72b7 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/Stream/MetricAggregatorFactory.php @@ -0,0 +1,28 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\Stream; + +use OpenTelemetry\SDK\Metrics\AggregationInterface; +use OpenTelemetry\SDK\Metrics\AttributeProcessorInterface; + +/** + * @internal + */ +final class MetricAggregatorFactory implements MetricAggregatorFactoryInterface +{ + private ?AttributeProcessorInterface $attributeProcessor; + private AggregationInterface $aggregation; + + public function __construct(?AttributeProcessorInterface $attributeProcessor, AggregationInterface $aggregation) + { + $this->attributeProcessor = $attributeProcessor; + $this->aggregation = $aggregation; + } + + public function create(): MetricAggregatorInterface + { + return new MetricAggregator($this->attributeProcessor, $this->aggregation); + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/Stream/MetricAggregatorFactoryInterface.php b/vendor/open-telemetry/sdk/Metrics/Stream/MetricAggregatorFactoryInterface.php new file mode 100644 index 000000000..356f682f2 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/Stream/MetricAggregatorFactoryInterface.php @@ -0,0 +1,13 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\Stream; + +/** + * @internal + */ +interface MetricAggregatorFactoryInterface +{ + public function create(): MetricAggregatorInterface; +} diff --git a/vendor/open-telemetry/sdk/Metrics/Stream/MetricAggregatorInterface.php b/vendor/open-telemetry/sdk/Metrics/Stream/MetricAggregatorInterface.php new file mode 100644 index 000000000..2f5cfbf15 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/Stream/MetricAggregatorInterface.php @@ -0,0 +1,12 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\Stream; + +/** + * @internal + */ +interface MetricAggregatorInterface extends WritableMetricStreamInterface, MetricCollectorInterface +{ +} diff --git a/vendor/open-telemetry/sdk/Metrics/Stream/MetricCollectorInterface.php b/vendor/open-telemetry/sdk/Metrics/Stream/MetricCollectorInterface.php new file mode 100644 index 000000000..51a728df7 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/Stream/MetricCollectorInterface.php @@ -0,0 +1,13 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\Stream; + +/** + * @internal + */ +interface MetricCollectorInterface +{ + public function collect(int $timestamp): Metric; +} diff --git a/vendor/open-telemetry/sdk/Metrics/Stream/MetricStreamInterface.php b/vendor/open-telemetry/sdk/Metrics/Stream/MetricStreamInterface.php new file mode 100644 index 000000000..1373a1c93 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/Stream/MetricStreamInterface.php @@ -0,0 +1,58 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\Stream; + +use OpenTelemetry\SDK\Metrics\Data\DataInterface; +use OpenTelemetry\SDK\Metrics\Data\Temporality; + +/** + * @internal + */ +interface MetricStreamInterface +{ + /** + * Returns the internal temporality of this stream. + * + * @return string|Temporality internal temporality + */ + public function temporality(); + + /** + * Returns the last metric timestamp. + * + * @return int metric timestamp + */ + public function timestamp(): int; + + /** + * Pushes metric data to the stream. + * + * @param Metric $metric metric data to push + */ + public function push(Metric $metric): void; + + /** + * Registers a new reader with the given temporality. + * + * @param string|Temporality $temporality temporality to use + * @return int reader id + */ + public function register($temporality): int; + + /** + * Unregisters the given reader. + * + * @param int $reader reader id + */ + public function unregister(int $reader): void; + + /** + * Collects metric data for the given reader. + * + * @param int $reader reader id + * @return DataInterface metric data + */ + public function collect(int $reader): DataInterface; +} diff --git a/vendor/open-telemetry/sdk/Metrics/Stream/SynchronousMetricStream.php b/vendor/open-telemetry/sdk/Metrics/Stream/SynchronousMetricStream.php new file mode 100644 index 000000000..52645504c --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/Stream/SynchronousMetricStream.php @@ -0,0 +1,126 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\Stream; + +use function assert; +use const E_USER_WARNING; +use function extension_loaded; +use GMP; +use function gmp_init; +use function is_int; +use OpenTelemetry\SDK\Metrics\AggregationInterface; +use OpenTelemetry\SDK\Metrics\Data\DataInterface; +use OpenTelemetry\SDK\Metrics\Data\Exemplar; +use OpenTelemetry\SDK\Metrics\Data\Temporality; +use const PHP_INT_SIZE; +use function sprintf; +use function trigger_error; + +/** + * @internal + */ +final class SynchronousMetricStream implements MetricStreamInterface +{ + private AggregationInterface $aggregation; + + private int $timestamp; + + private DeltaStorage $delta; + /** + * @psalm-suppress UndefinedDocblockClass + * @phan-suppress PhanUndeclaredTypeProperty + * @var int|GMP + */ + private $readers = 0; + /** + * @psalm-suppress UndefinedDocblockClass + * @phan-suppress PhanUndeclaredTypeProperty + * @var int|GMP + */ + private $cumulative = 0; + + public function __construct(AggregationInterface $aggregation, int $startTimestamp) + { + $this->aggregation = $aggregation; + $this->timestamp = $startTimestamp; + $this->delta = new DeltaStorage($aggregation); + } + + public function temporality() + { + return Temporality::DELTA; + } + + public function timestamp(): int + { + return $this->timestamp; + } + + public function push(Metric $metric): void + { + [$this->timestamp, $metric->timestamp] = [$metric->timestamp, $this->timestamp]; + $this->delta->add($metric, $this->readers); + } + + public function register($temporality): int + { + $reader = 0; + for ($r = $this->readers; ($r & 1) != 0; $r >>= 1, $reader++) { + } + + if ($reader === (PHP_INT_SIZE << 3) - 1 && is_int($this->readers)) { + if (!extension_loaded('gmp')) { + trigger_error(sprintf('GMP extension required to register over %d readers', (PHP_INT_SIZE << 3) - 1), E_USER_WARNING); + $reader = PHP_INT_SIZE << 3; + } else { + assert(is_int($this->cumulative)); + $this->readers = gmp_init($this->readers); + $this->cumulative = gmp_init($this->cumulative); + } + } + + $readerMask = ($this->readers & 1 | 1) << $reader; + $this->readers ^= $readerMask; + if ($temporality === Temporality::CUMULATIVE) { + $this->cumulative ^= $readerMask; + } + + return $reader; + } + + public function unregister(int $reader): void + { + $readerMask = ($this->readers & 1 | 1) << $reader; + if (($this->readers & $readerMask) == 0) { + return; + } + + $this->delta->collect($reader); + + $this->readers ^= $readerMask; + if (($this->cumulative & $readerMask) != 0) { + $this->cumulative ^= $readerMask; + } + } + + public function collect(int $reader): DataInterface + { + $cumulative = ($this->cumulative >> $reader & 1) != 0; + $metric = $this->delta->collect($reader, $cumulative) ?? new Metric([], [], $this->timestamp); + + $temporality = $cumulative + ? Temporality::CUMULATIVE + : Temporality::DELTA; + + return $this->aggregation->toData( + $metric->attributes, + $metric->summaries, + Exemplar::groupByIndex($metric->exemplars), + $metric->timestamp, + $this->timestamp, + $temporality, + ); + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/Stream/WritableMetricStreamInterface.php b/vendor/open-telemetry/sdk/Metrics/Stream/WritableMetricStreamInterface.php new file mode 100644 index 000000000..9fd425a44 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/Stream/WritableMetricStreamInterface.php @@ -0,0 +1,19 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\Stream; + +use OpenTelemetry\Context\ContextInterface; +use OpenTelemetry\SDK\Common\Attribute\AttributesInterface; + +/** + * @internal + */ +interface WritableMetricStreamInterface +{ + /** + * @param float|int $value + */ + public function record($value, AttributesInterface $attributes, ContextInterface $context, int $timestamp): void; +} diff --git a/vendor/open-telemetry/sdk/Metrics/UpDownCounter.php b/vendor/open-telemetry/sdk/Metrics/UpDownCounter.php new file mode 100644 index 000000000..1adf67f8a --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/UpDownCounter.php @@ -0,0 +1,37 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics; + +use OpenTelemetry\API\Metrics\UpDownCounterInterface; +use OpenTelemetry\SDK\Metrics\MetricRegistry\MetricWriterInterface; + +/** + * @internal + */ +final class UpDownCounter implements UpDownCounterInterface +{ + private MetricWriterInterface $writer; + private Instrument $instrument; + private ReferenceCounterInterface $referenceCounter; + + public function __construct(MetricWriterInterface $writer, Instrument $instrument, ReferenceCounterInterface $referenceCounter) + { + $this->writer = $writer; + $this->instrument = $instrument; + $this->referenceCounter = $referenceCounter; + + $this->referenceCounter->acquire(); + } + + public function __destruct() + { + $this->referenceCounter->release(); + } + + public function add($amount, iterable $attributes = [], $context = null): void + { + $this->writer->record($this->instrument, $amount, $attributes, $context); + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/View/CriteriaViewRegistry.php b/vendor/open-telemetry/sdk/Metrics/View/CriteriaViewRegistry.php new file mode 100644 index 000000000..f387abf9c --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/View/CriteriaViewRegistry.php @@ -0,0 +1,40 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\View; + +use Generator; +use OpenTelemetry\SDK\Common\Instrumentation\InstrumentationScopeInterface; +use OpenTelemetry\SDK\Metrics\Instrument; +use OpenTelemetry\SDK\Metrics\ViewRegistryInterface; + +final class CriteriaViewRegistry implements ViewRegistryInterface +{ + /** @var list<SelectionCriteriaInterface> */ + private array $criteria = []; + /** @var list<ViewTemplate> */ + private array $views = []; + + public function register(SelectionCriteriaInterface $criteria, ViewTemplate $view): void + { + $this->criteria[] = $criteria; + $this->views[] = $view; + } + + public function find(Instrument $instrument, InstrumentationScopeInterface $instrumentationScope): ?iterable + { + $views = $this->generateViews($instrument, $instrumentationScope); + + return $views->valid() ? $views : null; + } + + private function generateViews(Instrument $instrument, InstrumentationScopeInterface $instrumentationScope): Generator + { + foreach ($this->criteria as $i => $criteria) { + if ($criteria->accepts($instrument, $instrumentationScope)) { + yield $this->views[$i]->project($instrument); + } + } + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/View/SelectionCriteria/AllCriteria.php b/vendor/open-telemetry/sdk/Metrics/View/SelectionCriteria/AllCriteria.php new file mode 100644 index 000000000..438297324 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/View/SelectionCriteria/AllCriteria.php @@ -0,0 +1,33 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\View\SelectionCriteria; + +use OpenTelemetry\SDK\Common\Instrumentation\InstrumentationScopeInterface; +use OpenTelemetry\SDK\Metrics\Instrument; +use OpenTelemetry\SDK\Metrics\View\SelectionCriteriaInterface; + +final class AllCriteria implements SelectionCriteriaInterface +{ + private iterable $criteria; + + /** + * @param iterable<SelectionCriteriaInterface> $criteria + */ + public function __construct(iterable $criteria) + { + $this->criteria = $criteria; + } + + public function accepts(Instrument $instrument, InstrumentationScopeInterface $instrumentationScope): bool + { + foreach ($this->criteria as $criterion) { + if (!$criterion->accepts($instrument, $instrumentationScope)) { + return false; + } + } + + return true; + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/View/SelectionCriteria/InstrumentNameCriteria.php b/vendor/open-telemetry/sdk/Metrics/View/SelectionCriteria/InstrumentNameCriteria.php new file mode 100644 index 000000000..ed6034755 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/View/SelectionCriteria/InstrumentNameCriteria.php @@ -0,0 +1,28 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\View\SelectionCriteria; + +use OpenTelemetry\SDK\Common\Instrumentation\InstrumentationScopeInterface; +use OpenTelemetry\SDK\Metrics\Instrument; +use OpenTelemetry\SDK\Metrics\View\SelectionCriteriaInterface; +use function preg_match; +use function preg_quote; +use function sprintf; +use function strtr; + +final class InstrumentNameCriteria implements SelectionCriteriaInterface +{ + private string $pattern; + + public function __construct(string $name) + { + $this->pattern = sprintf('/^%s$/', strtr(preg_quote($name, '/'), ['\\?' => '.', '\\*' => '.*'])); + } + + public function accepts(Instrument $instrument, InstrumentationScopeInterface $instrumentationScope): bool + { + return (bool) preg_match($this->pattern, $instrument->name); + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/View/SelectionCriteria/InstrumentTypeCriteria.php b/vendor/open-telemetry/sdk/Metrics/View/SelectionCriteria/InstrumentTypeCriteria.php new file mode 100644 index 000000000..46a88def0 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/View/SelectionCriteria/InstrumentTypeCriteria.php @@ -0,0 +1,29 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\View\SelectionCriteria; + +use function in_array; +use OpenTelemetry\SDK\Common\Instrumentation\InstrumentationScopeInterface; +use OpenTelemetry\SDK\Metrics\Instrument; +use OpenTelemetry\SDK\Metrics\InstrumentType; +use OpenTelemetry\SDK\Metrics\View\SelectionCriteriaInterface; + +final class InstrumentTypeCriteria implements SelectionCriteriaInterface +{ + private array $instrumentTypes; + + /** + * @param string|InstrumentType|string[]|InstrumentType[] $instrumentType + */ + public function __construct($instrumentType) + { + $this->instrumentTypes = (array) $instrumentType; + } + + public function accepts(Instrument $instrument, InstrumentationScopeInterface $instrumentationScope): bool + { + return in_array($instrument->type, $this->instrumentTypes, true); + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/View/SelectionCriteria/InstrumentationScopeNameCriteria.php b/vendor/open-telemetry/sdk/Metrics/View/SelectionCriteria/InstrumentationScopeNameCriteria.php new file mode 100644 index 000000000..201d1a7b2 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/View/SelectionCriteria/InstrumentationScopeNameCriteria.php @@ -0,0 +1,24 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\View\SelectionCriteria; + +use OpenTelemetry\SDK\Common\Instrumentation\InstrumentationScopeInterface; +use OpenTelemetry\SDK\Metrics\Instrument; +use OpenTelemetry\SDK\Metrics\View\SelectionCriteriaInterface; + +final class InstrumentationScopeNameCriteria implements SelectionCriteriaInterface +{ + private string $name; + + public function __construct(string $name) + { + $this->name = $name; + } + + public function accepts(Instrument $instrument, InstrumentationScopeInterface $instrumentationScope): bool + { + return $this->name === $instrumentationScope->getName(); + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/View/SelectionCriteria/InstrumentationScopeSchemaUrlCriteria.php b/vendor/open-telemetry/sdk/Metrics/View/SelectionCriteria/InstrumentationScopeSchemaUrlCriteria.php new file mode 100644 index 000000000..a11a1d589 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/View/SelectionCriteria/InstrumentationScopeSchemaUrlCriteria.php @@ -0,0 +1,24 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\View\SelectionCriteria; + +use OpenTelemetry\SDK\Common\Instrumentation\InstrumentationScopeInterface; +use OpenTelemetry\SDK\Metrics\Instrument; +use OpenTelemetry\SDK\Metrics\View\SelectionCriteriaInterface; + +final class InstrumentationScopeSchemaUrlCriteria implements SelectionCriteriaInterface +{ + private ?string $schemaUrl; + + public function __construct(?string $schemaUrl) + { + $this->schemaUrl = $schemaUrl; + } + + public function accepts(Instrument $instrument, InstrumentationScopeInterface $instrumentationScope): bool + { + return $this->schemaUrl === $instrumentationScope->getSchemaUrl(); + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/View/SelectionCriteria/InstrumentationScopeVersionCriteria.php b/vendor/open-telemetry/sdk/Metrics/View/SelectionCriteria/InstrumentationScopeVersionCriteria.php new file mode 100644 index 000000000..37d180f99 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/View/SelectionCriteria/InstrumentationScopeVersionCriteria.php @@ -0,0 +1,24 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\View\SelectionCriteria; + +use OpenTelemetry\SDK\Common\Instrumentation\InstrumentationScopeInterface; +use OpenTelemetry\SDK\Metrics\Instrument; +use OpenTelemetry\SDK\Metrics\View\SelectionCriteriaInterface; + +final class InstrumentationScopeVersionCriteria implements SelectionCriteriaInterface +{ + private ?string $version; + + public function __construct(?string $version) + { + $this->version = $version; + } + + public function accepts(Instrument $instrument, InstrumentationScopeInterface $instrumentationScope): bool + { + return $this->version === $instrumentationScope->getVersion(); + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/View/SelectionCriteriaInterface.php b/vendor/open-telemetry/sdk/Metrics/View/SelectionCriteriaInterface.php new file mode 100644 index 000000000..8abd6fa69 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/View/SelectionCriteriaInterface.php @@ -0,0 +1,13 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\View; + +use OpenTelemetry\SDK\Common\Instrumentation\InstrumentationScopeInterface; +use OpenTelemetry\SDK\Metrics\Instrument; + +interface SelectionCriteriaInterface +{ + public function accepts(Instrument $instrument, InstrumentationScopeInterface $instrumentationScope): bool; +} diff --git a/vendor/open-telemetry/sdk/Metrics/View/ViewTemplate.php b/vendor/open-telemetry/sdk/Metrics/View/ViewTemplate.php new file mode 100644 index 000000000..302ed83ae --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/View/ViewTemplate.php @@ -0,0 +1,77 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics\View; + +use OpenTelemetry\SDK\Metrics\AggregationInterface; +use OpenTelemetry\SDK\Metrics\Instrument; +use OpenTelemetry\SDK\Metrics\ViewProjection; + +final class ViewTemplate +{ + private ?string $name = null; + private ?string $description = null; + /** + * @var list<string> + */ + private ?array $attributeKeys = null; + private ?AggregationInterface $aggregation = null; + + private function __construct() + { + } + + public static function create(): self + { + static $instance; + + return $instance ??= new self(); + } + + public function withName(string $name): self + { + $self = clone $this; + $self->name = $name; + + return $self; + } + + public function withDescription(string $description): self + { + $self = clone $this; + $self->description = $description; + + return $self; + } + + /** + * @param list<string> $attributeKeys + */ + public function withAttributeKeys(array $attributeKeys): self + { + $self = clone $this; + $self->attributeKeys = $attributeKeys; + + return $self; + } + + public function withAggregation(?AggregationInterface $aggregation): self + { + $self = clone $this; + $self->aggregation = $aggregation; + + return $self; + } + + public function project(Instrument $instrument): ViewProjection + { + return new ViewProjection( + $this->name ?? $instrument->name, + $instrument->unit, + $this->description ?? $instrument->description, + $this->attributeKeys, + $this->aggregation, + ); + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/ViewProjection.php b/vendor/open-telemetry/sdk/Metrics/ViewProjection.php new file mode 100644 index 000000000..046bd6bb1 --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/ViewProjection.php @@ -0,0 +1,47 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics; + +final class ViewProjection +{ + /** + * @readonly + */ + public string $name; + /** + * @readonly + */ + public ?string $unit; + /** + * @readonly + */ + public ?string $description; + /** + * @readonly + * @var list<string>|null + */ + public ?array $attributeKeys; + /** + * @readonly + */ + public ?AggregationInterface $aggregation; + + /** + * @param list<string>|null $attributeKeys + */ + public function __construct( + string $name, + ?string $unit, + ?string $description, + ?array $attributeKeys, + ?AggregationInterface $aggregation + ) { + $this->name = $name; + $this->unit = $unit; + $this->description = $description; + $this->attributeKeys = $attributeKeys; + $this->aggregation = $aggregation; + } +} diff --git a/vendor/open-telemetry/sdk/Metrics/ViewRegistryInterface.php b/vendor/open-telemetry/sdk/Metrics/ViewRegistryInterface.php new file mode 100644 index 000000000..19d8f9ffd --- /dev/null +++ b/vendor/open-telemetry/sdk/Metrics/ViewRegistryInterface.php @@ -0,0 +1,15 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Metrics; + +use OpenTelemetry\SDK\Common\Instrumentation\InstrumentationScopeInterface; + +interface ViewRegistryInterface +{ + /** + * @return iterable<ViewProjection>|null + */ + public function find(Instrument $instrument, InstrumentationScopeInterface $instrumentationScope): ?iterable; +} diff --git a/vendor/open-telemetry/sdk/Propagation/PropagatorFactory.php b/vendor/open-telemetry/sdk/Propagation/PropagatorFactory.php new file mode 100644 index 000000000..2dc349dfb --- /dev/null +++ b/vendor/open-telemetry/sdk/Propagation/PropagatorFactory.php @@ -0,0 +1,55 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Propagation; + +use OpenTelemetry\API\Behavior\LogsMessagesTrait; +use OpenTelemetry\Context\Propagation\MultiTextMapPropagator; +use OpenTelemetry\Context\Propagation\NoopTextMapPropagator; +use OpenTelemetry\Context\Propagation\TextMapPropagatorInterface; +use OpenTelemetry\SDK\Common\Configuration\Configuration; +use OpenTelemetry\SDK\Common\Configuration\Variables; +use OpenTelemetry\SDK\Registry; + +class PropagatorFactory +{ + use LogsMessagesTrait; + + public function create(): TextMapPropagatorInterface + { + $propagators = Configuration::getList(Variables::OTEL_PROPAGATORS); + switch (count($propagators)) { + case 0: + return new NoopTextMapPropagator(); + case 1: + return $this->buildPropagator($propagators[0]); + default: + return new MultiTextMapPropagator($this->buildPropagators($propagators)); + } + } + + /** + * @return array<TextMapPropagatorInterface> + */ + private function buildPropagators(array $names): array + { + $propagators = []; + foreach ($names as $name) { + $propagators[] = $this->buildPropagator($name); + } + + return $propagators; + } + + private function buildPropagator(string $name): TextMapPropagatorInterface + { + try { + return Registry::textMapPropagator($name); + } catch (\RuntimeException $e) { + self::logWarning($e->getMessage()); + } + + return NoopTextMapPropagator::getInstance(); + } +} diff --git a/vendor/open-telemetry/sdk/Propagation/_register.php b/vendor/open-telemetry/sdk/Propagation/_register.php new file mode 100644 index 000000000..fd90da184 --- /dev/null +++ b/vendor/open-telemetry/sdk/Propagation/_register.php @@ -0,0 +1,16 @@ +<?php + +declare(strict_types=1); + +\OpenTelemetry\SDK\Registry::registerTextMapPropagator( + \OpenTelemetry\SDK\Common\Configuration\KnownValues::VALUE_BAGGAGE, + \OpenTelemetry\API\Baggage\Propagation\BaggagePropagator::getInstance() +); +\OpenTelemetry\SDK\Registry::registerTextMapPropagator( + \OpenTelemetry\SDK\Common\Configuration\KnownValues::VALUE_TRACECONTEXT, + \OpenTelemetry\API\Trace\Propagation\TraceContextPropagator::getInstance() +); +\OpenTelemetry\SDK\Registry::registerTextMapPropagator( + \OpenTelemetry\SDK\Common\Configuration\KnownValues::VALUE_NONE, + \OpenTelemetry\Context\Propagation\NoopTextMapPropagator::getInstance() +); diff --git a/vendor/open-telemetry/sdk/README.md b/vendor/open-telemetry/sdk/README.md new file mode 100644 index 000000000..6346dc0f3 --- /dev/null +++ b/vendor/open-telemetry/sdk/README.md @@ -0,0 +1,49 @@ +[![Releases](https://img.shields.io/badge/releases-purple)](https://github.com/opentelemetry-php/sdk/releases) +[![Source](https://img.shields.io/badge/source-sdk-green)](https://github.com/open-telemetry/opentelemetry-php/tree/main/src/SDK) +[![Mirror](https://img.shields.io/badge/mirror-opentelemetry--php:sdk-blue)](https://github.com/opentelemetry-php/sdk) +[![Latest Version](http://poser.pugx.org/open-telemetry/sdk/v/unstable)](https://packagist.org/packages/open-telemetry/sdk/) +[![Stable](http://poser.pugx.org/open-telemetry/sdk/v/stable)](https://packagist.org/packages/open-telemetry/sdk/) + +# OpenTelemetry SDK + +The OpenTelemetry PHP SDK implements the API, and should be used in conjunction with contributed exporter(s) to generate and export telemetry. + +## Documentation + +https://opentelemetry.io/docs/instrumentation/php/sdk/ + +## Getting started + +### Manual setup + +See https://github.com/open-telemetry/opentelemetry-php/tree/main/examples + +### SDK Builder + +See https://github.com/open-telemetry/opentelemetry-php/blob/main/examples/sdk_builder.php + +### Autoloading + +SDK autoloading works with configuration values provided via the environment (or php.ini). + +The SDK can be automatically created and registered, if the following conditions are met: +- `OTEL_PHP_AUTOLOAD_ENABLED=true` +- all required [SDK configuration](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/sdk-environment-variables.md#general-sdk-configuration) is provided + +SDK autoloading will be attempted as part of composer's autoloader: + +```php +require 'vendor/autoload.php'; + +$tracer = \OpenTelemetry\API\Globals::tracerProvider()->getTracer('example'); +$meter = \OpenTelemetry\API\Globals::meterProvider()->getMeter('example'); +``` + +If autoloading was not successful (or partially successful), no-op implementations of the above may be returned. + +See https://github.com/open-telemetry/opentelemetry-php/blob/main/examples/autoload_sdk.php for a more detailed example. + +## Contributing + +This repository is a read-only git subtree split. +To contribute, please see the main [OpenTelemetry PHP monorepo](https://github.com/open-telemetry/opentelemetry-php). diff --git a/vendor/open-telemetry/sdk/Registry.php b/vendor/open-telemetry/sdk/Registry.php new file mode 100644 index 000000000..2f0a20263 --- /dev/null +++ b/vendor/open-telemetry/sdk/Registry.php @@ -0,0 +1,208 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK; + +use OpenTelemetry\Context\Propagation\TextMapPropagatorInterface; +use OpenTelemetry\SDK\Common\Export\TransportFactoryInterface; +use OpenTelemetry\SDK\Logs\LogRecordExporterFactoryInterface; +use OpenTelemetry\SDK\Metrics\MetricExporterFactoryInterface; +use OpenTelemetry\SDK\Resource\ResourceDetectorInterface; +use OpenTelemetry\SDK\Trace\SpanExporter\SpanExporterFactoryInterface; +use RuntimeException; + +/** + * A registry to enable central registration of components that the SDK requires but which may be provided + * by non-SDK modules, such as contrib and extension. + */ +class Registry +{ + private static array $spanExporterFactories = []; + private static array $transportFactories = []; + private static array $metricExporterFactories = []; + private static array $textMapPropagators = []; + private static array $logRecordExporterFactories = []; + private static array $resourceDetectors = []; + + /** + * @param TransportFactoryInterface|class-string<TransportFactoryInterface> $factory + */ + public static function registerTransportFactory(string $protocol, $factory, bool $clobber = false): void + { + if (!$clobber && array_key_exists($protocol, self::$transportFactories)) { + return; + } + if (!is_subclass_of($factory, TransportFactoryInterface::class)) { + trigger_error( + sprintf( + 'Cannot register transport factory: %s must exist and implement %s', + is_string($factory) ? $factory : get_class($factory), + TransportFactoryInterface::class + ), + E_USER_WARNING + ); + + return; + } + self::$transportFactories[$protocol] = $factory; + } + + /** + * @param SpanExporterFactoryInterface|class-string<SpanExporterFactoryInterface> $factory + */ + public static function registerSpanExporterFactory(string $exporter, $factory, bool $clobber = false): void + { + if (!$clobber && array_key_exists($exporter, self::$spanExporterFactories)) { + return; + } + if (!is_subclass_of($factory, SpanExporterFactoryInterface::class)) { + trigger_error( + sprintf( + 'Cannot register span exporter factory: %s must exist and implement %s', + is_string($factory) ? $factory : get_class($factory), + SpanExporterFactoryInterface::class + ), + E_USER_WARNING + ); + + return; + } + self::$spanExporterFactories[$exporter] = $factory; + } + + /** + * @param MetricExporterFactoryInterface|class-string<MetricExporterFactoryInterface> $factory + */ + public static function registerMetricExporterFactory(string $exporter, $factory, bool $clobber = false): void + { + if (!$clobber && array_key_exists($exporter, self::$metricExporterFactories)) { + return; + } + if (!is_subclass_of($factory, MetricExporterFactoryInterface::class)) { + trigger_error( + sprintf( + 'Cannot register metric factory: %s must exist and implement %s', + is_string($factory) ? $factory : get_class($factory), + MetricExporterFactoryInterface::class + ), + E_USER_WARNING + ); + + return; + } + self::$metricExporterFactories[$exporter] = $factory; + } + + public static function registerLogRecordExporterFactory(string $exporter, $factory, bool $clobber = false): void + { + if (!$clobber && array_key_exists($exporter, self::$logRecordExporterFactories)) { + return; + } + if (!is_subclass_of($factory, LogRecordExporterFactoryInterface::class)) { + trigger_error( + sprintf( + 'Cannot register LogRecord exporter factory: %s must exist and implement %s', + is_string($factory) ? $factory : get_class($factory), + LogRecordExporterFactoryInterface::class + ), + E_USER_WARNING + ); + + return; + } + self::$logRecordExporterFactories[$exporter] = $factory; + } + + public static function registerTextMapPropagator(string $name, TextMapPropagatorInterface $propagator, bool $clobber = false): void + { + if (!$clobber && array_key_exists($name, self::$textMapPropagators)) { + return; + } + self::$textMapPropagators[$name] = $propagator; + } + + public static function registerResourceDetector(string $name, ResourceDetectorInterface $detector): void + { + self::$resourceDetectors[$name] = $detector; + } + + public static function spanExporterFactory(string $exporter): SpanExporterFactoryInterface + { + if (!array_key_exists($exporter, self::$spanExporterFactories)) { + throw new RuntimeException('Span exporter factory not defined for: ' . $exporter); + } + $class = self::$spanExporterFactories[$exporter]; + $factory = (is_callable($class)) ? $class : new $class(); + assert($factory instanceof SpanExporterFactoryInterface); + + return $factory; + } + + public static function logRecordExporterFactory(string $exporter): LogRecordExporterFactoryInterface + { + if (!array_key_exists($exporter, self::$logRecordExporterFactories)) { + throw new RuntimeException('LogRecord exporter factory not defined for: ' . $exporter); + } + $class = self::$logRecordExporterFactories[$exporter]; + $factory = (is_callable($class)) ? $class : new $class(); + assert($factory instanceof LogRecordExporterFactoryInterface); + + return $factory; + } + + /** + * Get transport factory registered for protocol. If $protocol contains a content-type eg `http/xyz` then + * only the first part, `http`, is used. + */ + public static function transportFactory(string $protocol): TransportFactoryInterface + { + $protocol = explode('/', $protocol)[0]; + if (!array_key_exists($protocol, self::$transportFactories)) { + throw new RuntimeException('Transport factory not defined for protocol: ' . $protocol); + } + $class = self::$transportFactories[$protocol]; + $factory = (is_callable($class)) ? $class : new $class(); + assert($factory instanceof TransportFactoryInterface); + + return $factory; + } + + public static function metricExporterFactory(string $exporter): MetricExporterFactoryInterface + { + if (!array_key_exists($exporter, self::$metricExporterFactories)) { + throw new RuntimeException('Metric exporter factory not registered for protocol: ' . $exporter); + } + $class = self::$metricExporterFactories[$exporter]; + $factory = (is_callable($class)) ? $class : new $class(); + assert($factory instanceof MetricExporterFactoryInterface); + + return $factory; + } + + public static function textMapPropagator(string $name): TextMapPropagatorInterface + { + if (!array_key_exists($name, self::$textMapPropagators)) { + throw new RuntimeException('Text map propagator not registered for: ' . $name); + } + + return self::$textMapPropagators[$name]; + } + + public static function resourceDetector(string $name): ResourceDetectorInterface + { + if (!array_key_exists($name, self::$resourceDetectors)) { + throw new RuntimeException('Resource detector not registered for: ' . $name); + } + + return self::$resourceDetectors[$name]; + } + + /** + * @return array<int, ResourceDetectorInterface> + */ + public static function resourceDetectors(): array + { + return array_values(self::$resourceDetectors); + } +} diff --git a/vendor/open-telemetry/sdk/Resource/Detectors/Composer.php b/vendor/open-telemetry/sdk/Resource/Detectors/Composer.php new file mode 100644 index 000000000..56b136ef1 --- /dev/null +++ b/vendor/open-telemetry/sdk/Resource/Detectors/Composer.php @@ -0,0 +1,30 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Resource\Detectors; + +use function class_exists; +use Composer\InstalledVersions; +use OpenTelemetry\SDK\Common\Attribute\Attributes; +use OpenTelemetry\SDK\Resource\ResourceDetectorInterface; +use OpenTelemetry\SDK\Resource\ResourceInfo; +use OpenTelemetry\SDK\Resource\ResourceInfoFactory; +use OpenTelemetry\SemConv\ResourceAttributes; + +final class Composer implements ResourceDetectorInterface +{ + public function getResource(): ResourceInfo + { + if (!class_exists(InstalledVersions::class)) { + return ResourceInfoFactory::emptyResource(); + } + + $attributes = [ + ResourceAttributes::SERVICE_NAME => InstalledVersions::getRootPackage()['name'], + ResourceAttributes::SERVICE_VERSION => InstalledVersions::getRootPackage()['pretty_version'], + ]; + + return ResourceInfo::create(Attributes::create($attributes), ResourceAttributes::SCHEMA_URL); + } +} diff --git a/vendor/open-telemetry/sdk/Resource/Detectors/Composite.php b/vendor/open-telemetry/sdk/Resource/Detectors/Composite.php new file mode 100644 index 000000000..9da267743 --- /dev/null +++ b/vendor/open-telemetry/sdk/Resource/Detectors/Composite.php @@ -0,0 +1,32 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Resource\Detectors; + +use OpenTelemetry\SDK\Resource\ResourceDetectorInterface; +use OpenTelemetry\SDK\Resource\ResourceInfo; +use OpenTelemetry\SDK\Resource\ResourceInfoFactory; + +final class Composite implements ResourceDetectorInterface +{ + private iterable $resourceDetectors; + + /** + * @param iterable<ResourceDetectorInterface> $resourceDetectors + */ + public function __construct(iterable $resourceDetectors) + { + $this->resourceDetectors = $resourceDetectors; + } + + public function getResource(): ResourceInfo + { + $resource = ResourceInfoFactory::emptyResource(); + foreach ($this->resourceDetectors as $resourceDetector) { + $resource = $resource->merge($resourceDetector->getResource()); + } + + return $resource; + } +} diff --git a/vendor/open-telemetry/sdk/Resource/Detectors/Constant.php b/vendor/open-telemetry/sdk/Resource/Detectors/Constant.php new file mode 100644 index 000000000..7ff9d19eb --- /dev/null +++ b/vendor/open-telemetry/sdk/Resource/Detectors/Constant.php @@ -0,0 +1,23 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Resource\Detectors; + +use OpenTelemetry\SDK\Resource\ResourceDetectorInterface; +use OpenTelemetry\SDK\Resource\ResourceInfo; + +final class Constant implements ResourceDetectorInterface +{ + private ResourceInfo $resourceInfo; + + public function __construct(ResourceInfo $resourceInfo) + { + $this->resourceInfo = $resourceInfo; + } + + public function getResource(): ResourceInfo + { + return $this->resourceInfo; + } +} diff --git a/vendor/open-telemetry/sdk/Resource/Detectors/Environment.php b/vendor/open-telemetry/sdk/Resource/Detectors/Environment.php new file mode 100644 index 000000000..ceee8fcf7 --- /dev/null +++ b/vendor/open-telemetry/sdk/Resource/Detectors/Environment.php @@ -0,0 +1,40 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Resource\Detectors; + +use OpenTelemetry\SDK\Common\Attribute\Attributes; +use OpenTelemetry\SDK\Common\Configuration\Configuration; +use OpenTelemetry\SDK\Common\Configuration\Variables; +use OpenTelemetry\SDK\Resource\ResourceDetectorInterface; +use OpenTelemetry\SDK\Resource\ResourceInfo; +use OpenTelemetry\SemConv\ResourceAttributes; + +/** + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/resource/sdk.md#specifying-resource-information-via-an-environment-variable + */ +final class Environment implements ResourceDetectorInterface +{ + public function getResource(): ResourceInfo + { + $attributes = Configuration::has(Variables::OTEL_RESOURCE_ATTRIBUTES) + ? self::decode(Configuration::getMap(Variables::OTEL_RESOURCE_ATTRIBUTES, [])) + : []; + + //@see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/configuration/sdk-environment-variables.md#general-sdk-configuration + $serviceName = Configuration::has(Variables::OTEL_SERVICE_NAME) + ? Configuration::getString(Variables::OTEL_SERVICE_NAME) + : null; + if ($serviceName) { + $attributes[ResourceAttributes::SERVICE_NAME] = $serviceName; + } + + return ResourceInfo::create(Attributes::create($attributes), ResourceAttributes::SCHEMA_URL); + } + + private static function decode(array $attributes): array + { + return array_map('urldecode', $attributes); + } +} diff --git a/vendor/open-telemetry/sdk/Resource/Detectors/Host.php b/vendor/open-telemetry/sdk/Resource/Detectors/Host.php new file mode 100644 index 000000000..dd2554540 --- /dev/null +++ b/vendor/open-telemetry/sdk/Resource/Detectors/Host.php @@ -0,0 +1,27 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Resource\Detectors; + +use OpenTelemetry\SDK\Common\Attribute\Attributes; +use OpenTelemetry\SDK\Resource\ResourceDetectorInterface; +use OpenTelemetry\SDK\Resource\ResourceInfo; +use OpenTelemetry\SemConv\ResourceAttributes; +use function php_uname; + +/** + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/v1.8.0/specification/resource/semantic_conventions/host.md#host + */ +final class Host implements ResourceDetectorInterface +{ + public function getResource(): ResourceInfo + { + $attributes = [ + ResourceAttributes::HOST_NAME => php_uname('n'), + ResourceAttributes::HOST_ARCH => php_uname('m'), + ]; + + return ResourceInfo::create(Attributes::create($attributes), ResourceAttributes::SCHEMA_URL); + } +} diff --git a/vendor/open-telemetry/sdk/Resource/Detectors/OperatingSystem.php b/vendor/open-telemetry/sdk/Resource/Detectors/OperatingSystem.php new file mode 100644 index 000000000..2cb350dc2 --- /dev/null +++ b/vendor/open-telemetry/sdk/Resource/Detectors/OperatingSystem.php @@ -0,0 +1,32 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Resource\Detectors; + +use OpenTelemetry\SDK\Common\Attribute\Attributes; +use OpenTelemetry\SDK\Resource\ResourceDetectorInterface; +use OpenTelemetry\SDK\Resource\ResourceInfo; +use OpenTelemetry\SemConv\ResourceAttributes; +use const PHP_OS; +use const PHP_OS_FAMILY; +use function php_uname; +use function strtolower; + +/** + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/v1.8.0/specification/resource/semantic_conventions/os.md + */ +final class OperatingSystem implements ResourceDetectorInterface +{ + public function getResource(): ResourceInfo + { + $attributes = [ + ResourceAttributes::OS_TYPE => strtolower(PHP_OS_FAMILY), + ResourceAttributes::OS_DESCRIPTION => php_uname('r'), + ResourceAttributes::OS_NAME => PHP_OS, + ResourceAttributes::OS_VERSION => php_uname('v'), + ]; + + return ResourceInfo::create(Attributes::create($attributes), ResourceAttributes::SCHEMA_URL); + } +} diff --git a/vendor/open-telemetry/sdk/Resource/Detectors/Process.php b/vendor/open-telemetry/sdk/Resource/Detectors/Process.php new file mode 100644 index 000000000..7f1d99386 --- /dev/null +++ b/vendor/open-telemetry/sdk/Resource/Detectors/Process.php @@ -0,0 +1,43 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Resource\Detectors; + +use function extension_loaded; +use function getmypid; +use OpenTelemetry\SDK\Common\Attribute\Attributes; +use OpenTelemetry\SDK\Resource\ResourceDetectorInterface; +use OpenTelemetry\SDK\Resource\ResourceInfo; +use OpenTelemetry\SemConv\ResourceAttributes; +use const PHP_BINARY; + +/** + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/v1.8.0/specification/resource/semantic_conventions/process.md#process + */ +final class Process implements ResourceDetectorInterface +{ + /** + * @psalm-suppress PossiblyUndefinedArrayOffset + */ + public function getResource(): ResourceInfo + { + $attributes = []; + $attributes[ResourceAttributes::PROCESS_PID] = getmypid(); + $attributes[ResourceAttributes::PROCESS_EXECUTABLE_PATH] = PHP_BINARY; + /** + * @psalm-suppress PossiblyUndefinedArrayOffset + */ + if ($_SERVER['argv'] ?? null) { + $attributes[ResourceAttributes::PROCESS_COMMAND] = $_SERVER['argv'][0]; + $attributes[ResourceAttributes::PROCESS_COMMAND_ARGS] = $_SERVER['argv']; + } + + /** @phan-suppress-next-line PhanTypeComparisonFromArray */ + if (extension_loaded('posix') && ($user = \posix_getpwuid(\posix_geteuid())) !== false) { + $attributes[ResourceAttributes::PROCESS_OWNER] = $user['name']; + } + + return ResourceInfo::create(Attributes::create($attributes), ResourceAttributes::SCHEMA_URL); + } +} diff --git a/vendor/open-telemetry/sdk/Resource/Detectors/ProcessRuntime.php b/vendor/open-telemetry/sdk/Resource/Detectors/ProcessRuntime.php new file mode 100644 index 000000000..f29ddfc8f --- /dev/null +++ b/vendor/open-telemetry/sdk/Resource/Detectors/ProcessRuntime.php @@ -0,0 +1,28 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Resource\Detectors; + +use OpenTelemetry\SDK\Common\Attribute\Attributes; +use OpenTelemetry\SDK\Resource\ResourceDetectorInterface; +use OpenTelemetry\SDK\Resource\ResourceInfo; +use OpenTelemetry\SemConv\ResourceAttributes; +use function php_sapi_name; +use const PHP_VERSION; + +/** + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/v1.8.0/specification/resource/semantic_conventions/process.md#process-runtimes + */ +final class ProcessRuntime implements ResourceDetectorInterface +{ + public function getResource(): ResourceInfo + { + $attributes = [ + ResourceAttributes::PROCESS_RUNTIME_NAME => php_sapi_name(), + ResourceAttributes::PROCESS_RUNTIME_VERSION => PHP_VERSION, + ]; + + return ResourceInfo::create(Attributes::create($attributes), ResourceAttributes::SCHEMA_URL); + } +} diff --git a/vendor/open-telemetry/sdk/Resource/Detectors/Sdk.php b/vendor/open-telemetry/sdk/Resource/Detectors/Sdk.php new file mode 100644 index 000000000..dba3eb8aa --- /dev/null +++ b/vendor/open-telemetry/sdk/Resource/Detectors/Sdk.php @@ -0,0 +1,53 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Resource\Detectors; + +use function class_exists; +use Composer\InstalledVersions; +use OpenTelemetry\SDK\Common\Attribute\Attributes; +use OpenTelemetry\SDK\Resource\ResourceDetectorInterface; +use OpenTelemetry\SDK\Resource\ResourceInfo; +use OpenTelemetry\SemConv\ResourceAttributes; + +/** + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/v1.8.0/specification/resource/semantic_conventions/README.md#telemetry-sdk + */ +final class Sdk implements ResourceDetectorInterface +{ + private const PACKAGES = [ + 'open-telemetry/sdk', + 'open-telemetry/opentelemetry', + ]; + + public function getResource(): ResourceInfo + { + $attributes = [ + ResourceAttributes::TELEMETRY_SDK_NAME => 'opentelemetry', + ResourceAttributes::TELEMETRY_SDK_LANGUAGE => 'php', + ]; + + if (class_exists(InstalledVersions::class)) { + foreach (self::PACKAGES as $package) { + if (!InstalledVersions::isInstalled($package)) { + continue; + } + if (($version = InstalledVersions::getPrettyVersion($package)) === null) { + continue; + } + + $attributes[ResourceAttributes::TELEMETRY_SDK_VERSION] = $version; + + break; + } + } + + if (extension_loaded('opentelemetry')) { + $attributes[ResourceAttributes::TELEMETRY_DISTRO_NAME] = 'opentelemetry-php-instrumentation'; + $attributes[ResourceAttributes::TELEMETRY_DISTRO_VERSION] = phpversion('opentelemetry'); + } + + return ResourceInfo::create(Attributes::create($attributes), ResourceAttributes::SCHEMA_URL); + } +} diff --git a/vendor/open-telemetry/sdk/Resource/Detectors/SdkProvided.php b/vendor/open-telemetry/sdk/Resource/Detectors/SdkProvided.php new file mode 100644 index 000000000..ec4ec7def --- /dev/null +++ b/vendor/open-telemetry/sdk/Resource/Detectors/SdkProvided.php @@ -0,0 +1,25 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Resource\Detectors; + +use OpenTelemetry\SDK\Common\Attribute\Attributes; +use OpenTelemetry\SDK\Resource\ResourceDetectorInterface; +use OpenTelemetry\SDK\Resource\ResourceInfo; +use OpenTelemetry\SemConv\ResourceAttributes; + +/** + * @see https://github.com/open-telemetry/semantic-conventions/blob/main/docs/resource/README.md#semantic-attributes-with-sdk-provided-default-value + */ +final class SdkProvided implements ResourceDetectorInterface +{ + public function getResource(): ResourceInfo + { + $attributes = [ + ResourceAttributes::SERVICE_NAME => 'unknown_service:php', + ]; + + return ResourceInfo::create(Attributes::create($attributes), ResourceAttributes::SCHEMA_URL); + } +} diff --git a/vendor/open-telemetry/sdk/Resource/ResourceDetectorInterface.php b/vendor/open-telemetry/sdk/Resource/ResourceDetectorInterface.php new file mode 100644 index 000000000..f2cd5256b --- /dev/null +++ b/vendor/open-telemetry/sdk/Resource/ResourceDetectorInterface.php @@ -0,0 +1,10 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Resource; + +interface ResourceDetectorInterface +{ + public function getResource(): ResourceInfo; +} diff --git a/vendor/open-telemetry/sdk/Resource/ResourceInfo.php b/vendor/open-telemetry/sdk/Resource/ResourceInfo.php new file mode 100644 index 000000000..4210a6142 --- /dev/null +++ b/vendor/open-telemetry/sdk/Resource/ResourceInfo.php @@ -0,0 +1,125 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Resource; + +use OpenTelemetry\API\Behavior\LogsMessagesTrait; +use OpenTelemetry\SDK\Common\Attribute\Attributes; +use OpenTelemetry\SDK\Common\Attribute\AttributesInterface; + +use OpenTelemetry\SDK\Common\Dev\Compatibility\Util as BcUtil; + +/** + * A Resource is an immutable representation of the entity producing telemetry. For example, a process producing telemetry + * that is running in a container on Kubernetes has a Pod name, it is in a namespace and possibly is part of a Deployment + * which also has a name. All three of these attributes can be included in the Resource. + * + * The class named as ResourceInfo due to `resource` is the soft reserved word in PHP. + */ +class ResourceInfo +{ + use LogsMessagesTrait; + + private AttributesInterface $attributes; + private ?string $schemaUrl; + + private function __construct(AttributesInterface $attributes, ?string $schemaUrl = null) + { + $this->attributes = $attributes; + $this->schemaUrl = $schemaUrl; + } + + public static function create(AttributesInterface $attributes, ?string $schemaUrl = null): self + { + return new ResourceInfo($attributes, $schemaUrl); + } + + public function getAttributes(): AttributesInterface + { + return $this->attributes; + } + + public function getSchemaUrl(): ?string + { + return $this->schemaUrl; + } + + public function serialize(): string + { + $copyOfAttributesAsArray = array_slice($this->attributes->toArray(), 0); //This may be overly cautious (in trying to avoid mutating the source array) + ksort($copyOfAttributesAsArray); //sort the associative array by keys since the serializer will consider equal arrays different otherwise + + //The exact return value doesn't matter, as long as it can distingusih between instances that represent the same/different resources + return serialize([ + 'schemaUrl' => $this->schemaUrl, + 'attributes' => $copyOfAttributesAsArray, + ]); + } + + /** + * Merge current resource with an updating resource, combining all attributes. If a key exists on both the old and updating + * resource, the value of the updating resource MUST be picked (even if the updated value is empty) + * + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/v1.20.0/specification/resource/sdk.md#merge + */ + public function merge(ResourceInfo $updating): ResourceInfo + { + $schemaUrl = self::mergeSchemaUrl($this->getSchemaUrl(), $updating->getSchemaUrl()); + $attributes = $updating->getAttributes()->toArray() + $this->getAttributes()->toArray(); + + return ResourceInfo::create(Attributes::create($attributes), $schemaUrl); + } + + /** + * Merge the schema URLs from the old and updating resource. + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/v1.20.0/specification/resource/sdk.md#merge + */ + private static function mergeSchemaUrl(?string $old, ?string $updating): ?string + { + if (empty($old)) { + return $updating; + } + if (empty($updating)) { + return $old; + } + if ($old === $updating) { + return $old; + } + + self::logWarning('Merging resources with different schema URLs', [ + 'old' => $old, + 'updating' => $updating, + ]); + + return null; + } + + /** + * @codeCoverageIgnore + */ + public static function defaultResource(): ResourceInfo + { + BcUtil::triggerMethodDeprecationNotice( + __METHOD__, + 'defaultResource', + ResourceInfoFactory::class + ); + + return ResourceInfoFactory::defaultResource(); + } + + /** + * @codeCoverageIgnore + */ + public static function emptyResource(): ResourceInfo + { + BcUtil::triggerMethodDeprecationNotice( + __METHOD__, + 'emptyResource', + ResourceInfoFactory::class + ); + + return ResourceInfoFactory::emptyResource(); + } +} diff --git a/vendor/open-telemetry/sdk/Resource/ResourceInfoFactory.php b/vendor/open-telemetry/sdk/Resource/ResourceInfoFactory.php new file mode 100644 index 000000000..7fc80bcd9 --- /dev/null +++ b/vendor/open-telemetry/sdk/Resource/ResourceInfoFactory.php @@ -0,0 +1,95 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK\Resource; + +use function in_array; +use OpenTelemetry\API\Behavior\LogsMessagesTrait; +use OpenTelemetry\SDK\Common\Attribute\Attributes; +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\Registry; +use RuntimeException; + +class ResourceInfoFactory +{ + use LogsMessagesTrait; + + public static function defaultResource(): ResourceInfo + { + $detectors = Configuration::getList(Env::OTEL_PHP_DETECTORS); + + if (in_array(Values::VALUE_ALL, $detectors)) { + // ascending priority: keys from later detectors will overwrite earlier + return (new Detectors\Composite([ + new Detectors\Host(), + new Detectors\OperatingSystem(), + new Detectors\Process(), + new Detectors\ProcessRuntime(), + new Detectors\Sdk(), + new Detectors\SdkProvided(), + new Detectors\Composer(), + ...Registry::resourceDetectors(), + new Detectors\Environment(), + ]))->getResource(); + } + + $resourceDetectors = []; + + foreach ($detectors as $detector) { + switch ($detector) { + case Values::VALUE_DETECTORS_ENVIRONMENT: + $resourceDetectors[] = new Detectors\Environment(); + + break; + case Values::VALUE_DETECTORS_HOST: + $resourceDetectors[] = new Detectors\Host(); + + break; + case Values::VALUE_DETECTORS_OS: + $resourceDetectors[] = new Detectors\OperatingSystem(); + + break; + case Values::VALUE_DETECTORS_PROCESS: + $resourceDetectors[] = new Detectors\Process(); + + break; + case Values::VALUE_DETECTORS_PROCESS_RUNTIME: + $resourceDetectors[] = new Detectors\ProcessRuntime(); + + break; + case Values::VALUE_DETECTORS_SDK: + $resourceDetectors[] = new Detectors\Sdk(); + + break; + case Values::VALUE_DETECTORS_SDK_PROVIDED: + $resourceDetectors[] = new Detectors\SdkProvided(); + + break; + + case Values::VALUE_DETECTORS_COMPOSER: + $resourceDetectors[] = new Detectors\Composer(); + + break; + case Values::VALUE_NONE: + + break; + default: + try { + $resourceDetectors[] = Registry::resourceDetector($detector); + } catch (RuntimeException $e) { + self::logWarning($e->getMessage()); + } + } + } + + return (new Detectors\Composite($resourceDetectors))->getResource(); + } + + public static function emptyResource(): ResourceInfo + { + return ResourceInfo::create(Attributes::create([])); + } +} diff --git a/vendor/open-telemetry/sdk/Sdk.php b/vendor/open-telemetry/sdk/Sdk.php new file mode 100644 index 000000000..3b63eb93a --- /dev/null +++ b/vendor/open-telemetry/sdk/Sdk.php @@ -0,0 +1,70 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK; + +use OpenTelemetry\API\Metrics\MeterProviderInterface; +use OpenTelemetry\API\Trace\TracerProviderInterface; +use OpenTelemetry\Context\Propagation\TextMapPropagatorInterface; +use OpenTelemetry\SDK\Common\Configuration\Configuration; +use OpenTelemetry\SDK\Common\Configuration\Variables; +use OpenTelemetry\SDK\Logs\LoggerProviderInterface; + +class Sdk +{ + private TracerProviderInterface $tracerProvider; + private MeterProviderInterface $meterProvider; + private LoggerProviderInterface $loggerProvider; + private TextMapPropagatorInterface $propagator; + + public function __construct( + TracerProviderInterface $tracerProvider, + MeterProviderInterface $meterProvider, + LoggerProviderInterface $loggerProvider, + TextMapPropagatorInterface $propagator + ) { + $this->tracerProvider = $tracerProvider; + $this->meterProvider = $meterProvider; + $this->loggerProvider = $loggerProvider; + $this->propagator = $propagator; + } + + public static function isDisabled(): bool + { + return Configuration::getBoolean(Variables::OTEL_SDK_DISABLED); + } + + /** + * Tests whether an auto-instrumentation package has been disabled by config + */ + public static function isInstrumentationDisabled(string $name): bool + { + return in_array($name, Configuration::getList(Variables::OTEL_PHP_DISABLED_INSTRUMENTATIONS)); + } + + public static function builder(): SdkBuilder + { + return new SdkBuilder(); + } + + public function getTracerProvider(): TracerProviderInterface + { + return $this->tracerProvider; + } + + public function getMeterProvider(): MeterProviderInterface + { + return $this->meterProvider; + } + + public function getLoggerProvider(): LoggerProviderInterface + { + return $this->loggerProvider; + } + + public function getPropagator(): TextMapPropagatorInterface + { + return $this->propagator; + } +} diff --git a/vendor/open-telemetry/sdk/SdkAutoloader.php b/vendor/open-telemetry/sdk/SdkAutoloader.php new file mode 100644 index 000000000..c08195e19 --- /dev/null +++ b/vendor/open-telemetry/sdk/SdkAutoloader.php @@ -0,0 +1,76 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK; + +use InvalidArgumentException; +use OpenTelemetry\API\Globals; +use OpenTelemetry\API\Instrumentation\Configurator; +use OpenTelemetry\SDK\Common\Configuration\Configuration; +use OpenTelemetry\SDK\Common\Configuration\Variables; +use OpenTelemetry\SDK\Common\Util\ShutdownHandler; +use OpenTelemetry\SDK\Logs\LoggerProviderFactory; +use OpenTelemetry\SDK\Metrics\MeterProviderFactory; +use OpenTelemetry\SDK\Propagation\PropagatorFactory; +use OpenTelemetry\SDK\Trace\ExporterFactory; +use OpenTelemetry\SDK\Trace\SamplerFactory; +use OpenTelemetry\SDK\Trace\SpanProcessorFactory; +use OpenTelemetry\SDK\Trace\TracerProviderBuilder; + +class SdkAutoloader +{ + private static ?bool $enabled = null; + + public static function autoload(): bool + { + try { + self::$enabled ??= Configuration::getBoolean(Variables::OTEL_PHP_AUTOLOAD_ENABLED); + } catch (InvalidArgumentException $e) { + //invalid setting, assume false + self::$enabled = false; + } + if (!self::$enabled) { + return false; + } + Globals::registerInitializer(function (Configurator $configurator) { + $propagator = (new PropagatorFactory())->create(); + if (Sdk::isDisabled()) { + //@see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/configuration/sdk-environment-variables.md#general-sdk-configuration + return $configurator->withPropagator($propagator); + } + $emitMetrics = Configuration::getBoolean(Variables::OTEL_PHP_INTERNAL_METRICS_ENABLED); + + $exporter = (new ExporterFactory())->create(); + $meterProvider = (new MeterProviderFactory())->create(); + $spanProcessor = (new SpanProcessorFactory())->create($exporter, $emitMetrics ? $meterProvider : null); + $tracerProvider = (new TracerProviderBuilder()) + ->addSpanProcessor($spanProcessor) + ->setSampler((new SamplerFactory())->create()) + ->build(); + + $loggerProvider = (new LoggerProviderFactory())->create($emitMetrics ? $meterProvider : null); + + ShutdownHandler::register([$tracerProvider, 'shutdown']); + ShutdownHandler::register([$meterProvider, 'shutdown']); + ShutdownHandler::register([$loggerProvider, 'shutdown']); + + return $configurator + ->withTracerProvider($tracerProvider) + ->withMeterProvider($meterProvider) + ->withLoggerProvider($loggerProvider) + ->withPropagator($propagator) + ; + }); + + return true; + } + + /** + * @internal + */ + public static function reset(): void + { + self::$enabled = null; + } +} diff --git a/vendor/open-telemetry/sdk/SdkBuilder.php b/vendor/open-telemetry/sdk/SdkBuilder.php new file mode 100644 index 000000000..2090c4731 --- /dev/null +++ b/vendor/open-telemetry/sdk/SdkBuilder.php @@ -0,0 +1,98 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\SDK; + +use OpenTelemetry\API\Instrumentation\Configurator; +use OpenTelemetry\Context\Context; +use OpenTelemetry\Context\Propagation\NoopTextMapPropagator; +use OpenTelemetry\Context\Propagation\TextMapPropagatorInterface; +use OpenTelemetry\Context\ScopeInterface; +use OpenTelemetry\SDK\Common\Util\ShutdownHandler; +use OpenTelemetry\SDK\Logs\LoggerProviderInterface; +use OpenTelemetry\SDK\Logs\NoopLoggerProvider; +use OpenTelemetry\SDK\Metrics\MeterProviderInterface; +use OpenTelemetry\SDK\Metrics\NoopMeterProvider; +use OpenTelemetry\SDK\Trace\NoopTracerProvider; +use OpenTelemetry\SDK\Trace\TracerProviderInterface; + +class SdkBuilder +{ + private ?TracerProviderInterface $tracerProvider = null; + private ?MeterProviderInterface $meterProvider = null; + private ?LoggerProviderInterface $loggerProvider = null; + private ?TextMapPropagatorInterface $propagator = null; + private bool $autoShutdown = false; + + /** + * Automatically shut down providers on process completion. If not set, the user is responsible for calling `shutdown`. + */ + public function setAutoShutdown(bool $shutdown): self + { + $this->autoShutdown = $shutdown; + + return $this; + } + + public function setTracerProvider(TracerProviderInterface $provider): self + { + $this->tracerProvider = $provider; + + return $this; + } + + public function setMeterProvider(MeterProviderInterface $meterProvider): self + { + $this->meterProvider = $meterProvider; + + return $this; + } + + public function setLoggerProvider(LoggerProviderInterface $loggerProvider): self + { + $this->loggerProvider = $loggerProvider; + + return $this; + } + + public function setPropagator(TextMapPropagatorInterface $propagator): self + { + $this->propagator = $propagator; + + return $this; + } + + public function build(): Sdk + { + $tracerProvider = $this->tracerProvider ?? new NoopTracerProvider(); + $meterProvider = $this->meterProvider ?? new NoopMeterProvider(); + $loggerProvider = $this->loggerProvider ?? new NoopLoggerProvider(); + if ($this->autoShutdown) { + // rector rule disabled in config, because ShutdownHandler::register() does not keep a strong reference to $this + ShutdownHandler::register([$tracerProvider, 'shutdown']); + ShutdownHandler::register([$meterProvider, 'shutdown']); + ShutdownHandler::register([$loggerProvider, 'shutdown']); + } + + return new Sdk( + $tracerProvider, + $meterProvider, + $loggerProvider, + $this->propagator ?? NoopTextMapPropagator::getInstance(), + ); + } + + public function buildAndRegisterGlobal(): ScopeInterface + { + $sdk = $this->build(); + $context = Configurator::create() + ->withPropagator($sdk->getPropagator()) + ->withTracerProvider($sdk->getTracerProvider()) + ->withMeterProvider($sdk->getMeterProvider()) + ->withLoggerProvider($sdk->getLoggerProvider()) + ->storeInContext(); + + return Context::storage()->attach($context); + } +} 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)); + } +} diff --git a/vendor/open-telemetry/sdk/_autoload.php b/vendor/open-telemetry/sdk/_autoload.php new file mode 100644 index 000000000..4e1de3450 --- /dev/null +++ b/vendor/open-telemetry/sdk/_autoload.php @@ -0,0 +1,5 @@ +<?php + +declare(strict_types=1); + +\OpenTelemetry\SDK\SdkAutoloader::autoload(); diff --git a/vendor/open-telemetry/sdk/composer.json b/vendor/open-telemetry/sdk/composer.json new file mode 100644 index 000000000..4497c9400 --- /dev/null +++ b/vendor/open-telemetry/sdk/composer.json @@ -0,0 +1,59 @@ +{ + "name": "open-telemetry/sdk", + "description": "SDK for OpenTelemetry PHP.", + "keywords": ["opentelemetry", "otel", "metrics", "tracing", "logging", "apm", "sdk"], + "type": "library", + "support": { + "issues": "https://github.com/open-telemetry/opentelemetry-php/issues", + "source": "https://github.com/open-telemetry/opentelemetry-php", + "docs": "https://opentelemetry.io/docs/php", + "chat": "https://app.slack.com/client/T08PSQ7BQ/C01NFPCV44V" + }, + "license": "Apache-2.0", + "authors": [ + { + "name": "opentelemetry-php contributors", + "homepage": "https://github.com/open-telemetry/opentelemetry-php/graphs/contributors" + } + ], + "require": { + "php": "^7.4 || ^8.0", + "ext-json": "*", + "open-telemetry/api": "^1.0", + "open-telemetry/context": "^1.0", + "open-telemetry/sem-conv": "^1.0", + "php-http/discovery": "^1.14", + "psr/http-client-implementation": "^1.0", + "psr/http-factory-implementation": "^1.0", + "psr/http-client": "^1.0", + "psr/http-message": "^1.0.1|^2.0", + "psr/log": "^1.1|^2.0|^3.0", + "symfony/polyfill-mbstring": "^1.23", + "symfony/polyfill-php80": "^1.26", + "symfony/polyfill-php81": "^1.26", + "symfony/polyfill-php82": "^1.26" + }, + "autoload": { + "psr-4": { + "OpenTelemetry\\SDK\\": "." + }, + "files": [ + "Common/Util/functions.php", + "Logs/Exporter/_register.php", + "Metrics/MetricExporter/_register.php", + "Propagation/_register.php", + "Trace/SpanExporter/_register.php", + "Common/Dev/Compatibility/_load.php", + "_autoload.php" + ] + }, + "suggest": { + "ext-gmp": "To support unlimited number of synchronous metric readers", + "ext-mbstring": "To increase performance of string operations" + }, + "extra": { + "branch-alias": { + "dev-main": "1.0.x-dev" + } + } +} |