diff --git a/composer.json b/composer.json index b92b07b..b0db656 100644 --- a/composer.json +++ b/composer.json @@ -28,7 +28,6 @@ "require-dev": { "doctrine/dbal": "^3.0", "friends-of-phpspec/phpspec-expect": "^4.0", - "open-telemetry/transport-grpc": "^1.0", "open-telemetry/gen-otlp-protobuf": "^1.0", "php-http/httplug": "^2.3", "phpspec/phpspec": "^7.5", diff --git a/readme.md b/readme.md index 90f3e23..3043aa1 100644 --- a/readme.md +++ b/readme.md @@ -3,6 +3,7 @@ ### Features #### Tracing + - Using the official [OpenTelemetry SDK](https://github.com/open-telemetry/opentelemetry-php) - Minimal auto-instrumentation for **requests**, console **commands**, **consumers** and **doctrine** - Trace context propagation from incoming **requests** to **consumers**, **outgoing http calls** and **databases** (using [`sqlcommenter`](https://google.github.io/sqlcommenter/)) @@ -10,18 +11,22 @@ - Automatic log inclusion with configurable log level and channels #### Metrics + - Using the [Prometheus Client](https://github.com/PromPHP/prometheus_client_php) - Minimal auto-instrumentation for common **request**, **consumer** and **message** metrics (see list of provided [default metrics](./docs/metrics/default-metrics.md)). - Autoconfigurable metric providers, see below. #### Logging + - Adds trace context to logs for correlation, with customizable keys. #### Baggage + - Using the official [OpenTelemetry SDK](https://github.com/open-telemetry/opentelemetry-php) - Baggage propagation from incoming **requests** to **consumers** and **outgoing http calls** #### Health + - A simple endpoint to expose application health (default: `/_healthz`) - Autoconfigurable healthcheck interface to add healthchecks to be made for global application health @@ -30,7 +35,9 @@ ```sh composer require worldia/instrumentation-bundle ``` + You will aso need to install an [exporter implementation](https://packagist.org/packages/open-telemetry/exporter-otlp?query=open-telemetry%2Fexporter-) and `APCu` is required by the prometheus exporter. + ``` Add to ```bundles.php```: @@ -41,8 +48,8 @@ return [ ]; ``` -**Minimal configuration** -See the complete [configuration reference here](./docs/config-reference.md) or run ```bin/console config:dump-reference instrumentation```. +**Minimal configuration** +See the complete [configuration reference here](./docs/config-reference.md) or run `bin/console config:dump-reference instrumentation`. ```yaml // docker-compose.yaml @@ -71,18 +78,18 @@ instrumentation: ~ ### Usage - **Tracing** - - [Simple tracing example](./docs/tracing/simple-trace.md) - - [Simple tracing example using the static API](./docs/tracing/static-usage.md) - - [Add Urls to your traces in error messages](./docs/tracing/add-urls-to-your-traces.md) - - [Use upstream request id as trace id](./docs/tracing/upstream-request-id.md) - - [Customize operation (span) name for a message](./docs/tracing/custom-operation-name-for-message.md) - - [Link strategy for a message](./docs/tracing/link-strategy-for-message.md) - - [Propagating trace/baggage context in HTTP requests](./docs/tracing/propagating-context.md) - - [Add request / response bodies as span attributes for HTTP requests](./docs/tracing/message-bodies.md) + - [Simple tracing example](./docs/tracing/simple-trace.md) + - [Simple tracing example using the static API](./docs/tracing/static-usage.md) + - [Add Urls to your traces in error messages](./docs/tracing/add-urls-to-your-traces.md) + - [Use upstream request id as trace id](./docs/tracing/upstream-request-id.md) + - [Customize operation (span) name for a message](./docs/tracing/custom-operation-name-for-message.md) + - [Link strategy for a message](./docs/tracing/link-strategy-for-message.md) + - [Propagating trace/baggage context in HTTP requests](./docs/tracing/propagating-context.md) + - [Add request / response bodies as span attributes for HTTP requests](./docs/tracing/message-bodies.md) - **Metrics** - - [Adding a metric](./docs/metrics/adding-a-metric.md) - - [Using Redis as storage adapter](./docs/metrics/using-redis-as-storage.md) (Recommended) + - [Adding a metric](./docs/metrics/adding-a-metric.md) + - [Using Redis as storage adapter](./docs/metrics/using-redis-as-storage.md) (Recommended) - **Logging** - - [Customizing trace context log keys](./docs/logging/custom-keys.md) + - [Customizing trace context log keys](./docs/logging/custom-keys.md) - **Health** - - [Adding a healthcheck](./docs/health/adding-a-healthcheck.md) + - [Adding a healthcheck](./docs/health/adding-a-healthcheck.md) diff --git a/spec/Tracing/Propagation/Doctrine/TraceContextInfoProviderSpec.php b/spec/Tracing/Propagation/Doctrine/TraceContextInfoProviderSpec.php index 992fdec..f256ee7 100644 --- a/spec/Tracing/Propagation/Doctrine/TraceContextInfoProviderSpec.php +++ b/spec/Tracing/Propagation/Doctrine/TraceContextInfoProviderSpec.php @@ -71,8 +71,8 @@ public function it_gets_controller_and_route(ResourceInfo $info, AttributesInter private function getMinimalInfo(): array { return [ - 'db_driver' => sprintf('doctrine/dbal-%s', InstalledVersions::getVersion('doctrine/dbal')), - 'framework' => sprintf('symfony-%s', Kernel::VERSION), + 'db_driver' => \sprintf('doctrine/dbal-%s', InstalledVersions::getVersion('doctrine/dbal')), + 'framework' => \sprintf('symfony-%s', Kernel::VERSION), ]; } } diff --git a/src/Bridge/GoogleCloud/Logging/Formatter/StdOutFormatter.php b/src/Bridge/GoogleCloud/Logging/Formatter/StdOutFormatter.php index 2cd6b34..3d157d6 100644 --- a/src/Bridge/GoogleCloud/Logging/Formatter/StdOutFormatter.php +++ b/src/Bridge/GoogleCloud/Logging/Formatter/StdOutFormatter.php @@ -45,30 +45,32 @@ protected function normalize(mixed $data, int $depth = 0): mixed $data['severity'] = $data['level_name']; unset($data['level_name']); - // Map tracing - if (isset($data['context']['trace'])) { - $data['logging.googleapis.com/trace'] = 'projects/'.$this->project.'/traces/'.$data['context']['trace']; - } - if (isset($data['context']['span'])) { - $data['logging.googleapis.com/spanId'] = $data['context']['span']; - } - if (isset($data['context']['sampled'])) { - $data['logging.googleapis.com/trace_sampled'] = $data['context']['sampled']; - } - if (isset($data['context']['operation'])) { - $data['logging.googleapis.com/operation'] = $data['context']['operation']; + if (\is_array($data['context'])) { + // Map tracing + if (isset($data['context']['trace'])) { + $data['logging.googleapis.com/trace'] = 'projects/'.$this->project.'/traces/'.$data['context']['trace']; + } + if (isset($data['context']['span'])) { + $data['logging.googleapis.com/spanId'] = $data['context']['span']; + } + if (isset($data['context']['sampled'])) { + $data['logging.googleapis.com/trace_sampled'] = $data['context']['sampled']; + } + if (isset($data['context']['operation'])) { + $data['logging.googleapis.com/operation'] = $data['context']['operation']; + } + unset($data['context']['trace'], $data['context']['span'], $data['context']['sampled'], $data['context']['operation']); + + if ($exception = $data['context']['exception'] ?? false) { + $data['message'] = $exception['message']; + $data['context'] = array_merge($data['context'], $exception['context']); + unset($data['context']['exception']); + } } - unset($data['context']['trace'], $data['context']['span'], $data['context']['sampled'], $data['context']['operation']); // Map channel $data['logging.googleapis.com/labels'] = ['channel' => $data['channel']]; unset($data['channel']); - - if ($exception = $data['context']['exception'] ?? false) { - $data['message'] = $exception['message']; - $data['context'] = array_merge($data['context'], $exception['context']); - unset($data['context']['exception']); - } } return $data; diff --git a/src/DependencyInjection/Configuration.php b/src/DependencyInjection/Configuration.php index a5b1683..92c5e34 100644 --- a/src/DependencyInjection/Configuration.php +++ b/src/DependencyInjection/Configuration.php @@ -34,7 +34,7 @@ public function getConfigTreeBuilder(): TreeBuilder ->scalarPrototype()->end() ->beforeNormalization() ->ifTrue(fn ($v) => !isset($v[ResourceAttributes::SERVICE_NAME])) - ->thenInvalid(sprintf('You must provide the "%s" attribute in resource info.', ResourceAttributes::SERVICE_NAME)) + ->thenInvalid(\sprintf('You must provide the "%s" attribute in resource info.', ResourceAttributes::SERVICE_NAME)) ->end() ->end() @@ -91,7 +91,7 @@ public function getConfigTreeBuilder(): TreeBuilder ->enumNode('level') ->defaultValue(Level::Info) ->values(Level::cases()) - ->info(sprintf('One of the %s levels.', Level::class)) + ->info(\sprintf('One of the %s levels.', Level::class)) ->end() ->arrayNode('channels') ->defaultValue([]) diff --git a/src/DependencyInjection/Extension.php b/src/DependencyInjection/Extension.php index 379372c..6161591 100644 --- a/src/DependencyInjection/Extension.php +++ b/src/DependencyInjection/Extension.php @@ -112,7 +112,7 @@ public function process(ContainerBuilder $container): void foreach ($providedMetrics as $name => $metric) { if (isset($metrics[$name])) { - throw new \RuntimeException(sprintf('A metric named %s is already registered.', $name)); + throw new \RuntimeException(\sprintf('A metric named %s is already registered.', $name)); } $metrics[$name] = $metric; } @@ -133,13 +133,13 @@ public function process(ContainerBuilder $container): void } foreach ($connectionsToTrace as $connection) { - $serviceId = sprintf('doctrine.dbal.%s_connection', $connection); + $serviceId = \sprintf('doctrine.dbal.%s_connection', $connection); if (!\in_array($serviceId, $connections, true)) { - throw new \InvalidArgumentException(sprintf('No such connection: "%s".', $connection)); + throw new \InvalidArgumentException(\sprintf('No such connection: "%s".', $connection)); } - $configDef = $container->getDefinition(sprintf('%s.configuration', $serviceId)); + $configDef = $container->getDefinition(\sprintf('%s.configuration', $serviceId)); $middlewares = []; foreach ($configDef->getMethodCalls() as $call) { @@ -252,7 +252,7 @@ protected function loadTracing(array $config, ContainerBuilder $container): void foreach (['blacklist', 'methods'] as $property) { if (isset($config[$feature][$property])) { - $container->setParameter(sprintf('tracing.%s.%s', $feature, $property), $config[$feature][$property]); + $container->setParameter(\sprintf('tracing.%s.%s', $feature, $property), $config[$feature][$property]); } } } @@ -281,7 +281,7 @@ protected function loadLogging(array $config, ContainerBuilder $container): void } foreach ($config['handlers'] as $handler) { - if ($container->hasDefinition(sprintf('monolog.handler.%s', $handler))) { + if ($container->hasDefinition(\sprintf('monolog.handler.%s', $handler))) { $container->getDefinition(\Instrumentation\Logging\Processor\TraceContextProcessor::class) ->addTag('monolog.processor', ['handler' => $handler]); } diff --git a/src/DependencyInjection/config/tracing/tracing.php b/src/DependencyInjection/config/tracing/tracing.php index 1d207d0..e6e9226 100644 --- a/src/DependencyInjection/config/tracing/tracing.php +++ b/src/DependencyInjection/config/tracing/tracing.php @@ -18,6 +18,7 @@ use Instrumentation\Tracing\Propagation\RegexIncomingTraceHeaderResolver; use Instrumentation\Tracing\Sampling\TogglableSampler; use Instrumentation\Tracing\Serializer\Normalizer\ErrorNormalizer; +use Instrumentation\Tracing\TogglableTracerProvider; use Instrumentation\Tracing\TraceUrlGeneratorInterface; use Instrumentation\Tracing\Twig\Extension\TracingExtension; use OpenTelemetry\API\Trace\TracerProviderInterface; @@ -90,6 +91,12 @@ ]) ->public() + ->set(TogglableTracerProvider::class) + ->decorate(TracerProviderInterface::class) + ->args([ + service('.inner'), + ]) + ->set(MainSpanContextInterface::class, MainSpanContext::class) ->set(TracingHandler::class) diff --git a/src/Http/HttpMessageHelper.php b/src/Http/HttpMessageHelper.php index dc4ad4a..0b7e294 100644 --- a/src/Http/HttpMessageHelper.php +++ b/src/Http/HttpMessageHelper.php @@ -21,7 +21,7 @@ public static function formatHeadersForSpanAttribute(array $headers): string $lines = []; foreach ($headers as $name => $values) { foreach ($values as $value) { - $lines[] = sprintf('%s: %s', mb_strtolower($name), $value); + $lines[] = \sprintf('%s: %s', mb_strtolower($name), $value); } } diff --git a/src/Http/TracedResponse.php b/src/Http/TracedResponse.php index 7f15dce..a462a5c 100644 --- a/src/Http/TracedResponse.php +++ b/src/Http/TracedResponse.php @@ -123,7 +123,7 @@ public static function stream(HttpClientInterface $client, iterable $responses, foreach ($responses as $r) { if (!$r instanceof self) { - throw new \TypeError(sprintf('"%s::stream()" expects parameter 1 to be an iterable of TracedResponse objects, "%s" given.', TracingHttpClient::class, get_debug_type($r))); + throw new \TypeError(\sprintf('"%s::stream()" expects parameter 1 to be an iterable of TracedResponse objects, "%s" given.', TracingHttpClient::class, get_debug_type($r))); } $traceableMap[$r->response] = $r; diff --git a/src/Http/TracingHttpClient.php b/src/Http/TracingHttpClient.php index 5cda904..18a2f94 100644 --- a/src/Http/TracingHttpClient.php +++ b/src/Http/TracingHttpClient.php @@ -70,7 +70,7 @@ protected function getExtraSpanAttributes(array|null $attributes): array } if (!\is_array($attributes)) { - throw new \RuntimeException(sprintf('Extra span attributes must be a comma separated list of attributes or an array. %s given.', get_debug_type($attributes))); + throw new \RuntimeException(\sprintf('Extra span attributes must be a comma separated list of attributes or an array. %s given.', get_debug_type($attributes))); } return $attributes; diff --git a/src/Metrics/CounterAdapter.php b/src/Metrics/CounterAdapter.php index d76fc2f..8334bd8 100644 --- a/src/Metrics/CounterAdapter.php +++ b/src/Metrics/CounterAdapter.php @@ -12,6 +12,8 @@ class CounterAdapter implements CounterInterface { + use IterableAttributesTrait; + public function __construct( private string $name, private string $description, @@ -20,11 +22,12 @@ public function __construct( } /** - * @param int $amount - * @param array{labels: array} $attributes + * @param int $amount + * @param iterable> $attributes */ public function add($amount, iterable $attributes = [], $context = null): void { + $attributes = $this->normalizeAttributes($attributes); /** @var array $labelNames */ $labelNames = array_keys($attributes['labels'] ?? []); $labelValues = array_values($attributes['labels'] ?? []); diff --git a/src/Metrics/EventSubscriber/RequestEventSubscriber.php b/src/Metrics/EventSubscriber/RequestEventSubscriber.php index c906771..09240a5 100644 --- a/src/Metrics/EventSubscriber/RequestEventSubscriber.php +++ b/src/Metrics/EventSubscriber/RequestEventSubscriber.php @@ -78,7 +78,7 @@ public function onTerminate(Event\TerminateEvent $event): void } $time = microtime(true) - $event->getRequest()->server->get('REQUEST_TIME_FLOAT'); - $code = sprintf('%sxx', substr((string) $event->getResponse()->getStatusCode(), 0, 1)); + $code = \sprintf('%sxx', substr((string) $event->getResponse()->getStatusCode(), 0, 1)); $operation = $this->mainSpanContext?->getOperationName() ?: 'unknown'; $this->registry->getGauge('requests_handling')->dec(); diff --git a/src/Metrics/HistogramAdapter.php b/src/Metrics/HistogramAdapter.php index 4088a4c..6bad420 100644 --- a/src/Metrics/HistogramAdapter.php +++ b/src/Metrics/HistogramAdapter.php @@ -13,6 +13,8 @@ class HistogramAdapter implements HistogramInterface { + use IterableAttributesTrait; + public function __construct( private string $name, private string $description, @@ -25,6 +27,7 @@ public function __construct( */ public function record($amount, iterable $attributes = [], $context = null): void { + $attributes = $this->normalizeAttributes($attributes); /** @var array $labelNames */ $labelNames = array_keys($attributes['labels'] ?? []); $labelValues = array_values($attributes['labels'] ?? []); diff --git a/src/Metrics/IterableAttributesTrait.php b/src/Metrics/IterableAttributesTrait.php new file mode 100644 index 0000000..161684c --- /dev/null +++ b/src/Metrics/IterableAttributesTrait.php @@ -0,0 +1,26 @@ + + */ + +namespace Instrumentation\Metrics; + +trait IterableAttributesTrait +{ + /** + * @param iterable> $attributes + * + * @return array> + */ + public function normalizeAttributes(iterable $attributes): array + { + $newAttr = []; + foreach ($attributes as $key => $value) { + $newAttr[$key] = $value; + } + + return $newAttr; + } +} diff --git a/src/Metrics/Meter.php b/src/Metrics/Meter.php index 86426c1..dc39ce8 100644 --- a/src/Metrics/Meter.php +++ b/src/Metrics/Meter.php @@ -58,7 +58,7 @@ public function createCounter(string $name, string|null $unit = null, string|nul */ public function createObservableCounter(string $name, string|null $unit = null, string|null $description = null, $advisory = [], callable ...$callbacks): ObservableCounterInterface { - throw new \LogicException(sprintf('Method %s is not implemented', __METHOD__)); + throw new \LogicException(\sprintf('Method %s is not implemented', __METHOD__)); } /** @@ -95,7 +95,7 @@ public function createHistogram(string $name, string|null $unit = null, string|n */ public function createObservableGauge(string $name, string|null $unit = null, string|null $description = null, $advisory = [], callable ...$callbacks): ObservableGaugeInterface { - throw new \LogicException(sprintf('Method %s is not implemented', __METHOD__)); + throw new \LogicException(\sprintf('Method %s is not implemented', __METHOD__)); } /** @@ -131,7 +131,7 @@ public function createUpDownCounter(string $name, string|null $unit = null, stri */ public function createObservableUpDownCounter(string $name, string|null $unit = null, string|null $description = null, $advisory = [], callable ...$callbacks): ObservableUpDownCounterInterface { - throw new \LogicException(sprintf('Method %s is not implemented', __METHOD__)); + throw new \LogicException(\sprintf('Method %s is not implemented', __METHOD__)); } public function batchObserve( @@ -139,6 +139,6 @@ public function batchObserve( AsynchronousInstrument $instrument, AsynchronousInstrument ...$instruments ): ObservableCallbackInterface { - throw new \LogicException(sprintf('Method %s is not implemented', __METHOD__)); + throw new \LogicException(\sprintf('Method %s is not implemented', __METHOD__)); } } diff --git a/src/Metrics/Registry.php b/src/Metrics/Registry.php index ca89b65..cba3534 100644 --- a/src/Metrics/Registry.php +++ b/src/Metrics/Registry.php @@ -63,7 +63,7 @@ private function getMetric(string $name): MetricDefinition { if (!isset($this->instantiated[$name])) { if (!isset($this->metrics[$name])) { - throw new \InvalidArgumentException(sprintf('No metric registered with that name: "%s".', $name)); + throw new \InvalidArgumentException(\sprintf('No metric registered with that name: "%s".', $name)); } /** diff --git a/src/Metrics/UpDownCounterAdapter.php b/src/Metrics/UpDownCounterAdapter.php index 8d64be2..21f2655 100644 --- a/src/Metrics/UpDownCounterAdapter.php +++ b/src/Metrics/UpDownCounterAdapter.php @@ -12,6 +12,8 @@ class UpDownCounterAdapter implements UpDownCounterInterface { + use IterableAttributesTrait; + public function __construct( private string $name, private string $description, @@ -25,6 +27,7 @@ public function __construct( */ public function add($amount, iterable $attributes = [], $context = null): void { + $attributes = $this->normalizeAttributes($attributes); /** @var array $labelNames */ $labelNames = array_keys($attributes['labels'] ?? []); $labelValues = array_values($attributes['labels'] ?? []); diff --git a/src/Semantics/Attribute/ClientRequestAttributeProvider.php b/src/Semantics/Attribute/ClientRequestAttributeProvider.php index 1f3c73e..cec2f3c 100644 --- a/src/Semantics/Attribute/ClientRequestAttributeProvider.php +++ b/src/Semantics/Attribute/ClientRequestAttributeProvider.php @@ -36,7 +36,7 @@ public function getAttributes(string $method, string $url, array $headers = []): $headers[$header] = implode(',', $headers[$header]); } - $attributes[sprintf('http.request.header.%s', str_replace('-', '_', $header))] = $headers[$header]; + $attributes[\sprintf('http.request.header.%s', str_replace('-', '_', $header))] = $headers[$header]; } $components = parse_url($url); diff --git a/src/Semantics/Attribute/ServerRequestAttributeProvider.php b/src/Semantics/Attribute/ServerRequestAttributeProvider.php index 6e7392d..56daeed 100644 --- a/src/Semantics/Attribute/ServerRequestAttributeProvider.php +++ b/src/Semantics/Attribute/ServerRequestAttributeProvider.php @@ -44,7 +44,7 @@ public function getAttributes(Request $request): array } foreach ($this->capturedHeaders as $header) { - $attributes[sprintf('http.response.header.%s', str_replace('-', '_', $header))] = [(string) $request->headers->get($header, '')]; + $attributes[\sprintf('http.response.header.%s', str_replace('-', '_', $header))] = [(string) $request->headers->get($header, '')]; } return array_filter($attributes); diff --git a/src/Semantics/OperationName/ClientRequestOperationNameResolver.php b/src/Semantics/OperationName/ClientRequestOperationNameResolver.php index b91602a..b8b5bf6 100644 --- a/src/Semantics/OperationName/ClientRequestOperationNameResolver.php +++ b/src/Semantics/OperationName/ClientRequestOperationNameResolver.php @@ -15,6 +15,6 @@ public function getOperationName(string $method, string $url): string { $url = parse_url($url); - return sprintf('http.%s %s://%s', strtolower($method), $url['scheme'] ?? 'http', $url['host'] ?? 'unknown'); + return \sprintf('http.%s %s://%s', strtolower($method), $url['scheme'] ?? 'http', $url['host'] ?? 'unknown'); } } diff --git a/src/Semantics/OperationName/CommandOperationNameResolver.php b/src/Semantics/OperationName/CommandOperationNameResolver.php index ce7d7ed..fbfc848 100644 --- a/src/Semantics/OperationName/CommandOperationNameResolver.php +++ b/src/Semantics/OperationName/CommandOperationNameResolver.php @@ -21,6 +21,6 @@ public function getOperationName(Command|null $command): string $name = $command->getName() ?: $command->getDefaultName(); } - return sprintf('cli %s', $name); + return \sprintf('cli %s', $name); } } diff --git a/src/Semantics/OperationName/MessageOperationNameResolver.php b/src/Semantics/OperationName/MessageOperationNameResolver.php index 78d6071..a3011e0 100644 --- a/src/Semantics/OperationName/MessageOperationNameResolver.php +++ b/src/Semantics/OperationName/MessageOperationNameResolver.php @@ -25,6 +25,6 @@ public function getOperationName(Envelope $envelope, string $operation): string $name = $stamp->getOperationName(); } - return sprintf('message.%s %s', $name, $operation); + return \sprintf('message.%s %s', $name, $operation); } } diff --git a/src/Semantics/OperationName/RouteNameServerRequestOperationNameResolver.php b/src/Semantics/OperationName/RouteNameServerRequestOperationNameResolver.php index 215bf6b..4d488a1 100644 --- a/src/Semantics/OperationName/RouteNameServerRequestOperationNameResolver.php +++ b/src/Semantics/OperationName/RouteNameServerRequestOperationNameResolver.php @@ -21,6 +21,6 @@ public function getOperationName(Request $request): string $routeName = $request->getPathInfo(); } - return sprintf('http.%s %s', strtolower($request->getMethod()), $routeName); + return \sprintf('http.%s %s', strtolower($request->getMethod()), $routeName); } } diff --git a/src/Semantics/OperationName/RoutePathServerRequestOperationNameResolver.php b/src/Semantics/OperationName/RoutePathServerRequestOperationNameResolver.php index f1c8dce..74fddfa 100644 --- a/src/Semantics/OperationName/RoutePathServerRequestOperationNameResolver.php +++ b/src/Semantics/OperationName/RoutePathServerRequestOperationNameResolver.php @@ -31,6 +31,6 @@ public function getOperationName(Request $request): string $path = $request->getPathInfo(); } - return sprintf('http.%s %s', strtolower($request->getMethod()), $path); + return \sprintf('http.%s %s', strtolower($request->getMethod()), $path); } } diff --git a/src/Tracing/Instrumentation/EventSubscriber/RequestEventSubscriber.php b/src/Tracing/Instrumentation/EventSubscriber/RequestEventSubscriber.php index 5215b8d..4c5c395 100644 --- a/src/Tracing/Instrumentation/EventSubscriber/RequestEventSubscriber.php +++ b/src/Tracing/Instrumentation/EventSubscriber/RequestEventSubscriber.php @@ -96,7 +96,7 @@ public function onRouteResolved(Event\RequestEvent $event): void $span = $this->getSpanForRequest($request); - $span->updateName(sprintf('sf.controller.%s', $event->isMainRequest() ? 'main' : 'sub')); + $span->updateName(\sprintf('sf.controller.%s', $event->isMainRequest() ? 'main' : 'sub')); $span->setAttribute('sf.controller', $controller); if ($event->isMainRequest()) { diff --git a/src/Tracing/Instrumentation/LogHandler/TracingHandler.php b/src/Tracing/Instrumentation/LogHandler/TracingHandler.php index 02e64e0..681194b 100644 --- a/src/Tracing/Instrumentation/LogHandler/TracingHandler.php +++ b/src/Tracing/Instrumentation/LogHandler/TracingHandler.php @@ -57,7 +57,7 @@ protected function write(LogRecord $record): void $span = match ($this->strategy) { self::STRATEGY_MAIN_SPAN => $this->mainSpanContext->getMainSpan(), self::STRATEGY_CURRENT_SPAN => Span::getCurrent(), - default => throw new \InvalidArgumentException(sprintf('Unkown strategy "%s".', $this->strategy)) + default => throw new \InvalidArgumentException(\sprintf('Unkown strategy "%s".', $this->strategy)) }; if (isset($record->context['exception']) && $record->context['exception'] instanceof \Throwable) { diff --git a/src/Tracing/Propagation/Doctrine/TraceContextInfoProvider.php b/src/Tracing/Propagation/Doctrine/TraceContextInfoProvider.php index ceac5c2..8f0128c 100644 --- a/src/Tracing/Propagation/Doctrine/TraceContextInfoProvider.php +++ b/src/Tracing/Propagation/Doctrine/TraceContextInfoProvider.php @@ -40,7 +40,7 @@ public function getTraceContext(): array $info['framework'] = 'symfony-'.Kernel::VERSION; try { - $info['db_driver'] = sprintf('doctrine/dbal-%s', InstalledVersions::getVersion('doctrine/dbal')); + $info['db_driver'] = \sprintf('doctrine/dbal-%s', InstalledVersions::getVersion('doctrine/dbal')); } catch (\Exception) { // Ignore } diff --git a/src/Tracing/Propagation/EventSubscriber/RequestEventSubscriber.php b/src/Tracing/Propagation/EventSubscriber/RequestEventSubscriber.php index 7741470..d8ba0b3 100644 --- a/src/Tracing/Propagation/EventSubscriber/RequestEventSubscriber.php +++ b/src/Tracing/Propagation/EventSubscriber/RequestEventSubscriber.php @@ -50,7 +50,7 @@ public function onRequest(Event\RequestEvent $event): void $sampled = $this->incomingTraceResolver->isSampled($request); if (null !== $traceId && null !== $spanId && null !== $sampled) { - $w3cHeader = sprintf('00-%s-%s-%s', $traceId, $spanId, $sampled ? '01' : '00'); + $w3cHeader = \sprintf('00-%s-%s-%s', $traceId, $spanId, $sampled ? '01' : '00'); ContextInitializer::fromW3CHeader($w3cHeader); return; diff --git a/src/Tracing/Propagation/Messenger/PropagationStrategyStamp.php b/src/Tracing/Propagation/Messenger/PropagationStrategyStamp.php index c8a5207..7428419 100644 --- a/src/Tracing/Propagation/Messenger/PropagationStrategyStamp.php +++ b/src/Tracing/Propagation/Messenger/PropagationStrategyStamp.php @@ -19,7 +19,7 @@ final class PropagationStrategyStamp implements StampInterface public function __construct(private string $strategy) { if (!\in_array($strategy, [self::STRATEGY_LINK, self::STRATEGY_PARENT])) { - throw new \InvalidArgumentException(sprintf('"%s" is not a valid value for strategy', $strategy)); + throw new \InvalidArgumentException(\sprintf('"%s" is not a valid value for strategy', $strategy)); } } diff --git a/src/Tracing/TogglableTracerProvider.php b/src/Tracing/TogglableTracerProvider.php new file mode 100644 index 0000000..801f77b --- /dev/null +++ b/src/Tracing/TogglableTracerProvider.php @@ -0,0 +1,34 @@ + + */ + +namespace Instrumentation\Tracing; + +use OpenTelemetry\API\Trace\NoopTracer; +use OpenTelemetry\API\Trace\TracerInterface; +use OpenTelemetry\API\Trace\TracerProviderInterface; +use OpenTelemetry\SDK\Sdk; + +class TogglableTracerProvider implements TracerProviderInterface +{ + public function __construct(private TracerProviderInterface $decorated) + { + } + + /** + * @param array $attributes + */ + public function getTracer(string $name, string|null $version = null, string|null $schemaUrl = null, iterable $attributes = []): TracerInterface + { + if (Sdk::isDisabled()) { + return new NoopTracer(); + } + + return $this->decorated->getTracer($name, $version, $schemaUrl, $attributes); + } +} diff --git a/src/Tracing/Tracing.php b/src/Tracing/Tracing.php index 6cd3781..133949b 100644 --- a/src/Tracing/Tracing.php +++ b/src/Tracing/Tracing.php @@ -13,6 +13,8 @@ use OpenTelemetry\API\Trace\SpanKind; use OpenTelemetry\API\Trace\TracerProviderInterface; use OpenTelemetry\Context\Context; +use OpenTelemetry\SDK\Sdk; +use OpenTelemetry\SDK\Trace\NoopTracerProvider; final class Tracing { @@ -46,6 +48,9 @@ public static function setProvider(TracerProviderInterface $tracerProvider): voi private static function getProvider(): TracerProviderInterface { + if (Sdk::isDisabled()) { + return new NoopTracerProvider(); + } if (!self::$tracerProvider) { throw new \RuntimeException('No trace provider was set.'); }