From 215731f6390e74068314fc719a541d13921b1f5c Mon Sep 17 00:00:00 2001 From: Tobias Bachert Date: Fri, 23 Sep 2022 20:15:46 +0200 Subject: [PATCH] Improve `open-telemetry/context` documentation (#830) --- .phan/config.php | 1 + src/Context/ContextInterface.php | 66 ++++++++++++++++---- src/Context/ContextStorageInterface.php | 18 ++++++ src/Context/ContextStorageScopeInterface.php | 5 ++ src/Context/README.md | 51 +++++++++++++++ src/Context/ScopeInterface.php | 5 +- src/Context/composer.json | 2 +- 7 files changed, 135 insertions(+), 13 deletions(-) diff --git a/.phan/config.php b/.phan/config.php index 3a6e8ee8a..ac8174861 100644 --- a/.phan/config.php +++ b/.phan/config.php @@ -284,6 +284,7 @@ 'PhanAccessClassInternal', 'PhanAccessMethodInternal', 'PhanAccessPropertyInternal', + 'PhanTemplateTypeNotUsedInFunctionReturn', ], // A regular expression to match files to be excluded diff --git a/src/Context/ContextInterface.php b/src/Context/ContextInterface.php index 55e14ad20..17a3fb9a2 100644 --- a/src/Context/ContextInterface.php +++ b/src/Context/ContextInterface.php @@ -4,39 +4,83 @@ namespace OpenTelemetry\Context; +/** + * Immutable execution scoped propagation mechanism. + * + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/context/README.md#context + */ interface ContextInterface { /** - * @param non-empty-string $key + * Creates a new context key. * - * @see https://github.com/open-telemetry/opentelemetry-specification/blob/v1.6.1/specification/context/context.md#create-a-key + * @param non-empty-string $key name of the key + * @return ContextKeyInterface created key + * + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/context/README.md#create-a-key */ public static function createKey(string $key): ContextKeyInterface; + /** + * Returns the current context. + * + * @return ContextInterface current context + * + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/context/README.md#get-current-context + */ public static function getCurrent(): ContextInterface; /** - * Makes `$this` the currently active {@see ContextInterface}. + * Attaches this context as active context. + * + * The returned scope has to be {@link ScopeInterface::detach()}ed. In most + * cases this should be done using a `try-finally` statement: + * ```php + * $scope = $context->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; /** - * This adds a key/value pair to this Context. + * 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` * - * @psalm-template T - * @psalm-param ContextKeyInterface $key - * @psalm-param T|null $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; /** - * Fetch a value from the Context given a key value. + * 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 * - * @psalm-template T - * @psalm-param ContextKeyInterface $key - * @psalm-return T|null + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/context/README.md#get-value */ public function get(ContextKeyInterface $key); } diff --git a/src/Context/ContextStorageInterface.php b/src/Context/ContextStorageInterface.php index d79fe0b7c..e5a105074 100644 --- a/src/Context/ContextStorageInterface.php +++ b/src/Context/ContextStorageInterface.php @@ -6,9 +6,27 @@ interface ContextStorageInterface { + /** + * Returns the current scope. + * + * @return ContextStorageScopeInterface|null current scope, or null if no + * scope was attached in the current execution unit + */ public function scope(): ?ContextStorageScopeInterface; + /** + * Returns the current context. + * + * @return ContextInterface current context + */ public function current(): ContextInterface; + /** + * Attaches the context as active context. + * + * @param ContextInterface $context context to attach + * @return ContextStorageScopeInterface scope to detach the context and + * restore the previous context + */ public function attach(ContextInterface $context): ContextStorageScopeInterface; } diff --git a/src/Context/ContextStorageScopeInterface.php b/src/Context/ContextStorageScopeInterface.php index 9145800f4..5fe58d6eb 100644 --- a/src/Context/ContextStorageScopeInterface.php +++ b/src/Context/ContextStorageScopeInterface.php @@ -8,6 +8,11 @@ interface ContextStorageScopeInterface extends ScopeInterface, ArrayAccess { + /** + * Returns the context associated with this scope. + * + * @return ContextInterface associated context + */ public function context(): ContextInterface; /** diff --git a/src/Context/README.md b/src/Context/README.md index 05074a542..9ac56740c 100644 --- a/src/Context/README.md +++ b/src/Context/README.md @@ -1 +1,52 @@ # 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`, `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(); + } + }; +} +``` + +[1]: https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/context/README.md#context diff --git a/src/Context/ScopeInterface.php b/src/Context/ScopeInterface.php index ebe017124..486a26f7b 100644 --- a/src/Context/ScopeInterface.php +++ b/src/Context/ScopeInterface.php @@ -8,8 +8,11 @@ interface ScopeInterface { + /** Already detached. */ public const DETACHED = 1 << (PHP_INT_SIZE << 3) - 1; + /** Execution context inactive. */ public const INACTIVE = 1 << (PHP_INT_SIZE << 3) - 2; + /** Not current context. */ public const MISMATCH = 1 << (PHP_INT_SIZE << 3) - 3; /** @@ -23,7 +26,7 @@ interface ScopeInterface * @see self::INACTIVE * @see self::MISMATCH * - * @see https://github.com/open-telemetry/opentelemetry-specification/blob/v1.7.0/specification/context/context.md#detach-context + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/context/README.md#detach-context */ public function detach(): int; } diff --git a/src/Context/composer.json b/src/Context/composer.json index ac650709b..49d7db425 100644 --- a/src/Context/composer.json +++ b/src/Context/composer.json @@ -1,7 +1,7 @@ { "name": "open-telemetry/context", "description": "Context implementation for OpenTelemetry PHP.", - "keywords": ["opentelemetry", "otel", "metrics", "tracing", "logging", "apm", "context"], + "keywords": ["opentelemetry", "otel", "context"], "type": "library", "license": "Apache-2.0", "authors": [