diff options
Diffstat (limited to 'vendor/open-telemetry/api')
78 files changed, 3556 insertions, 0 deletions
diff --git a/vendor/open-telemetry/api/Baggage/Baggage.php b/vendor/open-telemetry/api/Baggage/Baggage.php new file mode 100644 index 000000000..06c701605 --- /dev/null +++ b/vendor/open-telemetry/api/Baggage/Baggage.php @@ -0,0 +1,100 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\API\Baggage; + +use OpenTelemetry\Context\Context; +use OpenTelemetry\Context\ContextInterface; +use OpenTelemetry\Context\ContextKeys; +use OpenTelemetry\Context\ScopeInterface; + +final class Baggage implements BaggageInterface +{ + private static ?self $emptyBaggage = null; + + /** @inheritDoc */ + public static function fromContext(ContextInterface $context): BaggageInterface + { + return $context->get(ContextKeys::baggage()) ?? self::getEmpty(); + } + + /** @inheritDoc */ + public static function getBuilder(): BaggageBuilderInterface + { + return new BaggageBuilder(); + } + + /** @inheritDoc */ + public static function getCurrent(): BaggageInterface + { + return self::fromContext(Context::getCurrent()); + } + + /** @inheritDoc */ + public static function getEmpty(): BaggageInterface + { + if (null === self::$emptyBaggage) { + self::$emptyBaggage = new self(); + } + + return self::$emptyBaggage; + } + + /** @var array<string, Entry> */ + private array $entries; + + /** @param array<string, Entry> $entries */ + public function __construct(array $entries = []) + { + $this->entries = $entries; + } + + /** @inheritDoc */ + public function activate(): ScopeInterface + { + return Context::getCurrent()->withContextValue($this)->activate(); + } + + /** @inheritDoc */ + public function getEntry(string $key): ?Entry + { + return $this->entries[$key] ?? null; + } + + /** @inheritDoc */ + public function getValue(string $key) + { + if (($entry = $this->getEntry($key)) !== null) { + return $entry->getValue(); + } + + return null; + } + + /** @inheritDoc */ + public function getAll(): iterable + { + foreach ($this->entries as $key => $entry) { + yield $key => $entry; + } + } + + /** @inheritDoc */ + public function isEmpty(): bool + { + return $this->entries === []; + } + + /** @inheritDoc */ + public function toBuilder(): BaggageBuilderInterface + { + return new BaggageBuilder($this->entries); + } + + /** @inheritDoc */ + public function storeInContext(ContextInterface $context): ContextInterface + { + return $context->with(ContextKeys::baggage(), $this); + } +} diff --git a/vendor/open-telemetry/api/Baggage/BaggageBuilder.php b/vendor/open-telemetry/api/Baggage/BaggageBuilder.php new file mode 100644 index 000000000..d4500eac5 --- /dev/null +++ b/vendor/open-telemetry/api/Baggage/BaggageBuilder.php @@ -0,0 +1,40 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\API\Baggage; + +final class BaggageBuilder implements BaggageBuilderInterface +{ + /** @var array<string, Entry> */ + private array $entries; + + /** @param array<string, Entry> $entries */ + public function __construct(array $entries = []) + { + $this->entries = $entries; + } + + /** @inheritDoc */ + public function remove(string $key): BaggageBuilderInterface + { + unset($this->entries[$key]); + + return $this; + } + + /** @inheritDoc */ + public function set(string $key, $value, MetadataInterface $metadata = null): BaggageBuilderInterface + { + $metadata ??= Metadata::getEmpty(); + + $this->entries[$key] = new Entry($value, $metadata); + + return $this; + } + + public function build(): BaggageInterface + { + return new Baggage($this->entries); + } +} diff --git a/vendor/open-telemetry/api/Baggage/BaggageBuilderInterface.php b/vendor/open-telemetry/api/Baggage/BaggageBuilderInterface.php new file mode 100644 index 000000000..301cfbc3c --- /dev/null +++ b/vendor/open-telemetry/api/Baggage/BaggageBuilderInterface.php @@ -0,0 +1,23 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\API\Baggage; + +use OpenTelemetry\API\Baggage as API; + +interface BaggageBuilderInterface +{ + /** + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/v1.6.1/specification/baggage/api.md#set-value + * @param mixed $value + */ + public function set(string $key, $value, API\MetadataInterface $metadata = null): API\BaggageBuilderInterface; + + /** + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/v1.6.1/specification/baggage/api.md#remove-value + */ + public function remove(string $key): API\BaggageBuilderInterface; + + public function build(): API\BaggageInterface; +} diff --git a/vendor/open-telemetry/api/Baggage/BaggageInterface.php b/vendor/open-telemetry/api/Baggage/BaggageInterface.php new file mode 100644 index 000000000..83f45755d --- /dev/null +++ b/vendor/open-telemetry/api/Baggage/BaggageInterface.php @@ -0,0 +1,62 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\API\Baggage; + +use OpenTelemetry\API\Baggage as API; +use OpenTelemetry\Context\ContextInterface; +use OpenTelemetry\Context\ImplicitContextKeyedInterface; + +/** + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/v1.6.1/specification/baggage/api.md#operations + */ +interface BaggageInterface extends ImplicitContextKeyedInterface +{ + /** + * Returns the {@see API\BaggageInterface} from the provided *$context*, + * falling back on {@see API\BaggageInterface::getEmpty()} if there is no baggage in the provided context. + */ + public static function fromContext(ContextInterface $context): API\BaggageInterface; + + /** + * Returns a new empty {@see API\BaggageBuilderInterface}. + */ + public static function getBuilder(): API\BaggageBuilderInterface; + + /** + * Returns the current {@see Baggage} from the current {@see ContextInterface}, + * falling back on {@see API\BaggageInterface::getEmpty()} if there is no baggage in the current context. + */ + public static function getCurrent(): API\BaggageInterface; + + /** + * Returns a new {@see API\BaggageInterface} with no entries. + */ + public static function getEmpty(): API\BaggageInterface; + + /** + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/v1.6.1/specification/baggage/api.md#get-value + */ + public function getEntry(string $key): ?API\Entry; + + /** + * Returns the value from the {@see API\Entry} with the provided *key*. + * @see getEntry + * + * @return mixed + */ + public function getValue(string $key); + + /** + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/v1.6.1/specification/baggage/api.md#get-all-values + */ + public function getAll(): iterable; + + public function isEmpty(): bool; + + /** + * Returns a new {@see API\BaggageBuilderInterface} pre-initialized with the contents of `$this`. + */ + public function toBuilder(): API\BaggageBuilderInterface; +} diff --git a/vendor/open-telemetry/api/Baggage/Entry.php b/vendor/open-telemetry/api/Baggage/Entry.php new file mode 100644 index 000000000..eb3d0de5b --- /dev/null +++ b/vendor/open-telemetry/api/Baggage/Entry.php @@ -0,0 +1,38 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\API\Baggage; + +final class Entry +{ + /** @var mixed */ + private $value; + + private MetadataInterface $metadata; + + /** + * @param mixed $value + * @param MetadataInterface $metadata + */ + public function __construct( + $value, + MetadataInterface $metadata + ) { + $this->value = $value; + $this->metadata = $metadata; + } + + /** + * @return mixed + */ + public function getValue() + { + return $this->value; + } + + public function getMetadata(): MetadataInterface + { + return $this->metadata; + } +} diff --git a/vendor/open-telemetry/api/Baggage/Metadata.php b/vendor/open-telemetry/api/Baggage/Metadata.php new file mode 100644 index 000000000..043c96a8a --- /dev/null +++ b/vendor/open-telemetry/api/Baggage/Metadata.php @@ -0,0 +1,27 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\API\Baggage; + +final class Metadata implements MetadataInterface +{ + private static ?self $instance = null; + + public static function getEmpty(): Metadata + { + return self::$instance ??= new self(''); + } + + private string $metadata; + + public function __construct(string $metadata) + { + $this->metadata = $metadata; + } + + public function getValue(): string + { + return $this->metadata; + } +} diff --git a/vendor/open-telemetry/api/Baggage/MetadataInterface.php b/vendor/open-telemetry/api/Baggage/MetadataInterface.php new file mode 100644 index 000000000..cd0a6d1ec --- /dev/null +++ b/vendor/open-telemetry/api/Baggage/MetadataInterface.php @@ -0,0 +1,13 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\API\Baggage; + +/** + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/v1.6.1/specification/baggage/api.md#set-value + */ +interface MetadataInterface +{ + public function getValue(): string; +} diff --git a/vendor/open-telemetry/api/Baggage/Propagation/BaggagePropagator.php b/vendor/open-telemetry/api/Baggage/Propagation/BaggagePropagator.php new file mode 100644 index 000000000..fae62dcab --- /dev/null +++ b/vendor/open-telemetry/api/Baggage/Propagation/BaggagePropagator.php @@ -0,0 +1,92 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\API\Baggage\Propagation; + +use OpenTelemetry\API\Baggage\Baggage; +use OpenTelemetry\API\Baggage\BaggageBuilderInterface; +use OpenTelemetry\API\Baggage\Entry; /** @phan-suppress-current-line PhanUnreferencedUseNormal */ +use OpenTelemetry\Context\Context; +use OpenTelemetry\Context\ContextInterface; +use OpenTelemetry\Context\Propagation\ArrayAccessGetterSetter; +use OpenTelemetry\Context\Propagation\PropagationGetterInterface; +use OpenTelemetry\Context\Propagation\PropagationSetterInterface; +use OpenTelemetry\Context\Propagation\TextMapPropagatorInterface; +use function rtrim; +use function urlencode; + +/** + * @see https://www.w3.org/TR/baggage + */ +final class BaggagePropagator implements TextMapPropagatorInterface +{ + public const BAGGAGE = 'baggage'; + + private static ?self $instance = null; + + public static function getInstance(): self + { + if (null === self::$instance) { + self::$instance = new self(); + } + + return self::$instance; + } + + public function fields(): array + { + return [self::BAGGAGE]; + } + + public function inject(&$carrier, PropagationSetterInterface $setter = null, ContextInterface $context = null): void + { + $setter ??= ArrayAccessGetterSetter::getInstance(); + $context ??= Context::getCurrent(); + + $baggage = Baggage::fromContext($context); + + if ($baggage->isEmpty()) { + return; + } + + $headerString = ''; + + /** @var Entry $entry */ + foreach ($baggage->getAll() as $key => $entry) { + $value = urlencode($entry->getValue()); + $headerString.= "{$key}={$value}"; + + if (($metadata = $entry->getMetadata()->getValue()) !== '' && ($metadata = $entry->getMetadata()->getValue()) !== '0') { + $headerString .= ";{$metadata}"; + } + + $headerString .= ','; + } + + if ($headerString !== '' && $headerString !== '0') { + $headerString = rtrim($headerString, ','); + $setter->set($carrier, self::BAGGAGE, $headerString); + } + } + + public function extract($carrier, PropagationGetterInterface $getter = null, ContextInterface $context = null): ContextInterface + { + $getter ??= ArrayAccessGetterSetter::getInstance(); + $context ??= Context::getCurrent(); + + if (!$baggageHeader = $getter->get($carrier, self::BAGGAGE)) { + return $context; + } + + $baggageBuilder = Baggage::getBuilder(); + $this->extractValue($baggageHeader, $baggageBuilder); + + return $context->withContextValue($baggageBuilder->build()); + } + + private function extractValue(string $baggageHeader, BaggageBuilderInterface $baggageBuilder): void + { + (new Parser($baggageHeader))->parseInto($baggageBuilder); + } +} diff --git a/vendor/open-telemetry/api/Baggage/Propagation/Parser.php b/vendor/open-telemetry/api/Baggage/Propagation/Parser.php new file mode 100644 index 000000000..3518b858d --- /dev/null +++ b/vendor/open-telemetry/api/Baggage/Propagation/Parser.php @@ -0,0 +1,69 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\API\Baggage\Propagation; + +use function explode; +use OpenTelemetry\API\Baggage\BaggageBuilderInterface; +use OpenTelemetry\API\Baggage\Metadata; +use function str_replace; +use function trim; +use function urldecode; + +final class Parser +{ + private const EXCLUDED_KEY_CHARS = [' ', '(', ')', '<', '>', '@', ',', ';', ':', '\\', '"', '/', '[', ']', '?', '=', '{', '}']; + private const EXCLUDED_VALUE_CHARS = [' ', '"', ',', ';', '\\']; + private const EQUALS = '='; + + /** @readonly */ + private string $baggageHeader; + + public function __construct(string $baggageHeader) + { + $this->baggageHeader = $baggageHeader; + } + + public function parseInto(BaggageBuilderInterface $baggageBuilder): void + { + foreach (explode(',', $this->baggageHeader) as $baggageString) { + if (empty(trim($baggageString))) { + continue; + } + + $explodedString = explode(';', $baggageString, 2); + + $keyValue = trim($explodedString[0]); + + if (empty($keyValue) || mb_strpos($keyValue, self::EQUALS) === false) { + continue; + } + + $metadataString = $explodedString[1] ?? null; + + if ($metadataString && !empty(trim(($metadataString)))) { + $metadata = new Metadata(trim($metadataString)); + } else { + $metadata = null; + } + + [$key, $value] = explode(self::EQUALS, $keyValue, 2); + + $key = urldecode($key); + $value = urldecode($value); + + $key = str_replace(self::EXCLUDED_KEY_CHARS, '', trim($key), $invalidKeyCharacters); + if (empty($key) || $invalidKeyCharacters > 0) { + continue; + } + + $value = str_replace(self::EXCLUDED_VALUE_CHARS, '', trim($value), $invalidValueCharacters); + if (empty($value) || $invalidValueCharacters > 0) { + continue; + } + + $baggageBuilder->set($key, $value, $metadata); + } + } +} diff --git a/vendor/open-telemetry/api/Behavior/Internal/LogWriter/ErrorLogWriter.php b/vendor/open-telemetry/api/Behavior/Internal/LogWriter/ErrorLogWriter.php new file mode 100644 index 000000000..1b9f785aa --- /dev/null +++ b/vendor/open-telemetry/api/Behavior/Internal/LogWriter/ErrorLogWriter.php @@ -0,0 +1,13 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\API\Behavior\Internal\LogWriter; + +class ErrorLogWriter implements LogWriterInterface +{ + public function write($level, string $message, array $context): void + { + error_log(Formatter::format($level, $message, $context)); + } +} diff --git a/vendor/open-telemetry/api/Behavior/Internal/LogWriter/Formatter.php b/vendor/open-telemetry/api/Behavior/Internal/LogWriter/Formatter.php new file mode 100644 index 000000000..4cfd6f9d4 --- /dev/null +++ b/vendor/open-telemetry/api/Behavior/Internal/LogWriter/Formatter.php @@ -0,0 +1,37 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\API\Behavior\Internal\LogWriter; + +class Formatter +{ + public static function format($level, string $message, array $context): string + { + $exception = (array_key_exists('exception', $context) && $context['exception'] instanceof \Throwable) + ? $context['exception'] + : null; + if ($exception) { + $message = sprintf( + 'OpenTelemetry: [%s] %s [exception] %s%s%s', + $level, + $message, + $exception->getMessage(), + PHP_EOL, + $exception->getTraceAsString() + ); + } else { + //get calling location, skipping over trait, formatter etc + $caller = debug_backtrace()[3]; + $message = sprintf( + 'OpenTelemetry: [%s] %s in %s(%s)', + $level, + $message, + $caller['file'], + $caller['line'], + ); + } + + return $message; + } +} diff --git a/vendor/open-telemetry/api/Behavior/Internal/LogWriter/LogWriterInterface.php b/vendor/open-telemetry/api/Behavior/Internal/LogWriter/LogWriterInterface.php new file mode 100644 index 000000000..046d21fc9 --- /dev/null +++ b/vendor/open-telemetry/api/Behavior/Internal/LogWriter/LogWriterInterface.php @@ -0,0 +1,10 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\API\Behavior\Internal\LogWriter; + +interface LogWriterInterface +{ + public function write($level, string $message, array $context): void; +} diff --git a/vendor/open-telemetry/api/Behavior/Internal/LogWriter/NoopLogWriter.php b/vendor/open-telemetry/api/Behavior/Internal/LogWriter/NoopLogWriter.php new file mode 100644 index 000000000..f7529c082 --- /dev/null +++ b/vendor/open-telemetry/api/Behavior/Internal/LogWriter/NoopLogWriter.php @@ -0,0 +1,13 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\API\Behavior\Internal\LogWriter; + +class NoopLogWriter implements LogWriterInterface +{ + public function write($level, string $message, array $context): void + { + //do nothing + } +} diff --git a/vendor/open-telemetry/api/Behavior/Internal/LogWriter/Psr3LogWriter.php b/vendor/open-telemetry/api/Behavior/Internal/LogWriter/Psr3LogWriter.php new file mode 100644 index 000000000..5b2d19c15 --- /dev/null +++ b/vendor/open-telemetry/api/Behavior/Internal/LogWriter/Psr3LogWriter.php @@ -0,0 +1,22 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\API\Behavior\Internal\LogWriter; + +use Psr\Log\LoggerInterface; + +class Psr3LogWriter implements LogWriterInterface +{ + private LoggerInterface $logger; + + public function __construct(LoggerInterface $logger) + { + $this->logger = $logger; + } + + public function write($level, string $message, array $context): void + { + $this->logger->log($level, $message, $context); + } +} diff --git a/vendor/open-telemetry/api/Behavior/Internal/LogWriter/StreamLogWriter.php b/vendor/open-telemetry/api/Behavior/Internal/LogWriter/StreamLogWriter.php new file mode 100644 index 000000000..f65f1e856 --- /dev/null +++ b/vendor/open-telemetry/api/Behavior/Internal/LogWriter/StreamLogWriter.php @@ -0,0 +1,25 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\API\Behavior\Internal\LogWriter; + +class StreamLogWriter implements LogWriterInterface +{ + private $stream; + + public function __construct(string $destination) + { + $stream = fopen($destination, 'a'); + if ($stream) { + $this->stream = $stream; + } else { + throw new \RuntimeException(sprintf('Unable to open %s for writing', $destination)); + } + } + + public function write($level, string $message, array $context): void + { + fwrite($this->stream, Formatter::format($level, $message, $context)); + } +} diff --git a/vendor/open-telemetry/api/Behavior/Internal/LogWriterFactory.php b/vendor/open-telemetry/api/Behavior/Internal/LogWriterFactory.php new file mode 100644 index 000000000..07c48cea5 --- /dev/null +++ b/vendor/open-telemetry/api/Behavior/Internal/LogWriterFactory.php @@ -0,0 +1,48 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\API\Behavior\Internal; + +use OpenTelemetry\API\Behavior\Internal\LogWriter\ErrorLogWriter; +use OpenTelemetry\API\Behavior\Internal\LogWriter\LogWriterInterface; +use OpenTelemetry\API\Behavior\Internal\LogWriter\NoopLogWriter; +use OpenTelemetry\API\Behavior\Internal\LogWriter\Psr3LogWriter; +use OpenTelemetry\API\Behavior\Internal\LogWriter\StreamLogWriter; +use OpenTelemetry\API\Instrumentation\ConfigurationResolver; +use OpenTelemetry\API\LoggerHolder; + +class LogWriterFactory +{ + private const OTEL_PHP_LOG_DESTINATION = 'OTEL_PHP_LOG_DESTINATION'; + + public function create(): LogWriterInterface + { + $dest = (new ConfigurationResolver())->getString(self::OTEL_PHP_LOG_DESTINATION); + $logger = LoggerHolder::get(); + + switch ($dest) { + case 'none': + return new NoopLogWriter(); + case 'stderr': + return new StreamLogWriter('php://stderr'); + case 'stdout': + return new StreamLogWriter('php://stdout'); + case 'psr3': + if ($logger) { + return new Psr3LogWriter($logger); + } + error_log('OpenTelemetry: cannot use OTEL_PHP_LOG_DESTINATION=psr3 without providing a PSR-3 logger'); + //default to error log + return new ErrorLogWriter(); + case 'error_log': + return new ErrorLogWriter(); + default: + if ($logger) { + return new Psr3LogWriter($logger); + } + + return new ErrorLogWriter(); + } + } +} diff --git a/vendor/open-telemetry/api/Behavior/Internal/Logging.php b/vendor/open-telemetry/api/Behavior/Internal/Logging.php new file mode 100644 index 000000000..e5bec7ab5 --- /dev/null +++ b/vendor/open-telemetry/api/Behavior/Internal/Logging.php @@ -0,0 +1,90 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\API\Behavior\Internal; + +use OpenTelemetry\API\Behavior\Internal\LogWriter\LogWriterInterface; +use Psr\Log\LogLevel; + +/** + * Logging utility functions for internal logging (of OpenTelemetry errors/warnings etc). + * This is not part of SDK configuration to avoid creating a dependency on SDK from any package which does logging. + * @todo this should be `@internal`, but deptrac is not happy with that. + */ +class Logging +{ + private const OTEL_LOG_LEVEL = 'OTEL_LOG_LEVEL'; + private const DEFAULT_LEVEL = LogLevel::INFO; + private const NONE = 'none'; + private const LEVELS = [ + LogLevel::DEBUG, + LogLevel::INFO, + LogLevel::NOTICE, + LogLevel::WARNING, + LogLevel::ERROR, + LogLevel::CRITICAL, + LogLevel::ALERT, + LogLevel::EMERGENCY, + self::NONE, //highest priority so that nothing is logged + ]; + + /** + * The minimum log level. Messages with lower severity than this will be ignored. + */ + private static ?int $logLevel = null; + private static ?LogWriterInterface $writer = null; + + public static function setLogWriter(LogWriterInterface $writer): void + { + self::$writer = $writer; + } + + public static function logWriter(): LogWriterInterface + { + self::$writer ??= (new LogWriterFactory())->create(); + + return self::$writer; + } + + /** + * Get level priority from level name + */ + public static function level(string $level): int + { + $value = array_search($level, self::LEVELS); + + return $value ?: 1; //'info' + } + + /** + * Get defined OTEL_LOG_LEVEL, or default + */ + public static function logLevel(): int + { + self::$logLevel ??= self::getLogLevel(); + + return self::$logLevel; + } + + private static function getLogLevel(): int + { + $level = array_key_exists(self::OTEL_LOG_LEVEL, $_SERVER) + ? $_SERVER[self::OTEL_LOG_LEVEL] + : getenv(self::OTEL_LOG_LEVEL); + if (!$level) { + $level = ini_get(self::OTEL_LOG_LEVEL); + } + if (!$level) { + $level = self::DEFAULT_LEVEL; + } + + return self::level($level); + } + + public static function reset(): void + { + self::$logLevel = null; + self::$writer = null; + } +} diff --git a/vendor/open-telemetry/api/Behavior/LogsMessagesTrait.php b/vendor/open-telemetry/api/Behavior/LogsMessagesTrait.php new file mode 100644 index 000000000..d0207e4b1 --- /dev/null +++ b/vendor/open-telemetry/api/Behavior/LogsMessagesTrait.php @@ -0,0 +1,50 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\API\Behavior; + +use OpenTelemetry\API\Behavior\Internal\Logging; +use Psr\Log\LogLevel; + +trait LogsMessagesTrait +{ + private static function shouldLog(string $level): bool + { + return Logging::level($level) >= Logging::logLevel(); + } + + private static function doLog(string $level, string $message, array $context): void + { + $writer = Logging::logWriter(); + if (self::shouldLog($level)) { + $context['source'] = get_called_class(); + $writer->write($level, $message, $context); + } + } + + protected static function logDebug(string $message, array $context = []): void + { + self::doLog(LogLevel::DEBUG, $message, $context); + } + + protected static function logInfo(string $message, array $context = []): void + { + self::doLog(LogLevel::INFO, $message, $context); + } + + protected static function logNotice(string $message, array $context = []): void + { + self::doLog(LogLevel::NOTICE, $message, $context); + } + + protected static function logWarning(string $message, array $context = []): void + { + self::doLog(LogLevel::WARNING, $message, $context); + } + + protected static function logError(string $message, array $context = []): void + { + self::doLog(LogLevel::ERROR, $message, $context); + } +} diff --git a/vendor/open-telemetry/api/Globals.php b/vendor/open-telemetry/api/Globals.php new file mode 100644 index 000000000..8f04b0b42 --- /dev/null +++ b/vendor/open-telemetry/api/Globals.php @@ -0,0 +1,121 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\API; + +use function assert; +use Closure; +use const E_USER_WARNING; +use OpenTelemetry\API\Instrumentation\Configurator; +use OpenTelemetry\API\Instrumentation\ContextKeys; +use OpenTelemetry\API\Logs\LoggerProviderInterface; +use OpenTelemetry\API\Metrics\MeterProviderInterface; +use OpenTelemetry\API\Trace\TracerProviderInterface; +use OpenTelemetry\Context\Context; +use OpenTelemetry\Context\Propagation\TextMapPropagatorInterface; +use function sprintf; +use Throwable; +use function trigger_error; + +/** + * Provides access to the globally configured instrumentation instances. + */ +final class Globals +{ + /** @var Closure[] */ + private static array $initializers = []; + private static ?self $globals = null; + + private TracerProviderInterface $tracerProvider; + private MeterProviderInterface $meterProvider; + private TextMapPropagatorInterface $propagator; + private LoggerProviderInterface $loggerProvider; + + 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 tracerProvider(): TracerProviderInterface + { + return Context::getCurrent()->get(ContextKeys::tracerProvider()) ?? self::globals()->tracerProvider; + } + + public static function meterProvider(): MeterProviderInterface + { + return Context::getCurrent()->get(ContextKeys::meterProvider()) ?? self::globals()->meterProvider; + } + + public static function propagator(): TextMapPropagatorInterface + { + return Context::getCurrent()->get(ContextKeys::propagator()) ?? self::globals()->propagator; + } + + public static function loggerProvider(): LoggerProviderInterface + { + return Context::getCurrent()->get(ContextKeys::loggerProvider()) ?? self::globals()->loggerProvider; + } + + /** + * @param Closure(Configurator): Configurator $initializer + * + * @interal + * @psalm-internal OpenTelemetry + */ + public static function registerInitializer(Closure $initializer): void + { + self::$initializers[] = $initializer; + } + + /** + * @phan-suppress PhanTypeMismatchReturnNullable + */ + private static function globals(): self + { + if (self::$globals !== null) { + return self::$globals; + } + + $configurator = Configurator::createNoop(); + $scope = $configurator->activate(); + + try { + foreach (self::$initializers as $initializer) { + try { + $configurator = $initializer($configurator); + } catch (Throwable $e) { + trigger_error(sprintf("Error during opentelemetry initialization: %s\n%s", $e->getMessage(), $e->getTraceAsString()), E_USER_WARNING); + } + } + } finally { + $scope->detach(); + } + + $context = $configurator->storeInContext(); + $tracerProvider = $context->get(ContextKeys::tracerProvider()); + $meterProvider = $context->get(ContextKeys::meterProvider()); + $propagator = $context->get(ContextKeys::propagator()); + $loggerProvider = $context->get(ContextKeys::loggerProvider()); + + assert(isset($tracerProvider, $meterProvider, $loggerProvider, $propagator)); + + return self::$globals = new self($tracerProvider, $meterProvider, $loggerProvider, $propagator); + } + + /** + * @internal + */ + public static function reset(): void + { + self::$globals = null; + self::$initializers = []; + } +} diff --git a/vendor/open-telemetry/api/Instrumentation/CachedInstrumentation.php b/vendor/open-telemetry/api/Instrumentation/CachedInstrumentation.php new file mode 100644 index 000000000..5ffb3950d --- /dev/null +++ b/vendor/open-telemetry/api/Instrumentation/CachedInstrumentation.php @@ -0,0 +1,97 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\API\Instrumentation; + +use ArrayAccess; +use function assert; +use function class_exists; +use OpenTelemetry\API\Globals; +use OpenTelemetry\API\Logs\LoggerInterface; +use OpenTelemetry\API\Logs\LoggerProviderInterface; +use OpenTelemetry\API\Metrics\MeterInterface; +use OpenTelemetry\API\Metrics\MeterProviderInterface; +use OpenTelemetry\API\Trace\TracerInterface; +use OpenTelemetry\API\Trace\TracerProviderInterface; +use const PHP_VERSION_ID; + +/** + * Provides access to cached {@link TracerInterface} and {@link MeterInterface} + * instances. + * + * Autoinstrumentation should prefer using a {@link CachedInstrumentation} + * instance over repeatedly obtaining instrumentation instances from + * {@link Globals}. + */ +final class CachedInstrumentation +{ + private string $name; + private ?string $version; + private ?string $schemaUrl; + private iterable $attributes; + /** @var ArrayAccess<TracerProviderInterface, TracerInterface>|null */ + private ?ArrayAccess $tracers; + /** @var ArrayAccess<MeterProviderInterface, MeterInterface>|null */ + private ?ArrayAccess $meters; + /** @var ArrayAccess<LoggerProviderInterface, LoggerInterface>|null */ + private ?ArrayAccess $loggers; + + public function __construct(string $name, ?string $version = null, ?string $schemaUrl = null, iterable $attributes = []) + { + $this->name = $name; + $this->version = $version; + $this->schemaUrl = $schemaUrl; + $this->attributes = $attributes; + $this->tracers = self::createWeakMap(); + $this->meters = self::createWeakMap(); + $this->loggers = self::createWeakMap(); + } + + private static function createWeakMap(): ?ArrayAccess + { + if (PHP_VERSION_ID < 80000) { + return null; + } + + /** @phan-suppress-next-line PhanUndeclaredClassReference */ + assert(class_exists(\WeakMap::class, false)); + /** @phan-suppress-next-line PhanUndeclaredClassMethod */ + $map = new \WeakMap(); + assert($map instanceof ArrayAccess); + + return $map; + } + + public function tracer(): TracerInterface + { + $tracerProvider = Globals::tracerProvider(); + + if ($this->tracers === null) { + return $tracerProvider->getTracer($this->name, $this->version, $this->schemaUrl, $this->attributes); + } + + return $this->tracers[$tracerProvider] ??= $tracerProvider->getTracer($this->name, $this->version, $this->schemaUrl, $this->attributes); + } + + public function meter(): MeterInterface + { + $meterProvider = Globals::meterProvider(); + + if ($this->meters === null) { + return $meterProvider->getMeter($this->name, $this->version, $this->schemaUrl, $this->attributes); + } + + return $this->meters[$meterProvider] ??= $meterProvider->getMeter($this->name, $this->version, $this->schemaUrl, $this->attributes); + } + public function logger(): LoggerInterface + { + $loggerProvider = Globals::loggerProvider(); + + if ($this->loggers === null) { + return $loggerProvider->getLogger($this->name, $this->version, $this->schemaUrl, $this->attributes); + } + + return $this->loggers[$loggerProvider] ??= $loggerProvider->getLogger($this->name, $this->version, $this->schemaUrl, $this->attributes); + } +} diff --git a/vendor/open-telemetry/api/Instrumentation/ConfigurationResolver.php b/vendor/open-telemetry/api/Instrumentation/ConfigurationResolver.php new file mode 100644 index 000000000..bb5619c30 --- /dev/null +++ b/vendor/open-telemetry/api/Instrumentation/ConfigurationResolver.php @@ -0,0 +1,77 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\API\Instrumentation; + +class ConfigurationResolver implements ConfigurationResolverInterface +{ + public function has(string $name): bool + { + return $this->getVariable($name) !== null; + } + + public function getString(string $name): ?string + { + return $this->getVariable($name); + } + + public function getBoolean(string $name): ?bool + { + $value = $this->getVariable($name); + if ($value === null) { + return null; + } + + return ($value === 'true'); + } + + public function getInt(string $name): ?int + { + $value = $this->getVariable($name); + if ($value === null) { + return null; + } + if (filter_var($value, FILTER_VALIDATE_INT) === false) { + //log warning + return null; + } + + return (int) $value; + } + + public function getList(string $name): array + { + $value = $this->getVariable($name); + if ($value === null) { + return []; + } + + return explode(',', $value); + } + + private function getVariable(string $name): ?string + { + $value = $_SERVER[$name] ?? null; + if ($value !== false && !self::isEmpty($value)) { + assert(is_string($value)); + + return $value; + } + $value = getenv($name); + if ($value !== false && !self::isEmpty($value)) { + return $value; + } + $value = ini_get($name); + if ($value !== false && !self::isEmpty($value)) { + return $value; + } + + return null; + } + + private static function isEmpty($value): bool + { + return $value === false || $value === null || $value === ''; + } +} diff --git a/vendor/open-telemetry/api/Instrumentation/ConfigurationResolverInterface.php b/vendor/open-telemetry/api/Instrumentation/ConfigurationResolverInterface.php new file mode 100644 index 000000000..79bd94047 --- /dev/null +++ b/vendor/open-telemetry/api/Instrumentation/ConfigurationResolverInterface.php @@ -0,0 +1,14 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\API\Instrumentation; + +interface ConfigurationResolverInterface +{ + public function has(string $name): bool; + public function getString(string $name): ?string; + public function getBoolean(string $name): ?bool; + public function getInt(string $name): ?int; + public function getList(string $name): array; +} diff --git a/vendor/open-telemetry/api/Instrumentation/Configurator.php b/vendor/open-telemetry/api/Instrumentation/Configurator.php new file mode 100644 index 000000000..71d301363 --- /dev/null +++ b/vendor/open-telemetry/api/Instrumentation/Configurator.php @@ -0,0 +1,113 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\API\Instrumentation; + +use OpenTelemetry\API\Logs\LoggerProviderInterface; +use OpenTelemetry\API\Logs\NoopLoggerProvider; +use OpenTelemetry\API\Metrics\MeterProviderInterface; +use OpenTelemetry\API\Metrics\Noop\NoopMeterProvider; +use OpenTelemetry\API\Trace\NoopTracerProvider; +use OpenTelemetry\API\Trace\TracerProviderInterface; +use OpenTelemetry\Context\Context; +use OpenTelemetry\Context\ContextInterface; +use OpenTelemetry\Context\ImplicitContextKeyedInterface; +use OpenTelemetry\Context\Propagation\NoopTextMapPropagator; +use OpenTelemetry\Context\Propagation\TextMapPropagatorInterface; +use OpenTelemetry\Context\ScopeInterface; + +/** + * Configures the global (context scoped) instrumentation instances. + * + * @see Configurator::activate() + */ +final class Configurator implements ImplicitContextKeyedInterface +{ + private ?TracerProviderInterface $tracerProvider = null; + private ?MeterProviderInterface $meterProvider = null; + private ?TextMapPropagatorInterface $propagator = null; + private ?LoggerProviderInterface $loggerProvider = null; + + private function __construct() + { + } + + /** + * Creates a configurator that uses parent instances for not configured values. + */ + public static function create(): Configurator + { + return new self(); + } + + /** + * Creates a configurator that uses noop instances for not configured values. + */ + public static function createNoop(): Configurator + { + return self::create() + ->withTracerProvider(new NoopTracerProvider()) + ->withMeterProvider(new NoopMeterProvider()) + ->withPropagator(new NoopTextMapPropagator()) + ->withLoggerProvider(new NoopLoggerProvider()) + ; + } + + public function activate(): ScopeInterface + { + return $this->storeInContext()->activate(); + } + + public function storeInContext(?ContextInterface $context = null): ContextInterface + { + $context ??= Context::getCurrent(); + + if ($this->tracerProvider !== null) { + $context = $context->with(ContextKeys::tracerProvider(), $this->tracerProvider); + } + if ($this->meterProvider !== null) { + $context = $context->with(ContextKeys::meterProvider(), $this->meterProvider); + } + if ($this->propagator !== null) { + $context = $context->with(ContextKeys::propagator(), $this->propagator); + } + if ($this->loggerProvider !== null) { + $context = $context->with(ContextKeys::loggerProvider(), $this->loggerProvider); + } + + return $context; + } + + public function withTracerProvider(?TracerProviderInterface $tracerProvider): Configurator + { + $self = clone $this; + $self->tracerProvider = $tracerProvider; + + return $self; + } + + public function withMeterProvider(?MeterProviderInterface $meterProvider): Configurator + { + $self = clone $this; + $self->meterProvider = $meterProvider; + + return $self; + } + + public function withPropagator(?TextMapPropagatorInterface $propagator): Configurator + { + $self = clone $this; + $self->propagator = $propagator; + + return $self; + } + + public function withLoggerProvider(?LoggerProviderInterface $loggerProvider): Configurator + { + $self = clone $this; + $self->loggerProvider = $loggerProvider; + + return $self; + } +} diff --git a/vendor/open-telemetry/api/Instrumentation/ContextKeys.php b/vendor/open-telemetry/api/Instrumentation/ContextKeys.php new file mode 100644 index 000000000..ea1a66416 --- /dev/null +++ b/vendor/open-telemetry/api/Instrumentation/ContextKeys.php @@ -0,0 +1,58 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\API\Instrumentation; + +use OpenTelemetry\API\Logs\LoggerProviderInterface; +use OpenTelemetry\API\Metrics\MeterProviderInterface; +use OpenTelemetry\API\Trace\TracerProviderInterface; +use OpenTelemetry\Context\Context; +use OpenTelemetry\Context\ContextKeyInterface; +use OpenTelemetry\Context\Propagation\TextMapPropagatorInterface; + +/** + * @internal + */ +final class ContextKeys +{ + /** + * @return ContextKeyInterface<TracerProviderInterface> + */ + public static function tracerProvider(): ContextKeyInterface + { + static $instance; + + return $instance ??= Context::createKey(TracerProviderInterface::class); + } + + /** + * @return ContextKeyInterface<MeterProviderInterface> + */ + public static function meterProvider(): ContextKeyInterface + { + static $instance; + + return $instance ??= Context::createKey(MeterProviderInterface::class); + } + + /** + * @return ContextKeyInterface<TextMapPropagatorInterface> + */ + public static function propagator(): ContextKeyInterface + { + static $instance; + + return $instance ??= Context::createKey(TextMapPropagatorInterface::class); + } + + /** + * @return ContextKeyInterface<LoggerProviderInterface> + */ + public static function loggerProvider(): ContextKeyInterface + { + static $instance; + + return $instance ??= Context::createKey(LoggerProviderInterface::class); + } +} diff --git a/vendor/open-telemetry/api/Instrumentation/InstrumentationInterface.php b/vendor/open-telemetry/api/Instrumentation/InstrumentationInterface.php new file mode 100644 index 000000000..d67bc8d6d --- /dev/null +++ b/vendor/open-telemetry/api/Instrumentation/InstrumentationInterface.php @@ -0,0 +1,43 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\API\Instrumentation; + +use OpenTelemetry\API\Metrics\MeterInterface; +use OpenTelemetry\API\Metrics\MeterProviderInterface; +use OpenTelemetry\API\Trace\TracerInterface; +use OpenTelemetry\API\Trace\TracerProviderInterface; +use OpenTelemetry\Context\Propagation\TextMapPropagatorInterface; +use Psr\Log\LoggerInterface; + +interface InstrumentationInterface +{ + public function getName(): string; + + public function getVersion(): ?string; + + public function getSchemaUrl(): ?string; + + public function init(): bool; + + public function activate(): bool; + + public function setPropagator(TextMapPropagatorInterface $propagator): void; + + public function getPropagator(): TextMapPropagatorInterface; + + public function setTracerProvider(TracerProviderInterface $tracerProvider): void; + + public function getTracerProvider(): TracerProviderInterface; + + public function getTracer(): TracerInterface; + + public function setMeterProvider(MeterProviderInterface $meterProvider): void; + + public function getMeter(): MeterInterface; + + public function setLogger(LoggerInterface $logger): void; + + public function getLogger(): LoggerInterface; +} diff --git a/vendor/open-telemetry/api/Instrumentation/InstrumentationTrait.php b/vendor/open-telemetry/api/Instrumentation/InstrumentationTrait.php new file mode 100644 index 000000000..1e695adb5 --- /dev/null +++ b/vendor/open-telemetry/api/Instrumentation/InstrumentationTrait.php @@ -0,0 +1,193 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\API\Instrumentation; + +use OpenTelemetry\API\Metrics\MeterInterface; +use OpenTelemetry\API\Metrics\MeterProviderInterface; +use OpenTelemetry\API\Metrics\Noop\NoopMeter; +use OpenTelemetry\API\Trace\NoopTracer; +use OpenTelemetry\API\Trace\NoopTracerProvider; +use OpenTelemetry\API\Trace\TracerInterface; +use OpenTelemetry\API\Trace\TracerProviderInterface; +use OpenTelemetry\Context\Propagation\NoopTextMapPropagator; +use OpenTelemetry\Context\Propagation\TextMapPropagatorInterface; +use Psr\Log\LoggerInterface; +use Psr\Log\NullLogger; +use RuntimeException; + +/** + This trait in conjunction with the InstrumentationInterface is meant as a base for instrumentations for the + OpenTelemetry API. + Instrumentations need to implement the abstract methods of this trait (besides any instrumentation specific code) + + A very simplified instrumentation could look like this: + +class Instrumentation implements InstrumentationInterface +{ + use InstrumentationTrait; + + public function getName(): string + { + return 'foo-instrumentation'; + } + + public function getVersion(): ?string + { + return '0.0.1'; + } + + public function getSchemaUrl(): ?string + { + return null; + } + + public function init(): bool + { + // This is just an example. In a real-world scenario one should only create spans in reaction of things + // happening in the instrumented code, not just for the sake of it. + $span = $this->getTracer()->spanBuilder($this->getName())->startSpan(); + // do stuff + $span->end(); + } +} + +An user of the instrumentation and API/SDK would the call: + +$instrumentation = new Instrumentation; +$instrumentation->activate() + +to activate and use the instrumentation with the API/SDK. + **/ + +trait InstrumentationTrait +{ + private TextMapPropagatorInterface $propagator; + private TracerProviderInterface $tracerProvider; + private TracerInterface $tracer; + private MeterInterface $meter; + private LoggerInterface $logger; + + public function __construct() + { + $this->initDefaults(); + } + + /** + * The name of the instrumenting/instrumented library/package/project. + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/v1.12.0/specification/glossary.md#instrumentation-scope + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/v1.12.0/specification/glossary.md#instrumentation-library + */ + abstract public function getName(): string; + + /** + * The version of the instrumenting/instrumented library/package/project. + * If unknown or a lookup is too expensive simply return NULL. + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/v1.12.0/specification/glossary.md#instrumentation-scope + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/v1.12.0/specification/glossary.md#instrumentation-library + */ + abstract public function getVersion(): ?string; + + /** + * The version of the instrumenting/instrumented library/package/project. + * If unknown simply return NULL. + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/v1.12.0/specification/glossary.md#instrumentation-scope + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/v1.12.0/specification/glossary.md#instrumentation-library + */ + abstract public function getSchemaUrl(): ?string; + + /** + * This method will be called from the API when the instrumentation has been activated (via activate()). + * Here you can put any bootstrapping code needed by the instrumentation. + * If not needed simply implement a method which returns TRUE. + */ + abstract public function init(): bool; + + /** + * This method registers and activates the instrumentation with the OpenTelemetry API/SDK and thus + * the instrumentation will be used to generate telemetry data. + */ + public function activate(): bool + { + $this->validateImplementation(); + // activate instrumentation with the API. not implemented yet. + return true; + } + + public function setPropagator(TextMapPropagatorInterface $propagator): void + { + $this->propagator = $propagator; + } + + public function getPropagator(): TextMapPropagatorInterface + { + return $this->propagator; + } + + public function setTracerProvider(TracerProviderInterface $tracerProvider): void + { + $this->tracerProvider = $tracerProvider; + // @see https://github.com/open-telemetry/opentelemetry-specification/blob/v1.12.0/specification/trace/api.md#get-a-tracer + $this->tracer = $tracerProvider->getTracer( + $this->getName(), + $this->getVersion(), + $this->getSchemaUrl(), + ); + } + + public function getTracerProvider(): TracerProviderInterface + { + return $this->tracerProvider; + } + + public function getTracer(): TracerInterface + { + return $this->tracer; + } + + public function setMeterProvider(MeterProviderInterface $meterProvider): void + { + // @see https://github.com/open-telemetry/opentelemetry-specification/blob/v1.12.0/specification/metrics/api.md#get-a-meter + $this->meter = $meterProvider->getMeter( + $this->getName(), + $this->getVersion(), + ); + } + + public function getMeter(): MeterInterface + { + return $this->meter; + } + + public function setLogger(LoggerInterface $logger): void + { + $this->logger = $logger; + } + + public function getLogger(): LoggerInterface + { + return $this->logger; + } + + private function validateImplementation(): void + { + if (!$this instanceof InstrumentationInterface) { + throw new RuntimeException(sprintf( + '"%s" is meant to implement "%s"', + InstrumentationTrait::class, + InstrumentationInterface::class + )); + } + } + + private function initDefaults(): void + { + $this->propagator = new NoopTextMapPropagator(); + $this->tracer = new NoopTracer(); + $this->tracerProvider = new NoopTracerProvider(); + /** @phan-suppress-next-line PhanAccessMethodInternal */ + $this->meter = new NoopMeter(); + $this->logger = new NullLogger(); + } +} diff --git a/vendor/open-telemetry/api/LoggerHolder.php b/vendor/open-telemetry/api/LoggerHolder.php new file mode 100644 index 000000000..99f916a23 --- /dev/null +++ b/vendor/open-telemetry/api/LoggerHolder.php @@ -0,0 +1,53 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\API; + +use Psr\Log\LoggerInterface; +use Psr\Log\NullLogger; + +final class LoggerHolder +{ + private static ?LoggerInterface $logger = null; + + /** + * This constructor is a temporary solution to ease the setup of the logger with DI libraries + */ + public function __construct(?LoggerInterface $logger = null) + { + self::$logger = $logger; + } + + /** + * @suppress PhanTypeMismatchReturnNullable + * @internal + */ + public static function get(): ?LoggerInterface + { + return self::$logger; + } + + public static function set(?LoggerInterface $logger): void + { + self::$logger = $logger; + } + + public static function isSet(): bool + { + return null !== self::$logger; + } + + public static function unset(): void + { + self::$logger = null; + } + + /** + * Disable psr-3 logging + */ + public static function disable(): void + { + self::$logger = new NullLogger(); + } +} diff --git a/vendor/open-telemetry/api/Logs/EventLogger.php b/vendor/open-telemetry/api/Logs/EventLogger.php new file mode 100644 index 000000000..68deb865c --- /dev/null +++ b/vendor/open-telemetry/api/Logs/EventLogger.php @@ -0,0 +1,26 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\API\Logs; + +class EventLogger implements EventLoggerInterface +{ + private LoggerInterface $logger; + private string $domain; + + public function __construct(LoggerInterface $logger, string $domain) + { + $this->logger = $logger; + $this->domain = $domain; + } + + public function logEvent(string $eventName, LogRecord $logRecord): void + { + $logRecord->setAttributes([ + 'event.name' => $eventName, + 'event.domain' => $this->domain, + ]); + $this->logger->emit($logRecord); + } +} diff --git a/vendor/open-telemetry/api/Logs/EventLoggerInterface.php b/vendor/open-telemetry/api/Logs/EventLoggerInterface.php new file mode 100644 index 000000000..a2096b9b7 --- /dev/null +++ b/vendor/open-telemetry/api/Logs/EventLoggerInterface.php @@ -0,0 +1,13 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\API\Logs; + +/** + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/logs/event-api.md#events-api-interface + */ +interface EventLoggerInterface +{ + public function logEvent(string $eventName, LogRecord $logRecord): void; +} diff --git a/vendor/open-telemetry/api/Logs/LogRecord.php b/vendor/open-telemetry/api/Logs/LogRecord.php new file mode 100644 index 000000000..6833c71f9 --- /dev/null +++ b/vendor/open-telemetry/api/Logs/LogRecord.php @@ -0,0 +1,108 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\API\Logs; + +use OpenTelemetry\Context\ContextInterface; + +class LogRecord +{ + public const NANOS_PER_SECOND = 1_000_000_000; + + protected ?int $timestamp = null; + protected ?int $observedTimestamp = null; + protected ?ContextInterface $context = null; + protected int $severityNumber = 0; + protected ?string $severityText = null; + protected $body = null; + protected array $attributes = []; + + /** + * @param mixed $body + */ + public function __construct($body = null) + { + $this->body = $body; + } + + /** + * @param int $timestamp Timestamp, in nanoseconds since the unix epoch, when the event occurred. + * @see https://opentelemetry.io/docs/reference/specification/logs/data-model/#field-timestamp + */ + public function setTimestamp(int $timestamp): self + { + $this->timestamp = $timestamp; + + return $this; + } + + public function setContext(?ContextInterface $context = null): self + { + $this->context = $context; + + return $this; + } + + /** + * @param int $severityNumber Severity number + * @see https://opentelemetry.io/docs/reference/specification/logs/data-model/#field-severitynumber + */ + public function setSeverityNumber(int $severityNumber): self + { + $this->severityNumber = $severityNumber; + + return $this; + } + + /** + * @param string $severityText Severity text, also known as log level + * @see https://opentelemetry.io/docs/reference/specification/logs/data-model/#field-severitynumber + */ + public function setSeverityText(string $severityText): self + { + $this->severityText = $severityText; + + return $this; + } + + /** + * @param iterable $attributes Additional information about the specific event occurrence. + * @see https://opentelemetry.io/docs/reference/specification/logs/data-model/#field-attributes + */ + public function setAttributes(iterable $attributes): self + { + foreach ($attributes as $name => $value) { + $this->setAttribute($name, $value); + } + + return $this; + } + + public function setAttribute(string $name, $value): self + { + $this->attributes[$name] = $value; + + return $this; + } + + /** + * @param mixed $body The log record body + */ + public function setBody($body = null): self + { + $this->body = $body; + + return $this; + } + + /** + * @param int|null $observedTimestamp Time, in nanoseconds since the unix epoch, when the event was observed by the collection system. + */ + public function setObservedTimestamp(int $observedTimestamp = null): self + { + $this->observedTimestamp = $observedTimestamp; + + return $this; + } +} diff --git a/vendor/open-telemetry/api/Logs/LoggerInterface.php b/vendor/open-telemetry/api/Logs/LoggerInterface.php new file mode 100644 index 000000000..89477c8d2 --- /dev/null +++ b/vendor/open-telemetry/api/Logs/LoggerInterface.php @@ -0,0 +1,10 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\API\Logs; + +interface LoggerInterface +{ + public function emit(LogRecord $logRecord): void; +} diff --git a/vendor/open-telemetry/api/Logs/LoggerProviderInterface.php b/vendor/open-telemetry/api/Logs/LoggerProviderInterface.php new file mode 100644 index 000000000..e60353de2 --- /dev/null +++ b/vendor/open-telemetry/api/Logs/LoggerProviderInterface.php @@ -0,0 +1,18 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\API\Logs; + +/** + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/logs/bridge-api.md#get-a-logger + */ +interface LoggerProviderInterface +{ + public function getLogger( + string $name, + ?string $version = null, + ?string $schemaUrl = null, + iterable $attributes = [] //instrumentation scope attributes + ): LoggerInterface; +} diff --git a/vendor/open-telemetry/api/Logs/Map/Psr3.php b/vendor/open-telemetry/api/Logs/Map/Psr3.php new file mode 100644 index 000000000..8fd85fad0 --- /dev/null +++ b/vendor/open-telemetry/api/Logs/Map/Psr3.php @@ -0,0 +1,40 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\API\Logs\Map; + +use Psr\Log\LogLevel; + +class Psr3 +{ + /** + * Maps PSR-3 severity level (string) to the appropriate opentelemetry severity number + * + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/logs/data-model-appendix.md#appendix-b-severitynumber-example-mappings + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/logs/data-model.md#field-severitynumber + */ + public static function severityNumber(string $level): int + { + switch (strtolower($level)) { + case LogLevel::DEBUG: + return 5; + case LogLevel::INFO: + return 9; + case LogLevel::NOTICE: + return 10; + case LogLevel::WARNING: + return 13; + case LogLevel::ERROR: + return 17; + case LogLevel::CRITICAL: + return 18; + case LogLevel::ALERT: + return 19; + case LogLevel::EMERGENCY: + return 21; + default: + return 0; + } + } +} diff --git a/vendor/open-telemetry/api/Logs/NoopLogger.php b/vendor/open-telemetry/api/Logs/NoopLogger.php new file mode 100644 index 000000000..faacd5e10 --- /dev/null +++ b/vendor/open-telemetry/api/Logs/NoopLogger.php @@ -0,0 +1,33 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\API\Logs; + +use Psr\Log\LoggerTrait; + +class NoopLogger implements LoggerInterface +{ + use LoggerTrait; + + public static function getInstance(): self + { + static $instance; + + return $instance ??= new self(); + } + + /** + * @codeCoverageIgnore + */ + public function emit(LogRecord $logRecord): void + { + } + + /** + * @codeCoverageIgnore + */ + public function log($level, $message, array $context = []): void + { + } +} diff --git a/vendor/open-telemetry/api/Logs/NoopLoggerProvider.php b/vendor/open-telemetry/api/Logs/NoopLoggerProvider.php new file mode 100644 index 000000000..8b00b6637 --- /dev/null +++ b/vendor/open-telemetry/api/Logs/NoopLoggerProvider.php @@ -0,0 +1,20 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\API\Logs; + +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(); + } +} diff --git a/vendor/open-telemetry/api/Logs/README.md b/vendor/open-telemetry/api/Logs/README.md new file mode 100644 index 000000000..d0bdb923e --- /dev/null +++ b/vendor/open-telemetry/api/Logs/README.md @@ -0,0 +1,19 @@ +# Logs API + +This `Logger` API is not designed to be used by application developers, but rather by library developers for the purpose +of integrating existing logging libraries with OpenTelemetry. + +## Logging from 3rd party loggers + +3rd party loggers should log to OpenTelemetry in accordance with the +[logs bridge API](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/logs/bridge-api.md) +specification. + +This means that a "log appender" in the 3rd party logging library (sometimes known as a "handler") should: +- accept an `OpenTelemetry\API\Logs\LoggerProviderInterface`, or obtain a globally registered one from `OpenTelemetry\API\Instrumentation\Globals` +- obtain a `Logger` from the logger provider (optionally adding any resources that should be associated with logs emitted) +- convert logs from its own log format into OpenTelemetry's `LogRecord` format +- send the logs to OpenTelemetry via `Logger::logRecord()` + +See [monolog-otel-integration](/examples/logs/features/monolog-otel-integration.php) for an example. + diff --git a/vendor/open-telemetry/api/Metrics/CounterInterface.php b/vendor/open-telemetry/api/Metrics/CounterInterface.php new file mode 100644 index 000000000..f0da706e1 --- /dev/null +++ b/vendor/open-telemetry/api/Metrics/CounterInterface.php @@ -0,0 +1,21 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\API\Metrics; + +use OpenTelemetry\Context\ContextInterface; + +interface CounterInterface +{ + + /** + * @param float|int $amount non-negative amount to increment by + * @param iterable<non-empty-string, string|bool|float|int|array|null> $attributes + * attributes of the data point + * @param ContextInterface|false|null $context execution context + * + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/api.md#add + */ + public function add($amount, iterable $attributes = [], $context = null): void; +} diff --git a/vendor/open-telemetry/api/Metrics/HistogramInterface.php b/vendor/open-telemetry/api/Metrics/HistogramInterface.php new file mode 100644 index 000000000..22ddd1f3c --- /dev/null +++ b/vendor/open-telemetry/api/Metrics/HistogramInterface.php @@ -0,0 +1,21 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\API\Metrics; + +use OpenTelemetry\Context\ContextInterface; + +interface HistogramInterface +{ + + /** + * @param float|int $amount non-negative amount to record + * @param iterable<non-empty-string, string|bool|float|int|array|null> $attributes + * attributes of the data point + * @param ContextInterface|false|null $context execution context + * + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/api.md#record + */ + public function record($amount, iterable $attributes = [], $context = null): void; +} diff --git a/vendor/open-telemetry/api/Metrics/MeterInterface.php b/vendor/open-telemetry/api/Metrics/MeterInterface.php new file mode 100644 index 000000000..6e06d9085 --- /dev/null +++ b/vendor/open-telemetry/api/Metrics/MeterInterface.php @@ -0,0 +1,111 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\API\Metrics; + +interface MeterInterface +{ + + /** + * Creates a `Counter`. + * + * @param string $name name of the instrument + * @param string|null $unit unit of measure + * @param string|null $description description of the instrument + * @return CounterInterface created instrument + * + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/api.md#counter-creation + */ + public function createCounter( + string $name, + ?string $unit = null, + ?string $description = null + ): CounterInterface; + + /** + * Creates an `ObservableCounter`. + * + * @param string $name name of the instrument + * @param string|null $unit unit of measure + * @param string|null $description description of the instrument + * @param callable ...$callbacks responsible for reporting measurements + * @return ObservableCounterInterface created instrument + * + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/api.md#asynchronous-counter-creation + */ + public function createObservableCounter( + string $name, + ?string $unit = null, + ?string $description = null, + callable ...$callbacks + ): ObservableCounterInterface; + + /** + * Creates a `Histogram`. + * + * @param string $name name of the instrument + * @param string|null $unit unit of measure + * @param string|null $description description of the instrument + * @return HistogramInterface created instrument + * + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/api.md#histogram-creation + */ + public function createHistogram( + string $name, + ?string $unit = null, + ?string $description = null + ): HistogramInterface; + + /** + * Creates an `ObservableGauge`. + * + * @param string $name name of the instrument + * @param string|null $unit unit of measure + * @param string|null $description description of the instrument + * @param callable ...$callbacks responsible for reporting measurements + * @return ObservableGaugeInterface created instrument + * + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/api.md#asynchronous-gauge-creation + */ + public function createObservableGauge( + string $name, + ?string $unit = null, + ?string $description = null, + callable ...$callbacks + ): ObservableGaugeInterface; + + /** + * Creates an `UpDownCounter`. + * + * @param string $name name of the instrument + * @param string|null $unit unit of measure + * @param string|null $description description of the instrument + * @return UpDownCounterInterface created instrument + * + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/api.md#updowncounter-creation + */ + public function createUpDownCounter( + string $name, + ?string $unit = null, + ?string $description = null + ): UpDownCounterInterface; + + /** + * Creates an `ObservableUpDownCounter`. + * + * @param string $name name of the instrument + * @param string|null $unit unit of measure + * @param string|null $description description of the instrument + * @param callable ...$callbacks responsible for reporting measurements + * @return ObservableUpDownCounterInterface created instrument + * + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/api.md#asynchronous-updowncounter-creation + */ + public function createObservableUpDownCounter( + string $name, + ?string $unit = null, + ?string $description = null, + callable ...$callbacks + ): ObservableUpDownCounterInterface; +} diff --git a/vendor/open-telemetry/api/Metrics/MeterProviderInterface.php b/vendor/open-telemetry/api/Metrics/MeterProviderInterface.php new file mode 100644 index 000000000..f8fa07a2e --- /dev/null +++ b/vendor/open-telemetry/api/Metrics/MeterProviderInterface.php @@ -0,0 +1,28 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\API\Metrics; + +interface MeterProviderInterface +{ + + /** + * Returns a `Meter` for the given instrumentation scope. + * + * @param string $name name of the instrumentation scope + * @param string|null $version version of the instrumentation scope + * @param string|null $schemaUrl schema url to record in the emitted telemetry + * @param iterable<non-empty-string, string|bool|float|int|array|null> $attributes + * instrumentation scope attributes + * @return MeterInterface meter instance for the instrumentation scope + * + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/api.md#get-a-meter + */ + public function getMeter( + string $name, + ?string $version = null, + ?string $schemaUrl = null, + iterable $attributes = [] + ): MeterInterface; +} diff --git a/vendor/open-telemetry/api/Metrics/Noop/NoopCounter.php b/vendor/open-telemetry/api/Metrics/Noop/NoopCounter.php new file mode 100644 index 000000000..d47fc2166 --- /dev/null +++ b/vendor/open-telemetry/api/Metrics/Noop/NoopCounter.php @@ -0,0 +1,18 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\API\Metrics\Noop; + +use OpenTelemetry\API\Metrics\CounterInterface; + +/** + * @internal + */ +final class NoopCounter implements CounterInterface +{ + public function add($amount, iterable $attributes = [], $context = null): void + { + // no-op + } +} diff --git a/vendor/open-telemetry/api/Metrics/Noop/NoopHistogram.php b/vendor/open-telemetry/api/Metrics/Noop/NoopHistogram.php new file mode 100644 index 000000000..79f0e60ce --- /dev/null +++ b/vendor/open-telemetry/api/Metrics/Noop/NoopHistogram.php @@ -0,0 +1,18 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\API\Metrics\Noop; + +use OpenTelemetry\API\Metrics\HistogramInterface; + +/** + * @internal + */ +final class NoopHistogram implements HistogramInterface +{ + public function record($amount, iterable $attributes = [], $context = null): void + { + // no-op + } +} diff --git a/vendor/open-telemetry/api/Metrics/Noop/NoopMeter.php b/vendor/open-telemetry/api/Metrics/Noop/NoopMeter.php new file mode 100644 index 000000000..31e3bd35c --- /dev/null +++ b/vendor/open-telemetry/api/Metrics/Noop/NoopMeter.php @@ -0,0 +1,46 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\API\Metrics\Noop; + +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; + +final class NoopMeter implements MeterInterface +{ + public function createCounter(string $name, ?string $unit = null, ?string $description = null): CounterInterface + { + return new NoopCounter(); + } + + public function createObservableCounter(string $name, ?string $unit = null, ?string $description = null, callable ...$callbacks): ObservableCounterInterface + { + return new NoopObservableCounter(); + } + + public function createHistogram(string $name, ?string $unit = null, ?string $description = null): HistogramInterface + { + return new NoopHistogram(); + } + + public function createObservableGauge(string $name, ?string $unit = null, ?string $description = null, callable ...$callbacks): ObservableGaugeInterface + { + return new NoopObservableGauge(); + } + + public function createUpDownCounter(string $name, ?string $unit = null, ?string $description = null): UpDownCounterInterface + { + return new NoopUpDownCounter(); + } + + public function createObservableUpDownCounter(string $name, ?string $unit = null, ?string $description = null, callable ...$callbacks): ObservableUpDownCounterInterface + { + return new NoopObservableUpDownCounter(); + } +} diff --git a/vendor/open-telemetry/api/Metrics/Noop/NoopMeterProvider.php b/vendor/open-telemetry/api/Metrics/Noop/NoopMeterProvider.php new file mode 100644 index 000000000..b4b5810eb --- /dev/null +++ b/vendor/open-telemetry/api/Metrics/Noop/NoopMeterProvider.php @@ -0,0 +1,20 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\API\Metrics\Noop; + +use OpenTelemetry\API\Metrics\MeterInterface; +use OpenTelemetry\API\Metrics\MeterProviderInterface; + +final class NoopMeterProvider implements MeterProviderInterface +{ + public function getMeter( + string $name, + ?string $version = null, + ?string $schemaUrl = null, + iterable $attributes = [] + ): MeterInterface { + return new NoopMeter(); + } +} diff --git a/vendor/open-telemetry/api/Metrics/Noop/NoopObservableCallback.php b/vendor/open-telemetry/api/Metrics/Noop/NoopObservableCallback.php new file mode 100644 index 000000000..c933bd506 --- /dev/null +++ b/vendor/open-telemetry/api/Metrics/Noop/NoopObservableCallback.php @@ -0,0 +1,18 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\API\Metrics\Noop; + +use OpenTelemetry\API\Metrics\ObservableCallbackInterface; + +/** + * @internal + */ +final class NoopObservableCallback implements ObservableCallbackInterface +{ + public function detach(): void + { + // no-op + } +} diff --git a/vendor/open-telemetry/api/Metrics/Noop/NoopObservableCounter.php b/vendor/open-telemetry/api/Metrics/Noop/NoopObservableCounter.php new file mode 100644 index 000000000..41e363201 --- /dev/null +++ b/vendor/open-telemetry/api/Metrics/Noop/NoopObservableCounter.php @@ -0,0 +1,19 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\API\Metrics\Noop; + +use OpenTelemetry\API\Metrics\ObservableCallbackInterface; +use OpenTelemetry\API\Metrics\ObservableCounterInterface; + +/** + * @internal + */ +final class NoopObservableCounter implements ObservableCounterInterface +{ + public function observe(callable $callback, bool $weaken = false): ObservableCallbackInterface + { + return new NoopObservableCallback(); + } +} diff --git a/vendor/open-telemetry/api/Metrics/Noop/NoopObservableGauge.php b/vendor/open-telemetry/api/Metrics/Noop/NoopObservableGauge.php new file mode 100644 index 000000000..987a530c8 --- /dev/null +++ b/vendor/open-telemetry/api/Metrics/Noop/NoopObservableGauge.php @@ -0,0 +1,19 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\API\Metrics\Noop; + +use OpenTelemetry\API\Metrics\ObservableCallbackInterface; +use OpenTelemetry\API\Metrics\ObservableGaugeInterface; + +/** + * @internal + */ +final class NoopObservableGauge implements ObservableGaugeInterface +{ + public function observe(callable $callback, bool $weaken = false): ObservableCallbackInterface + { + return new NoopObservableCallback(); + } +} diff --git a/vendor/open-telemetry/api/Metrics/Noop/NoopObservableUpDownCounter.php b/vendor/open-telemetry/api/Metrics/Noop/NoopObservableUpDownCounter.php new file mode 100644 index 000000000..65a2bb830 --- /dev/null +++ b/vendor/open-telemetry/api/Metrics/Noop/NoopObservableUpDownCounter.php @@ -0,0 +1,19 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\API\Metrics\Noop; + +use OpenTelemetry\API\Metrics\ObservableCallbackInterface; +use OpenTelemetry\API\Metrics\ObservableUpDownCounterInterface; + +/** + * @internal + */ +final class NoopObservableUpDownCounter implements ObservableUpDownCounterInterface +{ + public function observe(callable $callback, bool $weaken = false): ObservableCallbackInterface + { + return new NoopObservableCallback(); + } +} diff --git a/vendor/open-telemetry/api/Metrics/Noop/NoopUpDownCounter.php b/vendor/open-telemetry/api/Metrics/Noop/NoopUpDownCounter.php new file mode 100644 index 000000000..e26140b7c --- /dev/null +++ b/vendor/open-telemetry/api/Metrics/Noop/NoopUpDownCounter.php @@ -0,0 +1,18 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\API\Metrics\Noop; + +use OpenTelemetry\API\Metrics\UpDownCounterInterface; + +/** + * @internal + */ +final class NoopUpDownCounter implements UpDownCounterInterface +{ + public function add($amount, iterable $attributes = [], $context = null): void + { + // no-op + } +} diff --git a/vendor/open-telemetry/api/Metrics/ObservableCallbackInterface.php b/vendor/open-telemetry/api/Metrics/ObservableCallbackInterface.php new file mode 100644 index 000000000..a20e59666 --- /dev/null +++ b/vendor/open-telemetry/api/Metrics/ObservableCallbackInterface.php @@ -0,0 +1,56 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\API\Metrics; + +/** + * An observed callback. + * + * Callbacks that are bound to an object are automatically detached when the + * `ObservableCallbackInterface` and the bound object are out of scope. + * This means that the `ObservableCallbackInterface` can be ignored if the + * observed callback should be bound to the lifetime of the object. + * ```php + * class Example { + * function __construct(MeterProviderInterface $meterProvider) { + * $meterProvider->getMeter('example') + * ->createObservableGauge('random') + * ->observe(fn(ObserverInterface $observer) + * => $observer->observe(rand(0, 10))); + * } + * } + * ``` + * Keeping a reference to the `ObservableCallbackInterface` within the bound + * object to gain a more fine-grained control over the life-time of the callback + * does not prevent garbage collection (but might require cycle collection). + * + * Unbound (static) callbacks must be detached manually using + * {@link ObservableCallbackInterface::detach()}. + * ```php + * class Example { + * private ObservableCallbackInterface $gauge; + * function __construct(MeterProviderInterface $meterProvider) { + * $this->gauge = $meterProvider->getMeter('example') + * ->createObservableGauge('random') + * ->observe(static fn(ObserverInterface $observer) + * => $observer->observe(rand(0, 10))); + * } + * function __destruct() { + * $this->gauge->detach(); + * } + * } + * ``` + * + * @see ObservableCounterInterface::observe() + * @see ObservableGaugeInterface::observe() + * @see ObservableUpDownCounterInterface::observe() + */ +interface ObservableCallbackInterface +{ + + /** + * Detaches the associated callback from the instrument. + */ + public function detach(): void; +} diff --git a/vendor/open-telemetry/api/Metrics/ObservableCounterInterface.php b/vendor/open-telemetry/api/Metrics/ObservableCounterInterface.php new file mode 100644 index 000000000..feb1ed439 --- /dev/null +++ b/vendor/open-telemetry/api/Metrics/ObservableCounterInterface.php @@ -0,0 +1,16 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\API\Metrics; + +interface ObservableCounterInterface +{ + + /** + * @param callable(ObserverInterface): void $callback function responsible for + * reporting the measurements (as absolute values) + * @return ObservableCallbackInterface token to detach callback + */ + public function observe(callable $callback): ObservableCallbackInterface; +} diff --git a/vendor/open-telemetry/api/Metrics/ObservableGaugeInterface.php b/vendor/open-telemetry/api/Metrics/ObservableGaugeInterface.php new file mode 100644 index 000000000..afe59a777 --- /dev/null +++ b/vendor/open-telemetry/api/Metrics/ObservableGaugeInterface.php @@ -0,0 +1,16 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\API\Metrics; + +interface ObservableGaugeInterface +{ + + /** + * @param callable(ObserverInterface): void $callback function responsible for + * reporting the measurements + * @return ObservableCallbackInterface token to detach callback + */ + public function observe(callable $callback): ObservableCallbackInterface; +} diff --git a/vendor/open-telemetry/api/Metrics/ObservableUpDownCounterInterface.php b/vendor/open-telemetry/api/Metrics/ObservableUpDownCounterInterface.php new file mode 100644 index 000000000..79548dec6 --- /dev/null +++ b/vendor/open-telemetry/api/Metrics/ObservableUpDownCounterInterface.php @@ -0,0 +1,16 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\API\Metrics; + +interface ObservableUpDownCounterInterface +{ + + /** + * @param callable(ObserverInterface): void $callback function responsible for + * reporting the measurements (as absolute values) + * @return ObservableCallbackInterface token to detach callback + */ + public function observe(callable $callback): ObservableCallbackInterface; +} diff --git a/vendor/open-telemetry/api/Metrics/ObserverInterface.php b/vendor/open-telemetry/api/Metrics/ObserverInterface.php new file mode 100644 index 000000000..36e0ea791 --- /dev/null +++ b/vendor/open-telemetry/api/Metrics/ObserverInterface.php @@ -0,0 +1,18 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\API\Metrics; + +interface ObserverInterface +{ + + /** + * Records the given absolute datapoint. + * + * @param float|int $amount observed amount + * @param iterable<non-empty-string, string|bool|float|int|array|null> $attributes + * attributes of the data point + */ + public function observe($amount, iterable $attributes = []): void; +} diff --git a/vendor/open-telemetry/api/Metrics/UpDownCounterInterface.php b/vendor/open-telemetry/api/Metrics/UpDownCounterInterface.php new file mode 100644 index 000000000..f1f808fdb --- /dev/null +++ b/vendor/open-telemetry/api/Metrics/UpDownCounterInterface.php @@ -0,0 +1,19 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\API\Metrics; + +use OpenTelemetry\Context\ContextInterface; + +interface UpDownCounterInterface +{ + + /** + * @param float|int $amount amount to increment / decrement by + * @param iterable<non-empty-string, string|bool|float|int|array|null> $attributes + * attributes of the data point + * @param ContextInterface|false|null $context execution context + */ + public function add($amount, iterable $attributes = [], $context = null): void; +} diff --git a/vendor/open-telemetry/api/README.md b/vendor/open-telemetry/api/README.md new file mode 100644 index 000000000..c2cbd1bf1 --- /dev/null +++ b/vendor/open-telemetry/api/README.md @@ -0,0 +1,14 @@ +[![Releases](https://img.shields.io/badge/releases-purple)](https://github.com/opentelemetry-php/api/releases) +[![Source](https://img.shields.io/badge/source-api-green)](https://github.com/open-telemetry/opentelemetry-php/tree/main/src/API) +[![Mirror](https://img.shields.io/badge/mirror-opentelemetry--php:api-blue)](https://github.com/opentelemetry-php/api) +[![Latest Version](http://poser.pugx.org/open-telemetry/api/v/unstable)](https://packagist.org/packages/open-telemetry/api/) +[![Stable](http://poser.pugx.org/open-telemetry/api/v/stable)](https://packagist.org/packages/open-telemetry/api/) + +# OpenTelemetry API + +Documentation: https://opentelemetry.io/docs/instrumentation/php + +## 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/api/Signals.php b/vendor/open-telemetry/api/Signals.php new file mode 100644 index 000000000..95582aaa2 --- /dev/null +++ b/vendor/open-telemetry/api/Signals.php @@ -0,0 +1,21 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\API; + +interface Signals +{ + /** @var string */ + public const TRACE = 'trace'; + /** @var string */ + public const METRICS = 'metrics'; + /** @var string */ + public const LOGS = 'logs'; + /** @var string[] */ + public const SIGNALS = [ + self::TRACE, + self::METRICS, + self::LOGS, + ]; +} diff --git a/vendor/open-telemetry/api/Trace/NonRecordingSpan.php b/vendor/open-telemetry/api/Trace/NonRecordingSpan.php new file mode 100644 index 000000000..67d74d39b --- /dev/null +++ b/vendor/open-telemetry/api/Trace/NonRecordingSpan.php @@ -0,0 +1,76 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\API\Trace; + +use Throwable; + +/** + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/v1.6.1/specification/trace/api.md#wrapping-a-spancontext-in-a-span + * + * @psalm-internal OpenTelemetry + */ +final class NonRecordingSpan extends Span +{ + private SpanContextInterface $context; + + public function __construct( + SpanContextInterface $context + ) { + $this->context = $context; + } + + /** @inheritDoc */ + public function getContext(): SpanContextInterface + { + return $this->context; + } + + /** @inheritDoc */ + public function isRecording(): bool + { + return false; + } + + /** @inheritDoc */ + public function setAttribute(string $key, $value): SpanInterface + { + return $this; + } + + /** @inheritDoc */ + public function setAttributes(iterable $attributes): SpanInterface + { + return $this; + } + + /** @inheritDoc */ + public function addEvent(string $name, iterable $attributes = [], int $timestamp = null): SpanInterface + { + return $this; + } + + /** @inheritDoc */ + public function recordException(Throwable $exception, iterable $attributes = []): SpanInterface + { + return $this; + } + + /** @inheritDoc */ + public function updateName(string $name): SpanInterface + { + return $this; + } + + /** @inheritDoc */ + public function setStatus(string $code, string $description = null): SpanInterface + { + return $this; + } + + /** @inheritDoc */ + public function end(int $endEpochNanos = null): void + { + } +} diff --git a/vendor/open-telemetry/api/Trace/NoopSpanBuilder.php b/vendor/open-telemetry/api/Trace/NoopSpanBuilder.php new file mode 100644 index 000000000..6f971e525 --- /dev/null +++ b/vendor/open-telemetry/api/Trace/NoopSpanBuilder.php @@ -0,0 +1,65 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\API\Trace; + +use OpenTelemetry\Context\Context; +use OpenTelemetry\Context\ContextInterface; +use OpenTelemetry\Context\ContextStorageInterface; + +final class NoopSpanBuilder implements SpanBuilderInterface +{ + private ContextStorageInterface $contextStorage; + + /** @var ContextInterface|false|null */ + private $parentContext = null; + + public function __construct(ContextStorageInterface $contextStorage) + { + $this->contextStorage = $contextStorage; + } + + public function setParent($context): SpanBuilderInterface + { + $this->parentContext = $context; + + return $this; + } + + public function addLink(SpanContextInterface $context, iterable $attributes = []): SpanBuilderInterface + { + return $this; + } + + public function setAttribute(string $key, $value): SpanBuilderInterface + { + return $this; + } + + public function setAttributes(iterable $attributes): SpanBuilderInterface + { + return $this; + } + + public function setStartTimestamp(int $timestampNanos): SpanBuilderInterface + { + return $this; + } + + public function setSpanKind(int $spanKind): SpanBuilderInterface + { + return $this; + } + + public function startSpan(): SpanInterface + { + $parentContext = Context::resolve($this->parentContext, $this->contextStorage); + $span = Span::fromContext($parentContext); + if ($span->isRecording()) { + $span = Span::wrap($span->getContext()); + } + + return $span; + } +} diff --git a/vendor/open-telemetry/api/Trace/NoopTracer.php b/vendor/open-telemetry/api/Trace/NoopTracer.php new file mode 100644 index 000000000..bc50248bd --- /dev/null +++ b/vendor/open-telemetry/api/Trace/NoopTracer.php @@ -0,0 +1,26 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\API\Trace; + +use OpenTelemetry\Context\Context; + +final class NoopTracer implements TracerInterface +{ + private static ?self $instance = null; + + public static function getInstance(): self + { + if (null === self::$instance) { + self::$instance = new self(); + } + + return self::$instance; + } + + public function spanBuilder(string $spanName): SpanBuilderInterface + { + return new NoopSpanBuilder(Context::storage()); + } +} diff --git a/vendor/open-telemetry/api/Trace/NoopTracerProvider.php b/vendor/open-telemetry/api/Trace/NoopTracerProvider.php new file mode 100644 index 000000000..e186a6fd9 --- /dev/null +++ b/vendor/open-telemetry/api/Trace/NoopTracerProvider.php @@ -0,0 +1,17 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\API\Trace; + +class NoopTracerProvider implements TracerProviderInterface +{ + public function getTracer( + string $name, + ?string $version = null, + ?string $schemaUrl = null, + iterable $attributes = [] + ): TracerInterface { + return NoopTracer::getInstance(); + } +} diff --git a/vendor/open-telemetry/api/Trace/Propagation/TraceContextPropagator.php b/vendor/open-telemetry/api/Trace/Propagation/TraceContextPropagator.php new file mode 100644 index 000000000..b70a15647 --- /dev/null +++ b/vendor/open-telemetry/api/Trace/Propagation/TraceContextPropagator.php @@ -0,0 +1,157 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\API\Trace\Propagation; + +use function count; +use function explode; +use function hexdec; +use OpenTelemetry\API\Trace\Span; +use OpenTelemetry\API\Trace\SpanContext; +use OpenTelemetry\API\Trace\SpanContextInterface; +use OpenTelemetry\API\Trace\SpanContextValidator; +use OpenTelemetry\API\Trace\TraceFlags; +use OpenTelemetry\API\Trace\TraceState; +use OpenTelemetry\Context\Context; +use OpenTelemetry\Context\ContextInterface; +use OpenTelemetry\Context\Propagation\ArrayAccessGetterSetter; +use OpenTelemetry\Context\Propagation\PropagationGetterInterface; +use OpenTelemetry\Context\Propagation\PropagationSetterInterface; +use OpenTelemetry\Context\Propagation\TextMapPropagatorInterface; + +/** + * TraceContext is a propagator that supports the W3C Trace Context format + * (https://www.w3.org/TR/trace-context/) + * + * This propagator will propagate the traceparent and tracestate headers to + * guarantee traces are not broken. It is up to the users of this propagator + * to choose if they want to participate in a trace by modifying the + * traceparent header and relevant parts of the tracestate header containing + * their proprietary information. + */ +final class TraceContextPropagator implements TextMapPropagatorInterface +{ + public const TRACEPARENT = 'traceparent'; + public const TRACESTATE = 'tracestate'; + private const VERSION = '00'; // Currently, only '00' is supported + + public const FIELDS = [ + self::TRACEPARENT, + self::TRACESTATE, + ]; + + private static ?self $instance = null; + + public static function getInstance(): self + { + if (null === self::$instance) { + self::$instance = new self(); + } + + return self::$instance; + } + + /** {@inheritdoc} */ + public function fields(): array + { + return self::FIELDS; + } + + /** {@inheritdoc} */ + public function inject(&$carrier, PropagationSetterInterface $setter = null, ContextInterface $context = null): void + { + $setter ??= ArrayAccessGetterSetter::getInstance(); + $context ??= Context::getCurrent(); + $spanContext = Span::fromContext($context)->getContext(); + + if (!$spanContext->isValid()) { + return; + } + + // Build and inject the traceparent header + $traceparent = self::VERSION . '-' . $spanContext->getTraceId() . '-' . $spanContext->getSpanId() . '-' . ($spanContext->isSampled() ? '01' : '00'); + $setter->set($carrier, self::TRACEPARENT, $traceparent); + + // Build and inject the tracestate header + // Spec says to avoid sending empty tracestate headers + if (($tracestate = (string) $spanContext->getTraceState()) !== '') { + $setter->set($carrier, self::TRACESTATE, $tracestate); + } + } + + /** {@inheritdoc} */ + public function extract($carrier, PropagationGetterInterface $getter = null, ContextInterface $context = null): ContextInterface + { + $getter ??= ArrayAccessGetterSetter::getInstance(); + $context ??= Context::getCurrent(); + + $spanContext = self::extractImpl($carrier, $getter); + if (!$spanContext->isValid()) { + return $context; + } + + return $context->withContextValue(Span::wrap($spanContext)); + } + + private static function extractImpl($carrier, PropagationGetterInterface $getter): SpanContextInterface + { + $traceparent = $getter->get($carrier, self::TRACEPARENT); + if ($traceparent === null) { + return SpanContext::getInvalid(); + } + + // traceParent = {version}-{trace-id}-{parent-id}-{trace-flags} + $pieces = explode('-', $traceparent); + + // If the header does not have at least 4 pieces, it is invalid -- restart the trace. + if (count($pieces) < 4) { + return SpanContext::getInvalid(); + } + + [$version, $traceId, $spanId, $traceFlags] = $pieces; + + /** + * Return invalid if: + * - Version is invalid (not 2 char hex or 'ff') + * - Trace version, trace ID, span ID or trace flag are invalid + */ + if (!TraceContextValidator::isValidTraceVersion($version) + || !SpanContextValidator::isValidTraceId($traceId) + || !SpanContextValidator::isValidSpanId($spanId) + || !TraceContextValidator::isValidTraceFlag($traceFlags) + ) { + return SpanContext::getInvalid(); + } + + // Return invalid if the trace version is not a future version but still has > 4 pieces. + $versionIsFuture = hexdec($version) > hexdec(self::VERSION); + if (count($pieces) > 4 && !$versionIsFuture) { + return SpanContext::getInvalid(); + } + + // Only the sampled flag is extracted from the traceFlags (00000001) + $convertedTraceFlags = hexdec($traceFlags); + $isSampled = ($convertedTraceFlags & TraceFlags::SAMPLED) === TraceFlags::SAMPLED; + + // Tracestate = 'Vendor1=Value1,...,VendorN=ValueN' + $rawTracestate = $getter->get($carrier, self::TRACESTATE); + if ($rawTracestate !== null) { + $tracestate = new TraceState($rawTracestate); + + return SpanContext::createFromRemoteParent( + $traceId, + $spanId, + $isSampled ? TraceFlags::SAMPLED : TraceFlags::DEFAULT, + $tracestate + ); + } + + // Only traceparent header is extracted. No tracestate. + return SpanContext::createFromRemoteParent( + $traceId, + $spanId, + $isSampled ? TraceFlags::SAMPLED : TraceFlags::DEFAULT + ); + } +} diff --git a/vendor/open-telemetry/api/Trace/Propagation/TraceContextValidator.php b/vendor/open-telemetry/api/Trace/Propagation/TraceContextValidator.php new file mode 100644 index 000000000..5fb3f12c7 --- /dev/null +++ b/vendor/open-telemetry/api/Trace/Propagation/TraceContextValidator.php @@ -0,0 +1,31 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\API\Trace\Propagation; + +use function strlen; + +class TraceContextValidator +{ + public const TRACE_FLAG_LENGTH = 2; + public const TRACE_VERSION_REGEX = '/^(?!ff)[\da-f]{2}$/'; + + /** + * @param string $traceVersion + * @return bool Returns a value that indicates whether a trace version is valid. + */ + public static function isValidTraceVersion(string $traceVersion): bool + { + return 1 === preg_match(self::TRACE_VERSION_REGEX, $traceVersion); + } + + /** + * @return bool Returns a value that indicates whether trace flag is valid + * TraceFlags must be exactly 1 bytes (1 char) representing a bit field + */ + public static function isValidTraceFlag(string $traceFlag): bool + { + return ctype_xdigit($traceFlag) && strlen($traceFlag) === self::TRACE_FLAG_LENGTH; + } +} diff --git a/vendor/open-telemetry/api/Trace/Span.php b/vendor/open-telemetry/api/Trace/Span.php new file mode 100644 index 000000000..88360e6cd --- /dev/null +++ b/vendor/open-telemetry/api/Trace/Span.php @@ -0,0 +1,59 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\API\Trace; + +use OpenTelemetry\Context\Context; +use OpenTelemetry\Context\ContextInterface; +use OpenTelemetry\Context\ContextKeys; +use OpenTelemetry\Context\ScopeInterface; + +abstract class Span implements SpanInterface +{ + private static ?self $invalidSpan = null; + + /** @inheritDoc */ + final public static function fromContext(ContextInterface $context): SpanInterface + { + return $context->get(ContextKeys::span()) ?? self::getInvalid(); + } + + /** @inheritDoc */ + final public static function getCurrent(): SpanInterface + { + return self::fromContext(Context::getCurrent()); + } + + /** @inheritDoc */ + final public static function getInvalid(): SpanInterface + { + if (null === self::$invalidSpan) { + self::$invalidSpan = new NonRecordingSpan(SpanContext::getInvalid()); + } + + return self::$invalidSpan; + } + + /** @inheritDoc */ + final public static function wrap(SpanContextInterface $spanContext): SpanInterface + { + if (!$spanContext->isValid()) { + return self::getInvalid(); + } + + return new NonRecordingSpan($spanContext); + } + + /** @inheritDoc */ + final public function activate(): ScopeInterface + { + return Context::getCurrent()->withContextValue($this)->activate(); + } + + /** @inheritDoc */ + final public function storeInContext(ContextInterface $context): ContextInterface + { + return $context->with(ContextKeys::span(), $this); + } +} diff --git a/vendor/open-telemetry/api/Trace/SpanBuilderInterface.php b/vendor/open-telemetry/api/Trace/SpanBuilderInterface.php new file mode 100644 index 000000000..52070933a --- /dev/null +++ b/vendor/open-telemetry/api/Trace/SpanBuilderInterface.php @@ -0,0 +1,51 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\API\Trace; + +use OpenTelemetry\Context\ContextInterface; + +/** + * Obtained from a {@see TracerInterface} and used to construct a {@see SpanInterface}. + */ +interface SpanBuilderInterface +{ + /** + * Sets the parent `Context`. + * + * @param ContextInterface|false|null $context the parent context, null to use the + * current context, false to set no parent + * @return SpanBuilderInterface this span builder + * + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/api.md#span-creation + */ + public function setParent($context): SpanBuilderInterface; + + public function addLink(SpanContextInterface $context, iterable $attributes = []): SpanBuilderInterface; + public function setAttribute(string $key, $value): SpanBuilderInterface; + public function setAttributes(iterable $attributes): SpanBuilderInterface; + + /** + * Sets an explicit start timestamp for the newly created {@see SpanInterface}. + * The provided *$timestamp* is assumed to be in nanoseconds. + * + * Defaults to the timestamp when {@see SpanBuilderInterface::startSpan} was called if not explicitly set. + */ + public function setStartTimestamp(int $timestampNanos): SpanBuilderInterface; + + /** + * @psalm-param SpanKind::KIND_* $spanKind + */ + public function setSpanKind(int $spanKind): SpanBuilderInterface; + + /** + * Starts and returns a new {@see SpanInterface}. + * + * The user _MUST_ manually end the span by calling {@see SpanInterface::end}. + * + * This method does _NOT_ automatically install the span into the current context. + * The user is responsible for calling {@see SpanInterface::activate} when they wish to do so. + */ + public function startSpan(): SpanInterface; +} diff --git a/vendor/open-telemetry/api/Trace/SpanContext.php b/vendor/open-telemetry/api/Trace/SpanContext.php new file mode 100644 index 000000000..7da7c0701 --- /dev/null +++ b/vendor/open-telemetry/api/Trace/SpanContext.php @@ -0,0 +1,127 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\API\Trace; + +use function hex2bin; + +final class SpanContext implements SpanContextInterface +{ + private static ?SpanContextInterface $invalidContext = null; + + /** + * @see https://www.w3.org/TR/trace-context/#trace-flags + * @see https://www.w3.org/TR/trace-context/#sampled-flag + */ + private bool $isSampled; + + private string $traceId; + private string $spanId; + private ?TraceStateInterface $traceState; + private bool $isValid = true; + private bool $isRemote; + private int $traceFlags; + + private function __construct( + string $traceId, + string $spanId, + int $traceFlags, + bool $isRemote, + TraceStateInterface $traceState = null + ) { + // TraceId must be exactly 16 bytes (32 chars) and at least one non-zero byte + // SpanId must be exactly 8 bytes (16 chars) and at least one non-zero byte + if (!SpanContextValidator::isValidTraceId($traceId) || !SpanContextValidator::isValidSpanId($spanId)) { + $traceId = SpanContextValidator::INVALID_TRACE; + $spanId = SpanContextValidator::INVALID_SPAN; + $this->isValid=false; + } + + $this->traceId = $traceId; + $this->spanId = $spanId; + $this->traceState = $traceState; + $this->isRemote = $isRemote; + $this->isSampled = ($traceFlags & TraceFlags::SAMPLED) === TraceFlags::SAMPLED; + $this->traceFlags = $traceFlags; + } + + public function getTraceId(): string + { + return $this->traceId; + } + + public function getTraceIdBinary(): string + { + return hex2bin($this->traceId); + } + + public function getSpanId(): string + { + return $this->spanId; + } + + public function getSpanIdBinary(): string + { + return hex2bin($this->spanId); + } + + public function getTraceState(): ?TraceStateInterface + { + return $this->traceState; + } + + public function isSampled(): bool + { + return $this->isSampled; + } + + public function isValid(): bool + { + return $this->isValid; + } + + public function isRemote(): bool + { + return $this->isRemote; + } + + public function getTraceFlags(): int + { + return $this->traceFlags; + } + + /** @inheritDoc */ + public static function createFromRemoteParent(string $traceId, string $spanId, int $traceFlags = TraceFlags::DEFAULT, ?TraceStateInterface $traceState = null): SpanContextInterface + { + return new self( + $traceId, + $spanId, + $traceFlags, + true, + $traceState, + ); + } + + /** @inheritDoc */ + public static function create(string $traceId, string $spanId, int $traceFlags = TraceFlags::DEFAULT, ?TraceStateInterface $traceState = null): SpanContextInterface + { + return new self( + $traceId, + $spanId, + $traceFlags, + false, + $traceState, + ); + } + + /** @inheritDoc */ + public static function getInvalid(): SpanContextInterface + { + if (null === self::$invalidContext) { + self::$invalidContext = self::create(SpanContextValidator::INVALID_TRACE, SpanContextValidator::INVALID_SPAN, 0); + } + + return self::$invalidContext; + } +} diff --git a/vendor/open-telemetry/api/Trace/SpanContextInterface.php b/vendor/open-telemetry/api/Trace/SpanContextInterface.php new file mode 100644 index 000000000..d15bc5987 --- /dev/null +++ b/vendor/open-telemetry/api/Trace/SpanContextInterface.php @@ -0,0 +1,28 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\API\Trace; + +/** + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/v1.6.1/specification/trace/api.md#spancontext + */ +interface SpanContextInterface +{ + public static function createFromRemoteParent(string $traceId, string $spanId, int $traceFlags = TraceFlags::DEFAULT, ?TraceStateInterface $traceState = null): SpanContextInterface; + public static function getInvalid(): SpanContextInterface; + public static function create(string $traceId, string $spanId, int $traceFlags = TraceFlags::DEFAULT, ?TraceStateInterface $traceState = null): SpanContextInterface; + + /** @psalm-mutation-free */ + public function getTraceId(): string; + public function getTraceIdBinary(): string; + + /** @psalm-mutation-free */ + public function getSpanId(): string; + public function getSpanIdBinary(): string; + public function getTraceFlags(): int; + public function getTraceState(): ?TraceStateInterface; + public function isValid(): bool; + public function isRemote(): bool; + public function isSampled(): bool; +} diff --git a/vendor/open-telemetry/api/Trace/SpanContextValidator.php b/vendor/open-telemetry/api/Trace/SpanContextValidator.php new file mode 100644 index 000000000..09b39f6d8 --- /dev/null +++ b/vendor/open-telemetry/api/Trace/SpanContextValidator.php @@ -0,0 +1,35 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\API\Trace; + +use function strlen; +use function strtolower; + +class SpanContextValidator +{ + public const VALID_SPAN = '/^[0-9a-f]{16}$/'; + public const VALID_TRACE = '/^[0-9a-f]{32}$/'; + public const INVALID_SPAN = '0000000000000000'; + public const INVALID_TRACE = '00000000000000000000000000000000'; + public const SPAN_LENGTH = 16; + public const TRACE_LENGTH = 32; + public const SPAN_LENGTH_BYTES = 8; + + /** + * @return bool Returns a value that indicates whether a trace id is valid + */ + public static function isValidTraceId(string $traceId): bool + { + return ctype_xdigit($traceId) && strlen($traceId) === self::TRACE_LENGTH && $traceId !== self::INVALID_TRACE && $traceId === strtolower($traceId); + } + + /** + * @return bool Returns a value that indicates whether a span id is valid + */ + public static function isValidSpanId(string $spanId): bool + { + return ctype_xdigit($spanId) && strlen($spanId) === self::SPAN_LENGTH && $spanId !== self::INVALID_SPAN && $spanId === strtolower($spanId); + } +} diff --git a/vendor/open-telemetry/api/Trace/SpanInterface.php b/vendor/open-telemetry/api/Trace/SpanInterface.php new file mode 100644 index 000000000..274a257ea --- /dev/null +++ b/vendor/open-telemetry/api/Trace/SpanInterface.php @@ -0,0 +1,96 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\API\Trace; + +use OpenTelemetry\Context\ContextInterface; +use OpenTelemetry\Context\ImplicitContextKeyedInterface; +use Throwable; + +/** + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/v1.6.1/specification/trace/api.md#span-operations + */ +interface SpanInterface extends ImplicitContextKeyedInterface +{ + /** + * Returns the {@see SpanInterface} from the provided *$context*, + * falling back on {@see SpanInterface::getInvalid()} if there is no span in the provided context. + */ + public static function fromContext(ContextInterface $context): SpanInterface; + + /** + * Returns the current {@see SpanInterface} from the current {@see ContextInterface}, + * falling back on {@see SpanInterface::getEmpty()} if there is no span in the current context. + */ + public static function getCurrent(): SpanInterface; + + /** + * Returns an invalid {@see SpanInterface} that is used when tracing is disabled, such s when there is no available SDK. + */ + public static function getInvalid(): SpanInterface; + + /** + * Returns a non-recording {@see SpanInterface} that hold the provided *$spanContext* but has no functionality. + * It will not be exported and al tracing operations are no-op, but can be used to propagate a valid {@see SpanContext} downstream. + * + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/v1.6.1/specification/trace/api.md#wrapping-a-spancontext-in-a-span + */ + public static function wrap(SpanContextInterface $spanContext): SpanInterface; + + /** + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/v1.6.1/specification/trace/api.md#get-context + */ + public function getContext(): SpanContextInterface; + + /** + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/v1.6.1/specification/trace/api.md#isrecording + */ + public function isRecording(): bool; + + /** + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/v1.6.1/specification/trace/api.md#set-attributes + * Adding attributes at span creation is preferred to calling setAttribute later, as samplers can only consider information + * already present during span creation + * @param non-empty-string $key + * @param bool|int|float|string|array|null $value Note: arrays MUST be homogeneous, i.e. it MUST NOT contain values of different types. + */ + public function setAttribute(string $key, $value): SpanInterface; + + /** + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/v1.6.1/specification/trace/api.md#set-attributes + * An attribute with a null key will be dropped, and an attribute with a null value will be dropped but also remove any existing + * attribute with the same key. + * @param iterable<non-empty-string, bool|int|float|string|array|null> $attributes + */ + public function setAttributes(iterable $attributes): SpanInterface; + + /** + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/v1.6.1/specification/trace/api.md#add-events + */ + public function addEvent(string $name, iterable $attributes = [], int $timestamp = null): SpanInterface; + + /** + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/v1.6.1/specification/trace/api.md#record-exception + */ + public function recordException(Throwable $exception, iterable $attributes = []): SpanInterface; + + /** + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/v1.6.1/specification/trace/api.md#updatename + * + * @param non-empty-string $name + */ + public function updateName(string $name): SpanInterface; + + /** + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/v1.6.1/specification/trace/api.md#set-status + * + * @psalm-param StatusCode::STATUS_* $code + */ + public function setStatus(string $code, string $description = null): SpanInterface; + + /** + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/v1.6.1/specification/trace/api.md#end + */ + public function end(int $endEpochNanos = null): void; +} diff --git a/vendor/open-telemetry/api/Trace/SpanKind.php b/vendor/open-telemetry/api/Trace/SpanKind.php new file mode 100644 index 000000000..f44339e00 --- /dev/null +++ b/vendor/open-telemetry/api/Trace/SpanKind.php @@ -0,0 +1,17 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\API\Trace; + +/** + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/v1.6.1/specification/trace/api.md#spankind + */ +interface SpanKind +{ + public const KIND_INTERNAL = 0; + public const KIND_CLIENT = 1; + public const KIND_SERVER = 2; + public const KIND_PRODUCER = 3; + public const KIND_CONSUMER = 4; +} diff --git a/vendor/open-telemetry/api/Trace/StatusCode.php b/vendor/open-telemetry/api/Trace/StatusCode.php new file mode 100644 index 000000000..0d95e96a5 --- /dev/null +++ b/vendor/open-telemetry/api/Trace/StatusCode.php @@ -0,0 +1,15 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\API\Trace; + +/** + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/v1.6.1/specification/trace/api.md#set-status + */ +interface StatusCode +{ + public const STATUS_UNSET = 'Unset'; + public const STATUS_OK = 'Ok'; + public const STATUS_ERROR = 'Error'; +} diff --git a/vendor/open-telemetry/api/Trace/TraceFlags.php b/vendor/open-telemetry/api/Trace/TraceFlags.php new file mode 100644 index 000000000..6adf72b1a --- /dev/null +++ b/vendor/open-telemetry/api/Trace/TraceFlags.php @@ -0,0 +1,11 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\API\Trace; + +interface TraceFlags +{ + public const SAMPLED = 0x01; + public const DEFAULT = 0x00; +} diff --git a/vendor/open-telemetry/api/Trace/TraceState.php b/vendor/open-telemetry/api/Trace/TraceState.php new file mode 100644 index 000000000..306a63322 --- /dev/null +++ b/vendor/open-telemetry/api/Trace/TraceState.php @@ -0,0 +1,190 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\API\Trace; + +use function array_reverse; +use OpenTelemetry\API\Behavior\LogsMessagesTrait; +use function strlen; + +class TraceState implements TraceStateInterface +{ + use LogsMessagesTrait; + + public const MAX_LIST_MEMBERS = 32; //@see https://www.w3.org/TR/trace-context/#tracestate-header-field-values + public const MAX_COMBINED_LENGTH = 512; //@see https://www.w3.org/TR/trace-context/#tracestate-limits + public const LIST_MEMBERS_SEPARATOR = ','; + public const LIST_MEMBER_KEY_VALUE_SPLITTER = '='; + private const VALID_KEY_CHAR_RANGE = '[_0-9a-z-*\/]'; + private const VALID_KEY = '[a-z]' . self::VALID_KEY_CHAR_RANGE . '{0,255}'; + private const VALID_VENDOR_KEY = '[a-z0-9]' . self::VALID_KEY_CHAR_RANGE . '{0,240}@[a-z]' . self::VALID_KEY_CHAR_RANGE . '{0,13}'; + private const VALID_KEY_REGEX = '/^(?:' . self::VALID_KEY . '|' . self::VALID_VENDOR_KEY . ')$/'; + private const VALID_VALUE_BASE_REGEX = '/^[ -~]{0,255}[!-~]$/'; + private const INVALID_VALUE_COMMA_EQUAL_REGEX = '/,|=/'; + + /** + * @var string[] + */ + private array $traceState = []; + + public function __construct(string $rawTracestate = null) + { + if ($rawTracestate === null || trim($rawTracestate) === '') { + return; + } + $this->traceState = $this->parse($rawTracestate); + } + + /** + * {@inheritdoc} + */ + public function with(string $key, string $value): TraceStateInterface + { + $clonedTracestate = clone $this; + + if ($this->validateKey($key) && $this->validateValue($value)) { + + /* + * Only one entry per key is allowed. In this case we need to overwrite the vendor entry + * upon reentry to the tracing system and ensure the updated entry is at the beginning of + * the list. This means we place it the back for now and it will be at the beginning once + * we reverse the order back during __toString(). + */ + if (array_key_exists($key, $clonedTracestate->traceState)) { + unset($clonedTracestate->traceState[$key]); + } + + // Add new or updated entry to the back of the list. + $clonedTracestate->traceState[$key] = $value; + } else { + self::logWarning('Invalid tracetrace key/value for: ' . $key); + } + + return $clonedTracestate; + } + + /** + * {@inheritdoc} + */ + public function without(string $key): TraceStateInterface + { + $clonedTracestate = clone $this; + + if ($key !== '') { + unset($clonedTracestate->traceState[$key]); + } + + return $clonedTracestate; + } + + /** + * {@inheritdoc} + */ + public function get(string $key): ?string + { + return $this->traceState[$key] ?? null; + } + + /** + * {@inheritdoc} + */ + public function getListMemberCount(): int + { + return count($this->traceState); + } + + /** + * {@inheritdoc} + */ + public function __toString(): string + { + if ($this->traceState === []) { + return ''; + } + $traceStateString=''; + foreach (array_reverse($this->traceState) as $k => $v) { + $traceStateString .=$k . self::LIST_MEMBER_KEY_VALUE_SPLITTER . $v . self::LIST_MEMBERS_SEPARATOR; + } + + return rtrim($traceStateString, ','); + } + + /** + * Parse the raw tracestate header into the TraceState object. Since new or updated entries must + * be added to the beginning of the list, the key-value pairs in the TraceState object will be + * stored in reverse order. This ensures new entries added to the TraceState object are at the + * beginning when we reverse the order back again while building the final tracestate header. + * + * Ex: + * tracestate = 'vendor1=value1,vendor2=value2' + * + * || + * \/ + * + * $this->tracestate = ['vendor2' => 'value2' ,'vendor1' => 'value1'] + * + */ + private function parse(string $rawTracestate): array + { + if (strlen($rawTracestate) > self::MAX_COMBINED_LENGTH) { + self::logWarning('tracestate discarded, exceeds max combined length: ' . self::MAX_COMBINED_LENGTH); + + return []; + } + $parsedTracestate = []; + $listMembers = explode(self::LIST_MEMBERS_SEPARATOR, $rawTracestate); + + if (count($listMembers) > self::MAX_LIST_MEMBERS) { + self::logWarning('tracestate discarded, too many members'); + + return []; + } + + foreach ($listMembers as $listMember) { + $vendor = explode(self::LIST_MEMBER_KEY_VALUE_SPLITTER, trim($listMember)); + + // There should only be one list-member per vendor separated by '=' + if (count($vendor) !== 2 || !$this->validateKey($vendor[0]) || !$this->validateValue($vendor[1])) { + self::logWarning('tracestate discarded, invalid member: ' . $listMember); + + return []; + } + $parsedTracestate[$vendor[0]] = $vendor[1]; + } + + /* + * Reversing the tracestate ensures the new entries added to the TraceState object are at + * the beginning when we reverse it back during __toString(). + */ + return array_reverse($parsedTracestate); + } + + /** + * The Key is opaque string that is an identifier for a vendor. It can be up + * to 256 characters and MUST begin with a lowercase letter or a digit, and can + * only contain lowercase letters (a-z), digits (0-9), underscores (_), dashes (-), + * asterisks (*), and forward slashes (/). For multi-tenant vendor scenarios, an at + * sign (@) can be used to prefix the vendor name. Vendors SHOULD set the tenant ID + * at the beginning of the key. + * + * @see https://www.w3.org/TR/trace-context/#key + */ + private function validateKey(string $key): bool + { + return preg_match(self::VALID_KEY_REGEX, $key) !== 0; + } + + /** + * The value is an opaque string containing up to 256 printable ASCII [RFC0020] + * characters (i.e., the range 0x20 to 0x7E) except comma (,) and (=). Note that + * this also excludes tabs, newlines, carriage returns, etc. + * + * @see https://www.w3.org/TR/trace-context/#value + */ + private function validateValue(string $key): bool + { + return (preg_match(self::VALID_VALUE_BASE_REGEX, $key) !== 0) + && (preg_match(self::INVALID_VALUE_COMMA_EQUAL_REGEX, $key) === 0); + } +} diff --git a/vendor/open-telemetry/api/Trace/TraceStateInterface.php b/vendor/open-telemetry/api/Trace/TraceStateInterface.php new file mode 100644 index 000000000..79d4e0299 --- /dev/null +++ b/vendor/open-telemetry/api/Trace/TraceStateInterface.php @@ -0,0 +1,61 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\API\Trace; + +/** + * TraceState parses and stores the tracestate header as an immutable list of string + * key/value pairs. It provides the following operations following the rules described + * in the W3C Trace Context specification: + * - Get value for a given key + * - Add a new key/value pair + * - Update an existing value for a given key + * - Delete a key/value pair + * + * All mutating operations return a new TraceState with the modifications applied. + * + * @see https://www.w3.org/TR/trace-context/#tracestate-header + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/trace/api.md#tracestate + */ +interface TraceStateInterface +{ + /** + * Return a new TraceState object that inherits from this TraceState + * and contains the given key value pair. + * + * @param string $key + * @param string $value + * @return TraceStateInterface + */ + public function with(string $key, string $value): TraceStateInterface; + + /** + * Return a new TraceState object that inherits from this TraceState + * without the given key value pair. + * + * @param string $key + * @return TraceStateInterface + */ + public function without(string $key): TraceStateInterface; + + /** + * Return the value of a given key from this TraceState if it exists + * + * @param string $key + * @return string|null + */ + public function get(string $key): ?string; + + /** + * Get the list-member count in this TraceState + * + * @return int + */ + public function getListMemberCount(): int; + + /** + * Returns a string representation of this TraceSate + */ + public function __toString(): string; +} diff --git a/vendor/open-telemetry/api/Trace/TracerInterface.php b/vendor/open-telemetry/api/Trace/TracerInterface.php new file mode 100644 index 000000000..1293a6642 --- /dev/null +++ b/vendor/open-telemetry/api/Trace/TracerInterface.php @@ -0,0 +1,11 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\API\Trace; + +interface TracerInterface +{ + /** @param non-empty-string $spanName */ + public function spanBuilder(string $spanName): SpanBuilderInterface; +} diff --git a/vendor/open-telemetry/api/Trace/TracerProviderInterface.php b/vendor/open-telemetry/api/Trace/TracerProviderInterface.php new file mode 100644 index 000000000..9f5d20759 --- /dev/null +++ b/vendor/open-telemetry/api/Trace/TracerProviderInterface.php @@ -0,0 +1,19 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\API\Trace; + +/** @see https://github.com/open-telemetry/opentelemetry-specification/blob/v1.7.0/specification/trace/api.md#tracerprovider */ +interface TracerProviderInterface +{ + /** + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/v1.7.0/specification/trace/api.md#get-a-tracer + */ + public function getTracer( + string $name, + ?string $version = null, + ?string $schemaUrl = null, + iterable $attributes = [] + ): TracerInterface; +} diff --git a/vendor/open-telemetry/api/Trace/functions.php b/vendor/open-telemetry/api/Trace/functions.php new file mode 100644 index 000000000..79f730717 --- /dev/null +++ b/vendor/open-telemetry/api/Trace/functions.php @@ -0,0 +1,44 @@ +<?php + +declare(strict_types=1); + +namespace OpenTelemetry\API\Trace; + +use Closure; +use Throwable; + +/** + * Executes the given closure within the provided span. + * + * The span will be ended. + * + * @template R + * @param SpanInterface $span span to enclose the closure with + * @param Closure(...): R $closure closure to invoke + * @param iterable<int|string, mixed> $args arguments to provide to the closure + * @return R result of the closure invocation + * + * @phpstan-ignore-next-line + */ +function trace(SpanInterface $span, Closure $closure, iterable $args = []) +{ + $s = $span; + $c = $closure; + $a = $args; + unset($span, $closure, $args); + + $scope = $s->activate(); + + try { + /** @psalm-suppress InvalidArgument */ + return $c(...$a, ...($a = [])); + } catch (Throwable $e) { + $s->setStatus(StatusCode::STATUS_ERROR, $e->getMessage()); + $s->recordException($e, ['exception.escaped' => true]); + + throw $e; + } finally { + $scope->detach(); + $s->end(); + } +} diff --git a/vendor/open-telemetry/api/composer.json b/vendor/open-telemetry/api/composer.json new file mode 100644 index 000000000..39acaec47 --- /dev/null +++ b/vendor/open-telemetry/api/composer.json @@ -0,0 +1,40 @@ +{ + "name": "open-telemetry/api", + "description": "API for OpenTelemetry PHP.", + "keywords": ["opentelemetry", "otel", "metrics", "tracing", "logging", "apm", "api"], + "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", + "open-telemetry/context": "^1.0", + "psr/log": "^1.1|^2.0|^3.0", + "symfony/polyfill-php80": "^1.26", + "symfony/polyfill-php81": "^1.26", + "symfony/polyfill-php82": "^1.26" + }, + "autoload": { + "psr-4": { + "OpenTelemetry\\API\\": "." + }, + "files": [ + "Trace/functions.php" + ] + }, + "extra": { + "branch-alias": { + "dev-main": "1.0.x-dev" + } + } +} |