From cdd7ad020e165fe680703b6d3319b908b682fb7a Mon Sep 17 00:00:00 2001 From: Andrew Dolgov Date: Fri, 20 Oct 2023 17:12:29 +0300 Subject: jaeger-client -> opentelemetry --- vendor/open-telemetry/context/Context.php | 131 +++++++++++++++++++++ vendor/open-telemetry/context/ContextInterface.php | 86 ++++++++++++++ vendor/open-telemetry/context/ContextKey.php | 23 ++++ .../open-telemetry/context/ContextKeyInterface.php | 12 ++ vendor/open-telemetry/context/ContextKeys.php | 25 ++++ vendor/open-telemetry/context/ContextStorage.php | 57 +++++++++ .../open-telemetry/context/ContextStorageHead.php | 19 +++ .../context/ContextStorageInterface.php | 32 +++++ .../open-telemetry/context/ContextStorageNode.php | 92 +++++++++++++++ .../context/ContextStorageScopeInterface.php | 22 ++++ vendor/open-telemetry/context/DebugScope.php | 94 +++++++++++++++ .../context/ExecutionContextAwareInterface.php | 23 ++++ .../context/FiberBoundContextStorage.php | 84 +++++++++++++ .../context/FiberBoundContextStorageScope.php | 67 +++++++++++ .../context/ImplicitContextKeyedInterface.php | 32 +++++ .../Propagation/ArrayAccessGetterSetter.php | 129 ++++++++++++++++++++ .../context/Propagation/MultiTextMapPropagator.php | 83 +++++++++++++ .../context/Propagation/NoopTextMapPropagator.php | 36 ++++++ .../Propagation/PropagationGetterInterface.php | 25 ++++ .../Propagation/PropagationSetterInterface.php | 16 +++ .../SanitizeCombinedHeadersPropagationGetter.php | 46 ++++++++ .../Propagation/TextMapPropagatorInterface.php | 40 +++++++ vendor/open-telemetry/context/README.md | 63 ++++++++++ vendor/open-telemetry/context/ScopeInterface.php | 32 +++++ .../open-telemetry/context/ZendObserverFiber.php | 67 +++++++++++ vendor/open-telemetry/context/composer.json | 41 +++++++ .../context/fiber/initialize_fiber_handler.php | 20 ++++ .../context/fiber/zend_observer_fiber.h | 9 ++ 28 files changed, 1406 insertions(+) create mode 100644 vendor/open-telemetry/context/Context.php create mode 100644 vendor/open-telemetry/context/ContextInterface.php create mode 100644 vendor/open-telemetry/context/ContextKey.php create mode 100644 vendor/open-telemetry/context/ContextKeyInterface.php create mode 100644 vendor/open-telemetry/context/ContextKeys.php create mode 100644 vendor/open-telemetry/context/ContextStorage.php create mode 100644 vendor/open-telemetry/context/ContextStorageHead.php create mode 100644 vendor/open-telemetry/context/ContextStorageInterface.php create mode 100644 vendor/open-telemetry/context/ContextStorageNode.php create mode 100644 vendor/open-telemetry/context/ContextStorageScopeInterface.php create mode 100644 vendor/open-telemetry/context/DebugScope.php create mode 100644 vendor/open-telemetry/context/ExecutionContextAwareInterface.php create mode 100644 vendor/open-telemetry/context/FiberBoundContextStorage.php create mode 100644 vendor/open-telemetry/context/FiberBoundContextStorageScope.php create mode 100644 vendor/open-telemetry/context/ImplicitContextKeyedInterface.php create mode 100644 vendor/open-telemetry/context/Propagation/ArrayAccessGetterSetter.php create mode 100644 vendor/open-telemetry/context/Propagation/MultiTextMapPropagator.php create mode 100644 vendor/open-telemetry/context/Propagation/NoopTextMapPropagator.php create mode 100644 vendor/open-telemetry/context/Propagation/PropagationGetterInterface.php create mode 100644 vendor/open-telemetry/context/Propagation/PropagationSetterInterface.php create mode 100644 vendor/open-telemetry/context/Propagation/SanitizeCombinedHeadersPropagationGetter.php create mode 100644 vendor/open-telemetry/context/Propagation/TextMapPropagatorInterface.php create mode 100644 vendor/open-telemetry/context/README.md create mode 100644 vendor/open-telemetry/context/ScopeInterface.php create mode 100644 vendor/open-telemetry/context/ZendObserverFiber.php create mode 100644 vendor/open-telemetry/context/composer.json create mode 100644 vendor/open-telemetry/context/fiber/initialize_fiber_handler.php create mode 100644 vendor/open-telemetry/context/fiber/zend_observer_fiber.h (limited to 'vendor/open-telemetry/context') diff --git a/vendor/open-telemetry/context/Context.php b/vendor/open-telemetry/context/Context.php new file mode 100644 index 000000000..32b0162a3 --- /dev/null +++ b/vendor/open-telemetry/context/Context.php @@ -0,0 +1,131 @@ + */ + private array $context = []; + /** @var array */ + private array $contextKeys = []; + + private function __construct() + { + self::$spanContextKey = ContextKeys::span(); + } + + public static function createKey(string $key): ContextKeyInterface + { + return new ContextKey($key); + } + + /** + * @param ContextStorageInterface&ExecutionContextAwareInterface $storage + */ + public static function setStorage(ContextStorageInterface $storage): void + { + self::$storage = $storage; + } + + /** + * @return ContextStorageInterface&ExecutionContextAwareInterface + */ + public static function storage(): ContextStorageInterface + { + /** @psalm-suppress RedundantPropertyInitializationCheck */ + return self::$storage ??= new ContextStorage(); + } + + /** + * @param ContextInterface|false|null $context + * + * @internal OpenTelemetry + */ + public static function resolve($context, ?ContextStorageInterface $contextStorage = null): ContextInterface + { + return $context + ?? ($contextStorage ?? self::storage())->current() + ?: self::getRoot(); + } + + /** + * @internal + */ + public static function getRoot(): ContextInterface + { + static $empty; + + return $empty ??= new self(); + } + + public static function getCurrent(): ContextInterface + { + return self::storage()->current(); + } + + public function activate(): ScopeInterface + { + $scope = self::storage()->attach($this); + /** @psalm-suppress RedundantCondition */ + assert((bool) $scope = new DebugScope($scope)); + + return $scope; + } + + public function withContextValue(ImplicitContextKeyedInterface $value): ContextInterface + { + return $value->storeInContext($this); + } + + public function with(ContextKeyInterface $key, $value): self + { + if ($this->get($key) === $value) { + return $this; + } + + $self = clone $this; + + if ($key === self::$spanContextKey) { + $self->span = $value; // @phan-suppress-current-line PhanTypeMismatchPropertyReal + + return $self; + } + + $id = spl_object_id($key); + if ($value !== null) { + $self->context[$id] = $value; + $self->contextKeys[$id] ??= $key; + } else { + unset( + $self->context[$id], + $self->contextKeys[$id], + ); + } + + return $self; + } + + public function get(ContextKeyInterface $key) + { + if ($key === self::$spanContextKey) { + /** @psalm-suppress InvalidReturnStatement */ + return $this->span; + } + + return $this->context[spl_object_id($key)] ?? null; + } +} diff --git a/vendor/open-telemetry/context/ContextInterface.php b/vendor/open-telemetry/context/ContextInterface.php new file mode 100644 index 000000000..17a3fb9a2 --- /dev/null +++ b/vendor/open-telemetry/context/ContextInterface.php @@ -0,0 +1,86 @@ +activate(); + * try { + * // ... + * } finally { + * $scope->detach(); + * } + * ``` + * + * @return ScopeInterface scope to detach the context and restore the previous + * context + * + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/context/README.md#attach-context + */ + public function activate(): ScopeInterface; + + /** + * Returns a context with the given key set to the given value. + * + * @template T + * @param ContextKeyInterface $key key to set + * @param T|null $value value to set + * @return ContextInterface a context with the given key set to `$value` + * + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/context/README.md#set-value + */ + public function with(ContextKeyInterface $key, $value): ContextInterface; + + /** + * Returns a context with the given value set. + * + * @param ImplicitContextKeyedInterface $value value to set + * @return ContextInterface a context with the given `$value` + * + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/context/README.md#set-value + */ + public function withContextValue(ImplicitContextKeyedInterface $value): ContextInterface; + + /** + * Returns the value assigned to the given key. + * + * @template T + * @param ContextKeyInterface $key key to get + * @return T|null value assigned to `$key`, or null if no such value exists + * + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/context/README.md#get-value + */ + public function get(ContextKeyInterface $key); +} diff --git a/vendor/open-telemetry/context/ContextKey.php b/vendor/open-telemetry/context/ContextKey.php new file mode 100644 index 000000000..f7450249e --- /dev/null +++ b/vendor/open-telemetry/context/ContextKey.php @@ -0,0 +1,23 @@ +name = $name; + } + + public function name(): ?string + { + return $this->name; + } +} diff --git a/vendor/open-telemetry/context/ContextKeyInterface.php b/vendor/open-telemetry/context/ContextKeyInterface.php new file mode 100644 index 000000000..b3ad00814 --- /dev/null +++ b/vendor/open-telemetry/context/ContextKeyInterface.php @@ -0,0 +1,12 @@ + */ + private array $forks = []; + + public function __construct() + { + $this->current = $this->main = new ContextStorageHead($this); + } + + public function fork($id): void + { + $this->forks[$id] = clone $this->current; + } + + public function switch($id): void + { + $this->current = $this->forks[$id] ?? $this->main; + } + + public function destroy($id): void + { + unset($this->forks[$id]); + } + + public function scope(): ?ContextStorageScopeInterface + { + return ($this->current->node->head ?? null) === $this->current + ? $this->current->node + : null; + } + + public function current(): ContextInterface + { + return $this->current->node->context ?? Context::getRoot(); + } + + public function attach(ContextInterface $context): ContextStorageScopeInterface + { + return $this->current->node = new ContextStorageNode($context, $this->current, $this->current->node); + } + + private function __clone() + { + } +} diff --git a/vendor/open-telemetry/context/ContextStorageHead.php b/vendor/open-telemetry/context/ContextStorageHead.php new file mode 100644 index 000000000..3cc4d7181 --- /dev/null +++ b/vendor/open-telemetry/context/ContextStorageHead.php @@ -0,0 +1,19 @@ +storage = $storage; + } +} diff --git a/vendor/open-telemetry/context/ContextStorageInterface.php b/vendor/open-telemetry/context/ContextStorageInterface.php new file mode 100644 index 000000000..e5a105074 --- /dev/null +++ b/vendor/open-telemetry/context/ContextStorageInterface.php @@ -0,0 +1,32 @@ +context = $context; + $this->head = $head; + $this->previous = $previous; + } + + public function offsetExists($offset): bool + { + return isset($this->localStorage[$offset]); + } + + /** + * @phan-suppress PhanUndeclaredClassAttribute + */ + #[\ReturnTypeWillChange] + public function offsetGet($offset) + { + return $this->localStorage[$offset]; + } + + public function offsetSet($offset, $value): void + { + $this->localStorage[$offset] = $value; + } + + public function offsetUnset($offset): void + { + unset($this->localStorage[$offset]); + } + + public function context(): ContextInterface + { + return $this->context; + } + + public function detach(): int + { + $flags = 0; + if ($this->head !== $this->head->storage->current) { + $flags |= ScopeInterface::INACTIVE; + } + + if ($this === $this->head->node) { + assert($this->previous !== $this); + $this->head->node = $this->previous; + $this->previous = $this; + + return $flags; + } + + if ($this->previous === $this) { + return $flags | ScopeInterface::DETACHED; + } + + assert($this->head->node !== null); + for ($n = $this->head->node, $depth = 1; + $n->previous !== $this; + $n = $n->previous, $depth++) { + assert($n->previous !== null); + } + $n->previous = $this->previous; + $this->previous = $this; + + return $flags | ScopeInterface::MISMATCH | $depth; + } + + private function __clone() + { + } +} diff --git a/vendor/open-telemetry/context/ContextStorageScopeInterface.php b/vendor/open-telemetry/context/ContextStorageScopeInterface.php new file mode 100644 index 000000000..5fe58d6eb --- /dev/null +++ b/vendor/open-telemetry/context/ContextStorageScopeInterface.php @@ -0,0 +1,22 @@ +scope = $node; + $this->scope[self::DEBUG_TRACE_CREATE] = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS); + } + + public function detach(): int + { + $this->scope[self::DEBUG_TRACE_DETACH] ??= debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS); + + $flags = $this->scope->detach(); + + if (($flags & ScopeInterface::DETACHED) !== 0) { + trigger_error(sprintf( + 'Scope: unexpected call to Scope::detach() for scope #%d, scope was already detached %s', + spl_object_id($this), + self::formatBacktrace($this->scope[self::DEBUG_TRACE_DETACH]), + )); + } elseif (($flags & ScopeInterface::MISMATCH) !== 0) { + trigger_error(sprintf( + 'Scope: unexpected call to Scope::detach() for scope #%d, scope successfully detached but another scope should have been detached first', + spl_object_id($this), + )); + } elseif (($flags & ScopeInterface::INACTIVE) !== 0) { + trigger_error(sprintf( + 'Scope: unexpected call to Scope::detach() for scope #%d, scope successfully detached from different execution context', + spl_object_id($this), + )); + } + + return $flags; + } + + public function __destruct() + { + if (!isset($this->scope[self::DEBUG_TRACE_DETACH])) { + trigger_error(sprintf( + 'Scope: missing call to Scope::detach() for scope #%d, created %s', + spl_object_id($this->scope), + self::formatBacktrace($this->scope[self::DEBUG_TRACE_CREATE]), + )); + } + } + + private static function formatBacktrace(array $trace): string + { + $s = ''; + for ($i = 0, $n = count($trace) + 1; ++$i < $n;) { + $s .= "\n\t"; + $s .= 'at '; + if (isset($trace[$i]['class'])) { + $s .= strtr($trace[$i]['class'], ['\\' => '.']); + $s .= '.'; + } + $s .= strtr($trace[$i]['function'] ?? '{main}', ['\\' => '.']); + $s .= '('; + if (isset($trace[$i - 1]['file'])) { + $s .= basename($trace[$i - 1]['file']); + if (isset($trace[$i - 1]['line'])) { + $s .= ':'; + $s .= $trace[$i - 1]['line']; + } + } else { + $s .= 'Unknown Source'; + } + $s .= ')'; + } + + return $s . "\n"; + } +} diff --git a/vendor/open-telemetry/context/ExecutionContextAwareInterface.php b/vendor/open-telemetry/context/ExecutionContextAwareInterface.php new file mode 100644 index 000000000..3a955bfae --- /dev/null +++ b/vendor/open-telemetry/context/ExecutionContextAwareInterface.php @@ -0,0 +1,23 @@ +storage = $storage; + } + + public function fork($id): void + { + $this->storage->fork($id); + } + + public function switch($id): void + { + $this->storage->switch($id); + } + + public function destroy($id): void + { + $this->storage->destroy($id); + } + + public function scope(): ?ContextStorageScopeInterface + { + $this->checkFiberMismatch(); + + if (($scope = $this->storage->scope()) === null) { + return null; + } + + return new FiberBoundContextStorageScope($scope); + } + + public function current(): ContextInterface + { + $this->checkFiberMismatch(); + + return $this->storage->current(); + } + + public function attach(ContextInterface $context): ContextStorageScopeInterface + { + $scope = $this->storage->attach($context); + assert(class_exists(Fiber::class, false)); + $scope[Fiber::class] = Fiber::getCurrent(); + + return new FiberBoundContextStorageScope($scope); + } + + private function checkFiberMismatch(): void + { + $scope = $this->storage->scope(); + assert(class_exists(Fiber::class, false)); + if ($scope && $scope[Fiber::class] !== Fiber::getCurrent()) { + trigger_error('Fiber context switching not supported', E_USER_WARNING); + } + } +} diff --git a/vendor/open-telemetry/context/FiberBoundContextStorageScope.php b/vendor/open-telemetry/context/FiberBoundContextStorageScope.php new file mode 100644 index 000000000..647552244 --- /dev/null +++ b/vendor/open-telemetry/context/FiberBoundContextStorageScope.php @@ -0,0 +1,67 @@ +scope = $scope; + } + + public function offsetExists($offset): bool + { + return $this->scope->offsetExists($offset); + } + + /** + * @phan-suppress PhanUndeclaredClassAttribute + */ + #[\ReturnTypeWillChange] + public function offsetGet($offset) + { + return $this->scope->offsetGet($offset); + } + + public function offsetSet($offset, $value): void + { + $this->scope->offsetSet($offset, $value); + } + + public function offsetUnset($offset): void + { + $this->scope->offsetUnset($offset); + } + + public function context(): ContextInterface + { + return $this->scope->context(); + } + + public function detach(): int + { + $flags = $this->scope->detach(); + assert(class_exists(Fiber::class, false)); + if ($this->scope[Fiber::class] !== Fiber::getCurrent()) { + $flags |= ScopeInterface::INACTIVE; + } + + return $flags; + } +} diff --git a/vendor/open-telemetry/context/ImplicitContextKeyedInterface.php b/vendor/open-telemetry/context/ImplicitContextKeyedInterface.php new file mode 100644 index 000000000..0af93122c --- /dev/null +++ b/vendor/open-telemetry/context/ImplicitContextKeyedInterface.php @@ -0,0 +1,32 @@ +isSupportedCarrier($carrier)) { + $keys = []; + foreach ($carrier as $key => $_) { + $keys[] = (string) $key; + } + + return $keys; + } + + throw new InvalidArgumentException( + sprintf( + 'Unsupported carrier type: %s.', + is_object($carrier) ? get_class($carrier) : gettype($carrier), + ) + ); + } + + /** {@inheritdoc} */ + public function get($carrier, string $key): ?string + { + if ($this->isSupportedCarrier($carrier)) { + $value = $carrier[$this->resolveKey($carrier, $key)] ?? null; + if (is_array($value) && $value) { + $value = $value[array_key_first($value)]; + } + + return is_string($value) + ? $value + : null; + } + + throw new InvalidArgumentException( + sprintf( + 'Unsupported carrier type: %s. Unable to get value associated with key:%s', + is_object($carrier) ? get_class($carrier) : gettype($carrier), + $key + ) + ); + } + + /** {@inheritdoc} */ + public function set(&$carrier, string $key, string $value): void + { + if ($key === '') { + throw new InvalidArgumentException('Unable to set value with an empty key'); + } + if ($this->isSupportedCarrier($carrier)) { + if (($r = $this->resolveKey($carrier, $key)) !== $key) { + unset($carrier[$r]); + } + + $carrier[$key] = $value; + + return; + } + + throw new InvalidArgumentException( + sprintf( + 'Unsupported carrier type: %s. Unable to set value associated with key:%s', + is_object($carrier) ? get_class($carrier) : gettype($carrier), + $key + ) + ); + } + + private function isSupportedCarrier($carrier): bool + { + return is_array($carrier) || $carrier instanceof ArrayAccess && $carrier instanceof Traversable; + } + + private function resolveKey($carrier, string $key): string + { + if (isset($carrier[$key])) { + return $key; + } + + foreach ($carrier as $k => $_) { + $k = (string) $k; + if (strcasecmp($k, $key) === 0) { + return $k; + } + } + + return $key; + } +} diff --git a/vendor/open-telemetry/context/Propagation/MultiTextMapPropagator.php b/vendor/open-telemetry/context/Propagation/MultiTextMapPropagator.php new file mode 100644 index 000000000..075fe98fe --- /dev/null +++ b/vendor/open-telemetry/context/Propagation/MultiTextMapPropagator.php @@ -0,0 +1,83 @@ + + */ + private array $propagators = []; + + /** + * @readonly + * + * @var list + */ + private array $fields; + + /** + * @no-named-arguments + * + * @param list $propagators + */ + public function __construct(array $propagators) + { + $this->propagators = $propagators; + $this->fields = $this->extractFields($propagators); + } + + public function fields(): array + { + return $this->fields; + } + + public function inject(&$carrier, PropagationSetterInterface $setter = null, ContextInterface $context = null): void + { + foreach ($this->propagators as $propagator) { + $propagator->inject($carrier, $setter, $context); + } + } + + public function extract($carrier, PropagationGetterInterface $getter = null, ContextInterface $context = null): ContextInterface + { + $context ??= Context::getCurrent(); + + foreach ($this->propagators as $propagator) { + $context = $propagator->extract($carrier, $getter, $context); + } + + return $context; + } + + /** + * @param list $propagators + * @return list + */ + private function extractFields(array $propagators): array + { + return array_values( + array_unique( + // Phan seems to struggle here with the variadic argument + // @phan-suppress-next-line PhanParamTooFewInternalUnpack + array_merge( + ...array_map( + static fn (TextMapPropagatorInterface $propagator) => $propagator->fields(), + $propagators + ) + ) + ) + ); + } +} diff --git a/vendor/open-telemetry/context/Propagation/NoopTextMapPropagator.php b/vendor/open-telemetry/context/Propagation/NoopTextMapPropagator.php new file mode 100644 index 000000000..c408cfc79 --- /dev/null +++ b/vendor/open-telemetry/context/Propagation/NoopTextMapPropagator.php @@ -0,0 +1,36 @@ + + */ + public function keys($carrier): array; + + /** + * Gets the value of a given key from a carrier. + */ + public function get($carrier, string $key) : ?string; +} diff --git a/vendor/open-telemetry/context/Propagation/PropagationSetterInterface.php b/vendor/open-telemetry/context/Propagation/PropagationSetterInterface.php new file mode 100644 index 000000000..75e205628 --- /dev/null +++ b/vendor/open-telemetry/context/Propagation/PropagationSetterInterface.php @@ -0,0 +1,16 @@ +getter = $getter; + } + + public function keys($carrier): array + { + return $this->getter->keys($carrier); + } + + public function get($carrier, string $key): ?string + { + $value = $this->getter->get($carrier, $key); + if ($value === null) { + return null; + } + + return preg_replace( + [self::SERVER_CONCAT_HEADERS_REGEX, self::TRAILING_LEADING_SEPARATOR_REGEX], + [self::LIST_MEMBERS_SEPARATOR], + $value, + ); + } +} diff --git a/vendor/open-telemetry/context/Propagation/TextMapPropagatorInterface.php b/vendor/open-telemetry/context/Propagation/TextMapPropagatorInterface.php new file mode 100644 index 000000000..fdf2d5141 --- /dev/null +++ b/vendor/open-telemetry/context/Propagation/TextMapPropagatorInterface.php @@ -0,0 +1,40 @@ + + */ + public function fields() : array; + + /** + * Injects specific values from the provided {@see ContextInterface} into the provided carrier + * via an {@see PropagationSetterInterface}. + * + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/v1.6.1/specification/context/api-propagators.md#textmap-inject + * + * @param mixed $carrier + */ + public function inject(&$carrier, PropagationSetterInterface $setter = null, ContextInterface $context = null): void; + + /** + * Extracts specific values from the provided carrier into the provided {@see ContextInterface} + * via an {@see PropagationGetterInterface}. + * + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/v1.6.1/specification/context/api-propagators.md#textmap-extract + */ + public function extract($carrier, PropagationGetterInterface $getter = null, ContextInterface $context = null): ContextInterface; +} diff --git a/vendor/open-telemetry/context/README.md b/vendor/open-telemetry/context/README.md new file mode 100644 index 000000000..4dfe0e23f --- /dev/null +++ b/vendor/open-telemetry/context/README.md @@ -0,0 +1,63 @@ +[![Releases](https://img.shields.io/badge/releases-purple)](https://github.com/opentelemetry-php/context/releases) +[![Source](https://img.shields.io/badge/source-context-green)](https://github.com/open-telemetry/opentelemetry-php/tree/main/src/Context) +[![Mirror](https://img.shields.io/badge/mirror-opentelemetry--php:context-blue)](https://github.com/opentelemetry-php/context) +[![Latest Version](http://poser.pugx.org/open-telemetry/context/v/unstable)](https://packagist.org/packages/open-telemetry/context/) +[![Stable](http://poser.pugx.org/open-telemetry/context/v/stable)](https://packagist.org/packages/open-telemetry/context/) + +# OpenTelemetry Context + +Immutable execution scoped propagation mechanism, for further details see [opentelemetry-specification][1]. + +## Installation + +```shell +composer require open-telemetry/context +``` + +## Usage + +### Implicit propagation + +```php +$context = Context::getCurrent(); +// modify context +$scope = $context->activate(); +try { + // run within new context +} finally { + $scope->detach(); +} +``` + +It is recommended to use a `try-finally` statement after `::activate()` to ensure that the created scope is properly `::detach()`ed. + +## Async applications + +### Fiber support + +Requires `PHP >= 8.1`, an NTS build, `ext-ffi`, and setting the environment variable `OTEL_PHP_FIBERS_ENABLED` to a truthy value. Additionally `vendor/autoload.php` has to be preloaded for non-CLI SAPIs if [`ffi.enable`](https://www.php.net/manual/en/ffi.configuration.php#ini.ffi.enable) is set to `preload`. + +### Event loops + +Event loops have to restore the original context on callback execution. A basic implementation could look like the following, though implementations should avoid keeping unnecessary references to arguments if possible: + +```php +function bindContext(Closure $closure): Closure { + $context = Context::getCurrent(); + return static function (mixed ...$args) use ($closure, $context): mixed { + $scope = $context->activate(); + try { + return $closure(...$args); + } finally { + $scope->detach(); + } + }; +} +``` + +## 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). + +[1]: https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/context/README.md#context diff --git a/vendor/open-telemetry/context/ScopeInterface.php b/vendor/open-telemetry/context/ScopeInterface.php new file mode 100644 index 000000000..05319b8fc --- /dev/null +++ b/vendor/open-telemetry/context/ScopeInterface.php @@ -0,0 +1,32 @@ += 8.1, an NTS build, and the FFI extension'); + + return false; + } + + try { + $fibers = FFI::scope('OTEL_ZEND_OBSERVER_FIBER'); + } catch (FFI\Exception $e) { + try { + $fibers = FFI::load(__DIR__ . '/fiber/zend_observer_fiber.h'); + } catch (FFI\Exception $e) { + trigger_error(sprintf('Context: Fiber context switching not supported, %s', $e->getMessage())); + + return false; + } + } + + $fibers->zend_observer_fiber_init_register(static fn (int $initializing) => Context::storage()->fork($initializing)); //@phpstan-ignore-line + $fibers->zend_observer_fiber_switch_register(static fn (int $from, int $to) => Context::storage()->switch($to)); //@phpstan-ignore-line + $fibers->zend_observer_fiber_destroy_register(static fn (int $destroying) => Context::storage()->destroy($destroying)); //@phpstan-ignore-line + + return true; + } +} diff --git a/vendor/open-telemetry/context/composer.json b/vendor/open-telemetry/context/composer.json new file mode 100644 index 000000000..348b57f73 --- /dev/null +++ b/vendor/open-telemetry/context/composer.json @@ -0,0 +1,41 @@ +{ + "name": "open-telemetry/context", + "description": "Context implementation for OpenTelemetry PHP.", + "keywords": ["opentelemetry", "otel", "context"], + "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", + "symfony/polyfill-php80": "^1.26", + "symfony/polyfill-php81": "^1.26", + "symfony/polyfill-php82": "^1.26" + }, + "autoload": { + "psr-4": { + "OpenTelemetry\\Context\\": "." + }, + "files": [ + "fiber/initialize_fiber_handler.php" + ] + }, + "suggest": { + "ext-ffi": "To allow context switching in Fibers" + }, + "extra": { + "branch-alias": { + "dev-main": "1.0.x-dev" + } + } +} diff --git a/vendor/open-telemetry/context/fiber/initialize_fiber_handler.php b/vendor/open-telemetry/context/fiber/initialize_fiber_handler.php new file mode 100644 index 000000000..b9c706395 --- /dev/null +++ b/vendor/open-telemetry/context/fiber/initialize_fiber_handler.php @@ -0,0 +1,20 @@ +