├── .gitignore ├── src ├── Name │ └── Generator │ │ ├── NameGeneratorInterface.php │ │ ├── AbstractGeneratorDecorator.php │ │ ├── ShortenGeneratorDecorator.php │ │ ├── NameGeneratorChain.php │ │ ├── ControllerNameGenerator.php │ │ ├── CommandNameGenerator.php │ │ ├── DefaultNameGenerator.php │ │ └── RequestNameGenerator.php ├── Debug │ └── Extractor │ │ ├── DebugExtractorInterface.php │ │ ├── DebugExtractorChain.php │ │ ├── EnvDebugExtractor.php │ │ └── CookieDebugExtractor.php ├── Context │ └── Extractor │ │ ├── ContextExtractorInterface.php │ │ ├── ContextExtractorChain.php │ │ ├── EnvContextExtractor.php │ │ └── HeaderContextExtractor.php ├── Resources │ ├── shorten.yml │ ├── denylist.yml │ └── services.yml ├── Tag │ ├── SymfonyComponentTag.php │ ├── TimeMicroTag.php │ ├── TimeValueTag.php │ ├── SymfonyBackgroundTag.php │ ├── SymfonySubRequestTag.php │ ├── TimeSourceTag.php │ ├── SymfonyMainRequestTag.php │ └── SymfonyVersionTag.php ├── Transport │ ├── SymfonyUDPTransport.php │ └── SymfonyBufferedTransport.php ├── Bridge │ ├── BackgroundStartListener.php │ ├── MainSpanFlushListener.php │ ├── TracerBridge.php │ ├── ExceptionListener.php │ ├── MainSpanNameListener.php │ ├── BackgroundSpanHandler.php │ ├── MainSpanLifecycleListener.php │ ├── AppStartSpanListener.php │ ├── JaegerSamplerFactory.php │ ├── ContextListener.php │ ├── DebugListener.php │ ├── MainSpanHandler.php │ └── RequestSpanListener.php ├── JaegerBundle.php ├── DependencyInjection │ ├── NameGeneratorChainCompilerPass.php │ ├── DebugExtractorChainCompilerPass.php │ ├── ContextExtractorChainCompilerPass.php │ ├── CodecRegistryCompilerPass.php │ ├── Configuration.php │ ├── DeprecatedAliasesCompilerPass.php │ └── JaegerExtension.php └── Sampler │ └── DenylistOperationsSampler.php ├── composer.json ├── LICENSE ├── psalm.xml └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | /vendor/ 3 | composer.lock 4 | composer.phar 5 | -------------------------------------------------------------------------------- /src/Name/Generator/NameGeneratorInterface.php: -------------------------------------------------------------------------------- 1 | generator = $generator; 13 | } 14 | 15 | public function generate(): string 16 | { 17 | return $this->generator->generate(); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "code-tool/jaeger-client-symfony-bridge", 3 | "license": "MIT", 4 | "autoload": { 5 | "psr-4": { 6 | "Jaeger\\Symfony\\": "src/" 7 | } 8 | }, 9 | "require": { 10 | "php": "^7.4|^8.0", 11 | "code-tool/jaeger-client-php": "^3.4", 12 | "symfony/config": "^4.4|^5.4|^6.0|^7.0", 13 | "symfony/console": "^4.4|^5.4|^6.0|^7.0", 14 | "symfony/dependency-injection": "^4.4|^5.4|^6.0|^7.0", 15 | "symfony/event-dispatcher": "^4.4|^5.4|^6.0|^7.0", 16 | "symfony/http-kernel": "^4.4|^5.4|^6.0|^7.0", 17 | "symfony/yaml": "^4.4|^5.4|^6.0|^7.0", 18 | "symfony/service-contracts": "^2|^3" 19 | }, 20 | "require-dev": { 21 | "vimeo/psalm": "^5.15" 22 | }, 23 | "minimum-stability": "dev", 24 | "prefer-stable": true 25 | } 26 | -------------------------------------------------------------------------------- /src/Bridge/BackgroundStartListener.php: -------------------------------------------------------------------------------- 1 | handler = $handler; 16 | } 17 | 18 | public static function getSubscribedEvents(): array 19 | { 20 | return [TerminateEvent::class => ['onTerminate', 16384],]; 21 | } 22 | 23 | public function onTerminate(TerminateEvent $event): void 24 | { 25 | $this->handler->start($event->getRequest()); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/Name/Generator/ShortenGeneratorDecorator.php: -------------------------------------------------------------------------------- 1 | maxLength = $maxLength; 13 | parent::__construct($generator); 14 | } 15 | 16 | public function shorten(string $name) 17 | { 18 | if ($this->maxLength >= \strlen($name)) { 19 | return $name; 20 | } 21 | 22 | return \substr($name, 0, $this->maxLength); 23 | } 24 | 25 | public function generate(): string 26 | { 27 | return $this->shorten(parent::generate()); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/Bridge/MainSpanFlushListener.php: -------------------------------------------------------------------------------- 1 | backgroundHandler = $backgroundHandler; 18 | $this->globalHandler = $globalHandler; 19 | } 20 | 21 | public static function getSubscribedEvents(): array 22 | { 23 | return [TerminateEvent::class => ['onTerminate', -16384]]; 24 | } 25 | 26 | public function onTerminate() 27 | { 28 | $this->backgroundHandler->flush(); 29 | $this->globalHandler->flush(); 30 | 31 | return $this; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/Debug/Extractor/DebugExtractorChain.php: -------------------------------------------------------------------------------- 1 | queue = $queue; 13 | } 14 | 15 | public function add(DebugExtractorInterface $extractor, int $priority = 0): DebugExtractorChain 16 | { 17 | $this->queue->insert($extractor, $priority); 18 | 19 | return $this; 20 | } 21 | 22 | public function getDebug(): string 23 | { 24 | $queue = clone $this->queue; 25 | while (false === $queue->isEmpty()) { 26 | /** @var DebugExtractorInterface $extractor */ 27 | $extractor = $queue->extract(); 28 | $debugId = $extractor->getDebug(); 29 | if ('' !== $debugId) { 30 | return $debugId; 31 | } 32 | } 33 | 34 | return ''; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/Name/Generator/NameGeneratorChain.php: -------------------------------------------------------------------------------- 1 | queue = $queue; 13 | } 14 | 15 | public function add(NameGeneratorInterface $extractor, int $priority = 0): NameGeneratorChain 16 | { 17 | $this->queue->insert($extractor, $priority); 18 | 19 | return $this; 20 | } 21 | 22 | public function generate(): string 23 | { 24 | $queue = clone $this->queue; 25 | while (false === $queue->isEmpty()) { 26 | /** @var NameGeneratorInterface $generator */ 27 | $generator = $queue->extract(); 28 | $name = $generator->generate(); 29 | if ('' !== $name) { 30 | return $name; 31 | } 32 | } 33 | 34 | return 'route.unknown'; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/Bridge/TracerBridge.php: -------------------------------------------------------------------------------- 1 | tracer = $tracer; 19 | } 20 | 21 | public static function getSubscribedEvents(): array 22 | { 23 | return [ 24 | ConsoleTerminateEvent::class => ['onTerminate', -65536], 25 | TerminateEvent::class => ['onTerminate', -65536], 26 | ]; 27 | } 28 | 29 | public function onTerminate(): void 30 | { 31 | $this->tracer->flush(); 32 | if ($this->tracer instanceof ResettableInterface) { 33 | $this->tracer->reset(); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/Context/Extractor/ContextExtractorChain.php: -------------------------------------------------------------------------------- 1 | queue = $queue; 15 | } 16 | 17 | public function add(ContextExtractorInterface $extractor, int $priority = 0): ContextExtractorChain 18 | { 19 | $this->queue->insert($extractor, $priority); 20 | 21 | return $this; 22 | } 23 | 24 | public function extract(): ?SpanContext 25 | { 26 | $queue = clone $this->queue; 27 | while (false === $queue->isEmpty()) { 28 | /** @var ContextExtractorInterface $extractor */ 29 | $extractor = $queue->extract(); 30 | $context = $extractor->extract(); 31 | if (null !== $context) { 32 | return $context; 33 | } 34 | } 35 | 36 | return null; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/JaegerBundle.php: -------------------------------------------------------------------------------- 1 | addCompilerPass(new CodecRegistryCompilerPass()) 21 | ->addCompilerPass(new ContextExtractorChainCompilerPass()) 22 | ->addCompilerPass(new DebugExtractorChainCompilerPass()) 23 | ->addCompilerPass(new NameGeneratorChainCompilerPass()) 24 | ->addCompilerPass(new DeprecatedAliasesCompilerPass()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 code-tool 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/DependencyInjection/NameGeneratorChainCompilerPass.php: -------------------------------------------------------------------------------- 1 | hasDefinition('jaeger.name.generator.chain')) { 15 | throw new \RuntimeException( 16 | sprintf('Required service %s is missing from container', 'jaeger.name.generator.chain') 17 | ); 18 | } 19 | 20 | $definition = $container->getDefinition('jaeger.name.generator.chain'); 21 | foreach ($container->findTaggedServiceIds('jaeger.name.generator') as $id => $tags) { 22 | foreach ($tags as $tag) { 23 | $priority = $tag['priority'] ?? 0; 24 | $definition->addMethodCall('add', [new Reference($id), $priority]); 25 | } 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/DependencyInjection/DebugExtractorChainCompilerPass.php: -------------------------------------------------------------------------------- 1 | hasDefinition('jaeger.debug.extractor.chain')) { 15 | throw new \RuntimeException( 16 | sprintf('Required service %s is missing from container', 'jaeger.debug.extractor.chain') 17 | ); 18 | } 19 | 20 | $definition = $container->getDefinition('jaeger.debug.extractor.chain'); 21 | foreach ($container->findTaggedServiceIds('jaeger.debug.extractor') as $id => $tags) { 22 | foreach ($tags as $tag) { 23 | $priority = $tag['priority'] ?? 0; 24 | $definition->addMethodCall('add', [new Reference($id), $priority]); 25 | } 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/DependencyInjection/ContextExtractorChainCompilerPass.php: -------------------------------------------------------------------------------- 1 | hasDefinition('jaeger.context.extractor.chain')) { 15 | throw new \RuntimeException( 16 | sprintf('Required service %s is missing from container', 'jaeger.context.extractor.chain') 17 | ); 18 | } 19 | 20 | $definition = $container->getDefinition('jaeger.context.extractor.chain'); 21 | foreach ($container->findTaggedServiceIds('jaeger.context.extractor') as $id => $tags) { 22 | foreach ($tags as $tag) { 23 | $priority = $tag['priority'] ?? 0; 24 | $definition->addMethodCall('add', [new Reference($id), $priority]); 25 | } 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/Bridge/ExceptionListener.php: -------------------------------------------------------------------------------- 1 | spanManager = $spanManager; 19 | } 20 | 21 | public static function getSubscribedEvents(): array 22 | { 23 | return [ 24 | ExceptionEvent::class => ['onKernelException', 0], 25 | ]; 26 | } 27 | 28 | public function onKernelException(ExceptionEvent $event): void 29 | { 30 | $span = $this->spanManager->getSpan(); 31 | 32 | if (null === $span) { 33 | return; 34 | } 35 | 36 | $exception = $event->getThrowable(); 37 | 38 | $span 39 | ->addTag(new ErrorTag()) 40 | ->addLog(new ErrorLog($exception->getMessage(), $exception->getTraceAsString())) 41 | ; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/Debug/Extractor/EnvDebugExtractor.php: -------------------------------------------------------------------------------- 1 | envName = $envName; 19 | } 20 | 21 | public static function getSubscribedEvents(): array 22 | { 23 | return [ 24 | ConsoleEvents::COMMAND => ['onCommand', 16384], 25 | ConsoleEvents::TERMINATE => ['onTerminate'], 26 | ]; 27 | } 28 | 29 | public function onTerminate() 30 | { 31 | $this->reset(); 32 | 33 | return $this; 34 | } 35 | 36 | public function reset(): void 37 | { 38 | $this->debugId = ''; 39 | } 40 | 41 | public function getDebug(): string 42 | { 43 | return $this->debugId; 44 | } 45 | 46 | public function onCommand() 47 | { 48 | $this->debugId = $_ENV[$this->envName] ?? ''; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/Name/Generator/ControllerNameGenerator.php: -------------------------------------------------------------------------------- 1 | ['onRequest', 31], 20 | TerminateEvent::class => ['onTerminate', -16384], 21 | ]; 22 | } 23 | 24 | public function onRequest(RequestEvent $event): void 25 | { 26 | $this->controller = (string)$event->getRequest()->attributes->get('_controller', ''); 27 | } 28 | 29 | public function onTerminate(): void 30 | { 31 | $this->reset(); 32 | } 33 | 34 | public function reset(): void 35 | { 36 | $this->controller = ''; 37 | } 38 | 39 | public function generate(): string 40 | { 41 | return $this->controller; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/DependencyInjection/CodecRegistryCompilerPass.php: -------------------------------------------------------------------------------- 1 | hasDefinition('jaeger.codec.registry')) { 15 | throw new \RuntimeException( 16 | sprintf('Required service %s is missing from container', 'codec.registry') 17 | ); 18 | } 19 | 20 | $definition = $container->getDefinition('jaeger.codec.registry'); 21 | foreach ($container->findTaggedServiceIds('jaeger.codec') as $id => $tags) { 22 | foreach ($tags as $tag) { 23 | if (false === array_key_exists('alias', $tag)) { 24 | throw new \RuntimeException( 25 | sprintf('Required tag field %s is missing from definition', 'alias') 26 | ); 27 | } 28 | $definition->addMethodCall('offsetSet', [$tag['alias'], new Reference($id)]); 29 | } 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /psalm.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /src/Bridge/MainSpanNameListener.php: -------------------------------------------------------------------------------- 1 | handler = $handler; 19 | } 20 | 21 | public static function getSubscribedEvents(): array 22 | { 23 | return [ 24 | RequestEvent::class => ['onRequest', 30], 25 | ]; 26 | } 27 | 28 | public function onRequest(KernelEvent $event): MainSpanNameListener 29 | { 30 | if (false === $this->isMainRequestEvent($event)) { 31 | return $this; 32 | } 33 | $this->handler->name(); 34 | 35 | return $this; 36 | } 37 | 38 | /** 39 | * Use non-deprecated check method if availble 40 | * 41 | * @param KernelEvent $event 42 | * 43 | * @return bool 44 | */ 45 | private function isMainRequestEvent(KernelEvent $event): bool 46 | { 47 | if (\method_exists($event, 'isMainRequest')) { 48 | return $event->isMainRequest(); 49 | } 50 | 51 | return $event->isMasterRequest(); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/DependencyInjection/Configuration.php: -------------------------------------------------------------------------------- 1 | getRootNode() 17 | ->children() 18 | ->arrayNode('denylist') 19 | ->canBeEnabled() 20 | ->children() 21 | ->arrayNode('operation_names') 22 | ->scalarPrototype()->end() 23 | ->end() 24 | ->end() 25 | ->end() 26 | ->arrayNode('name_generator') 27 | ->canBeEnabled() 28 | ->children() 29 | ->integerNode('max_length')->defaultValue(64)->end() 30 | ->arrayNode('command') 31 | ->useAttributeAsKey('pattern') 32 | ->scalarPrototype()->end() 33 | ->end() 34 | ->arrayNode('request') 35 | ->useAttributeAsKey('pattern') 36 | ->scalarPrototype()->end() 37 | ->end() 38 | ->end() 39 | ->end() 40 | ->end(); 41 | // @formatter:on 42 | 43 | return $treeBuilder; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/Sampler/DenylistOperationsSampler.php: -------------------------------------------------------------------------------- 1 | sampler = $sampler; 26 | $this->denylistedOperationsMap = \array_fill_keys($denylistedOperations, true); 27 | } 28 | 29 | public function decide(int $traceId, string $operationName, string $debugId): SamplerResult 30 | { 31 | if ('' !== $debugId) { 32 | return $this->sampler->decide($traceId, $operationName, $debugId); 33 | } 34 | 35 | if (false === \array_key_exists($operationName, $this->denylistedOperationsMap)) { 36 | return $this->sampler->decide($traceId, $operationName, $debugId); 37 | } 38 | 39 | return new SamplerResult( 40 | false, 41 | 0, 42 | [ 43 | new SamplerTypeTag('denylist_operations'), 44 | new SamplerParamTag($operationName), 45 | new SamplerDecisionTag(false), 46 | new SamplerFlagsTag(0x00), 47 | ] 48 | ); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/Context/Extractor/EnvContextExtractor.php: -------------------------------------------------------------------------------- 1 | registry = $registry; 26 | $this->format = $format; 27 | $this->envName = $envName; 28 | } 29 | 30 | public static function getSubscribedEvents(): array 31 | { 32 | return [ 33 | ConsoleCommandEvent::class => ['onCommand', 16384], 34 | ConsoleTerminateEvent::class => ['onTerminate'], 35 | ]; 36 | } 37 | 38 | public function onTerminate(): void 39 | { 40 | $this->context = null; 41 | } 42 | 43 | public function extract(): ?SpanContext 44 | { 45 | return $this->context; 46 | } 47 | 48 | public function onCommand(): void 49 | { 50 | if (null === ($data = $_ENV[$this->envName] ?? null)) { 51 | return; 52 | } 53 | if (null === ($context = $this->registry[$this->format]->decode($data))) { 54 | return; 55 | } 56 | $this->context = $context; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/Bridge/BackgroundSpanHandler.php: -------------------------------------------------------------------------------- 1 | tracer = $tracer; 26 | } 27 | 28 | public function start(Request $request): BackgroundSpanHandler 29 | { 30 | $this->span = $this->tracer->start( 31 | 'background', 32 | [ 33 | new HttpMethodTag($request->getMethod()), 34 | new HttpUriTag($request->getRequestUri()), 35 | new SpanKindServerTag(), 36 | new SymfonyComponentTag(), 37 | new SymfonyVersionTag(), 38 | new SymfonyBackgroundTag(), 39 | ] 40 | ); 41 | 42 | return $this; 43 | } 44 | 45 | public function flush(): BackgroundSpanHandler 46 | { 47 | if (null === $this->span) { 48 | return $this; 49 | } 50 | $this->span->finish(); 51 | $this->reset(); 52 | 53 | return $this; 54 | } 55 | 56 | public function reset(): void 57 | { 58 | $this->span = null; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/Bridge/MainSpanLifecycleListener.php: -------------------------------------------------------------------------------- 1 | handler = $handler; 18 | } 19 | 20 | public static function getSubscribedEvents(): array 21 | { 22 | return [ 23 | RequestEvent::class => ['onRequest', 1024], 24 | TerminateEvent::class => ['onTerminate', 4096], 25 | ]; 26 | } 27 | 28 | public function onTerminate(): MainSpanLifecycleListener 29 | { 30 | $this->handler->finish(); 31 | 32 | return $this; 33 | } 34 | 35 | public function onRequest(RequestEvent $event): MainSpanLifecycleListener 36 | { 37 | if (false === $this->isMainRequestEvent($event)) { 38 | return $this; 39 | } 40 | $this->handler->start($event->getRequest()); 41 | 42 | return $this; 43 | } 44 | 45 | /** 46 | * Use non-deprecated check method if availble 47 | * 48 | * @param KernelEvent $event 49 | * 50 | * @return bool 51 | */ 52 | private function isMainRequestEvent(KernelEvent $event): bool 53 | { 54 | if (\method_exists($event, 'isMainRequest')) { 55 | return $event->isMainRequest(); 56 | } 57 | 58 | return $event->isMasterRequest(); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/Bridge/AppStartSpanListener.php: -------------------------------------------------------------------------------- 1 | tracer = $tracer; 21 | } 22 | 23 | public static function getSubscribedEvents(): array 24 | { 25 | return [RequestEvent::class => ['onRequest', 1023],]; 26 | } 27 | 28 | public function onRequest(RequestEvent $event) 29 | { 30 | if (false === $this->isMainRequestEvent($event)) { 31 | return $this; 32 | } 33 | 34 | $this->tracer 35 | ->start('symfony.start') 36 | ->addTag(new SpanKindServerTag()) 37 | ->addTag(new SymfonyComponentTag()) 38 | ->addTag(new SymfonyVersionTag()) 39 | ->start((int)(1000000 * $event->getRequest()->server->get('REQUEST_TIME_FLOAT', microtime(true)))) 40 | ->finish(); 41 | 42 | return $this; 43 | } 44 | 45 | /** 46 | * Use non-deprecated check method if availble 47 | * 48 | * @param KernelEvent $event 49 | * 50 | * @return bool 51 | */ 52 | private function isMainRequestEvent(KernelEvent $event): bool 53 | { 54 | if (\method_exists($event, 'isMainRequest')) { 55 | return $event->isMainRequest(); 56 | } 57 | 58 | return $event->isMasterRequest(); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/DependencyInjection/DeprecatedAliasesCompilerPass.php: -------------------------------------------------------------------------------- 1 | getAlias('jaeger.span.handler.gloabal') 15 | ->setDeprecated( 16 | ... 17 | $this->getDeprecationMsg( 18 | 'The "%alias_id%" service is deprecated. Use "jaeger.span.handler.global".', 19 | '3.5.0' 20 | ) 21 | ); 22 | } 23 | 24 | /** 25 | * Returns the correct deprecation param's as an array for setDeprecated. 26 | * 27 | * symfony/dependency-injection v5.1 introduces a deprecation notice when calling 28 | * setDeprecation() with less than 3 args and the 29 | * `Symfony\Component\DependencyInjection\Compiler\AliasDeprecatedPublicServicesPass` class was 30 | * introduced at the same time. By checking if this class exists, 31 | * we can determine the correct param count to use when calling setDeprecated. 32 | * 33 | * @param string $message 34 | * @param string $version 35 | * 36 | * @return array 37 | */ 38 | private function getDeprecationMsg(string $message, string $version): array 39 | { 40 | if (class_exists(AliasDeprecatedPublicServicesPass::class)) { 41 | return [ 42 | 'code-tool/jaeger-client-symfony-bridge', 43 | $version, 44 | $message, 45 | ]; 46 | } 47 | 48 | return [true, $message]; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/Bridge/JaegerSamplerFactory.php: -------------------------------------------------------------------------------- 1 | isApcuOn()) { 38 | return new ProbabilisticSampler((float)$param); 39 | } 40 | 41 | return new RateLimitingSampler((float)$param, new ConstGenerator()); 42 | case 'adaptive': 43 | if (false === $this->isApcuOn()) { 44 | return new ProbabilisticSampler((float)$param); 45 | } 46 | 47 | return new AdaptiveSampler( 48 | new RateLimitingSampler((float)$param, new OperationGenerator()), 49 | new ProbabilisticSampler((float)$param) 50 | ); 51 | default: 52 | throw new \RuntimeException( 53 | \sprintf('Unknown sampler type "%s"', $type) 54 | ); 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/Bridge/ContextListener.php: -------------------------------------------------------------------------------- 1 | injectable = $injectable; 24 | $this->extractor = $extractor; 25 | } 26 | 27 | public static function getSubscribedEvents(): array 28 | { 29 | return [ 30 | ConsoleCommandEvent::class => ['onCommand', 8192], 31 | RequestEvent::class => ['onRequest', 8192], 32 | ]; 33 | } 34 | 35 | public function onCommand(): void 36 | { 37 | $this->inject(); 38 | } 39 | 40 | public function inject(): void 41 | { 42 | if (null === ($context = $this->extractor->extract())) { 43 | return; 44 | } 45 | $this->injectable->assign($context); 46 | } 47 | 48 | public function onRequest(RequestEvent $event): void 49 | { 50 | if (false === $this->isMainRequestEvent($event)) { 51 | return; 52 | } 53 | $this->inject(); 54 | } 55 | 56 | /** 57 | * Use non-deprecated check method if availble 58 | * 59 | * @param KernelEvent $event 60 | * 61 | * @return bool 62 | */ 63 | private function isMainRequestEvent(KernelEvent $event): bool 64 | { 65 | if (\method_exists($event, 'isMainRequest')) { 66 | return $event->isMainRequest(); 67 | } 68 | 69 | return $event->isMasterRequest(); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/Name/Generator/CommandNameGenerator.php: -------------------------------------------------------------------------------- 1 | generators = $generators; 25 | } 26 | 27 | public function add(string $regexp, NameGeneratorInterface $generator): CommandNameGenerator 28 | { 29 | $this->generators[$regexp] = $generator; 30 | 31 | return $this; 32 | } 33 | 34 | public static function getSubscribedEvents(): array 35 | { 36 | return [ 37 | // Subscribe after route was resolved and request attributes were set 38 | ConsoleCommandEvent::class => ['onCommand', 31], 39 | ConsoleTerminateEvent::class => ['onTerminate'], 40 | ]; 41 | } 42 | 43 | public function onCommand(ConsoleCommandEvent $event): void 44 | { 45 | if (null === $command = $event->getCommand()) { 46 | return; 47 | } 48 | 49 | $this->name = (string)$command->getName(); 50 | } 51 | 52 | public function onTerminate(): CommandNameGenerator 53 | { 54 | $this->name = ''; 55 | 56 | return $this; 57 | } 58 | 59 | public function generate(): string 60 | { 61 | foreach ($this->generators as $regexp => $generator) { 62 | if (false === \preg_match($regexp, $this->name)) { 63 | continue; 64 | } 65 | 66 | return $generator->generate(); 67 | } 68 | 69 | return ''; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/Name/Generator/DefaultNameGenerator.php: -------------------------------------------------------------------------------- 1 | ['onRequest', 31], 22 | ConsoleCommandEvent::class => ['onCommand', 31], 23 | TerminateEvent::class => ['onTerminate', -16384], 24 | ConsoleTerminateEvent::class => ['onTerminate'], 25 | ]; 26 | } 27 | 28 | public function onCommand(ConsoleCommandEvent $event): void 29 | { 30 | if (null === $command = $event->getCommand()) { 31 | return; 32 | } 33 | 34 | $this->name = (string)$command->getName(); 35 | } 36 | 37 | public function onRequest(RequestEvent $event): void 38 | { 39 | $request = $event->getRequest(); 40 | if (null !== $request->attributes->get('is_fragment')) { 41 | $this->name = (null !== $controller = $request->attributes->get('_controller', null)) 42 | ? sprintf('fragment.%s', $controller) 43 | : 'fragment'; 44 | 45 | return; 46 | } 47 | 48 | $this->name = $request->attributes->get('_route', $request->getRequestUri()); 49 | } 50 | 51 | public function onTerminate(): void 52 | { 53 | $this->reset(); 54 | } 55 | 56 | public function reset(): void 57 | { 58 | $this->name = ''; 59 | } 60 | 61 | public function generate(): string 62 | { 63 | return $this->name; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/Name/Generator/RequestNameGenerator.php: -------------------------------------------------------------------------------- 1 | generators = $generators; 26 | } 27 | 28 | public function add(string $regexp, NameGeneratorInterface $generator): RequestNameGenerator 29 | { 30 | $this->generators[$regexp] = $generator; 31 | 32 | return $this; 33 | } 34 | 35 | public static function getSubscribedEvents(): array 36 | { 37 | return [ 38 | // Subscribe after route was resolved and request attributes were set 39 | RequestEvent::class => ['onRequest', 31], 40 | TerminateEvent::class => ['onTerminate', -16384], 41 | ]; 42 | } 43 | 44 | public function onRequest(RequestEvent $event): void 45 | { 46 | $this->route = $event->getRequest()->attributes->get('_route', $event->getRequest()->getRequestUri()); 47 | } 48 | 49 | public function onTerminate(): RequestNameGenerator 50 | { 51 | $this->reset(); 52 | 53 | return $this; 54 | } 55 | 56 | public function reset(): void 57 | { 58 | $this->route = ''; 59 | } 60 | 61 | public function generate(): string 62 | { 63 | foreach ($this->generators as $regexp => $generator) { 64 | if (1 !== \preg_match($regexp, $this->route)) { 65 | continue; 66 | } 67 | 68 | return $generator->generate(); 69 | } 70 | 71 | return ''; 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/Debug/Extractor/CookieDebugExtractor.php: -------------------------------------------------------------------------------- 1 | cookieName = $cookieName; 21 | } 22 | 23 | public function onRequest(RequestEvent $event): void 24 | { 25 | if (false === $this->isMainRequestEvent($event)) { 26 | return; 27 | } 28 | $request = $event->getRequest(); 29 | if (false === $request->cookies->has($this->cookieName)) { 30 | return; 31 | } 32 | $this->debugId = (string)$request->cookies->get($this->cookieName, ''); 33 | } 34 | 35 | public function onTerminate(TerminateEvent $event): void 36 | { 37 | if (false === $this->isMainRequestEvent($event)) { 38 | return; 39 | } 40 | 41 | $this->reset(); 42 | } 43 | 44 | public function reset(): void 45 | { 46 | $this->debugId = ''; 47 | } 48 | 49 | public function getDebug(): string 50 | { 51 | return $this->debugId; 52 | } 53 | 54 | public static function getSubscribedEvents(): array 55 | { 56 | return [ 57 | RequestEvent::class => ['onRequest', 16384], 58 | TerminateEvent::class => ['onTerminate'], 59 | ]; 60 | } 61 | 62 | /** 63 | * Use non-deprecated check method if availble 64 | * 65 | * @param KernelEvent $event 66 | * 67 | * @return bool 68 | */ 69 | private function isMainRequestEvent(KernelEvent $event): bool 70 | { 71 | if (\method_exists($event, 'isMainRequest')) { 72 | return $event->isMainRequest(); 73 | } 74 | 75 | return $event->isMasterRequest(); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Symfony Bridge for Jaeger library 2 | 3 | ## Getting started 4 | 5 | Register JaegerBundle like any other bundle for Symfony 4+ 6 | 7 | ```php 8 | // bundles.php 9 | return [ 10 | // ... 11 | \Jaeger\Symfony\JaegerBundle::class => ['all' => true], 12 | // ... 13 | ]; 14 | ``` 15 | 16 | ## Denylist sampling operations 17 | 18 | This feature allows to disable sampling for deny-listed operations. 19 | 20 | It will be useful when your infrastructure initiates some operations which you are 21 | not insterested for tracking in Jaeger. 22 | 23 | Operation names used in package configuration refers to first (parent) span operation name 24 | (https://www.jaegertracing.io/docs/latest/architecture/#span). 25 | 26 | > Hint: if you use default name generator (class `\Jaeger\Symfony\Name\Generator\DefaultNameGenerator`), 27 | > your operation name for HTTP requests will be the same as matched symfony route name. 28 | 29 | Example bundle config with denylist feature: 30 | 31 | ```yaml 32 | # config/jaeger.yaml 33 | jaeger: 34 | denylist: 35 | operation_names: 36 | - 'healthcheck' 37 | - 'metrics' 38 | ``` 39 | 40 | 41 | ## Name generation options 42 | 43 | You can configure custom name generators based on regular expression pattern, which will be evaluated for operation name. 44 | 45 | Configuration for this feature looks like key-value list, where key - regexp pattern, value - custom name generator DI service id (see details below). 46 | 47 | Name generator should implement an `Jaeger\Symfony\Name\Generator\NameGeneratorInterface` interface. 48 | As a custom name generator you can specify a full DI service id, or just the suffix if your name generator service is named as `jaeger.name.generator.*`. 49 | Keys are considered body of the regular expression pattern, do not put any modifiers (e.g. `/i`, `/g`) or slashes; `route` of the request or `name` of the command should match to use alternative generator. 50 | Expressions are checked top to bottom, if no match is found, default generator will be used 51 | 52 | Example bundle config with name generation feature: 53 | 54 | ```yaml 55 | # config/jaeger.yaml 56 | jaeger: 57 | name_generator: 58 | max_length: 32 59 | command: 60 | '^app:report:.+': 'my_service_generator_alias' 61 | .* : 'controller' 62 | request: 63 | 'user_routes_\w+': 'my_service_generator_alias' 64 | ``` 65 | -------------------------------------------------------------------------------- /src/Bridge/DebugListener.php: -------------------------------------------------------------------------------- 1 | debuggable = $debuggable; 24 | $this->extractor = $extractor; 25 | } 26 | 27 | public static function getSubscribedEvents(): array 28 | { 29 | return [ 30 | ConsoleCommandEvent::class => ['onCommand', 8192], 31 | RequestEvent::class => ['onRequest', 8192], 32 | ConsoleTerminateEvent::class => ['onTerminate'], 33 | TerminateEvent::class => ['onTerminate'], 34 | ]; 35 | } 36 | 37 | public function onTerminate(): void 38 | { 39 | $this->debuggable->disable(); 40 | } 41 | 42 | public function onCommand(): void 43 | { 44 | if ('' === ($debugId = $this->extractor->getDebug())) { 45 | return; 46 | } 47 | $this->debuggable->enable($debugId); 48 | } 49 | 50 | public function onRequest(RequestEvent $event) 51 | { 52 | if (false === $this->isMainRequestEvent($event)) { 53 | return; 54 | } 55 | if ('' === ($debugId = $this->extractor->getDebug())) { 56 | return; 57 | } 58 | $this->debuggable->enable($debugId); 59 | } 60 | 61 | /** 62 | * Use non-deprecated check method if availble 63 | * 64 | * @param KernelEvent $event 65 | * 66 | * @return bool 67 | */ 68 | private function isMainRequestEvent(KernelEvent $event): bool 69 | { 70 | if (\method_exists($event, 'isMainRequest')) { 71 | return $event->isMainRequest(); 72 | } 73 | 74 | return $event->isMasterRequest(); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/Bridge/MainSpanHandler.php: -------------------------------------------------------------------------------- 1 | tracer = $tracer; 33 | $this->nameGenerator = $nameGenerator; 34 | } 35 | 36 | public function start(Request $request): MainSpanHandler 37 | { 38 | $this->span = $this->tracer->start( 39 | 'main.start', 40 | [ 41 | new HttpMethodTag($request->getMethod()), 42 | new HttpUriTag($request->getRequestUri()), 43 | new SpanKindServerTag(), 44 | new SymfonyComponentTag(), 45 | new SymfonyVersionTag(), 46 | ] 47 | )->start((int)(1000000 * $request->server->get('REQUEST_TIME_FLOAT', microtime(true)))); 48 | 49 | return $this; 50 | } 51 | 52 | public function name(): MainSpanHandler 53 | { 54 | if (null === $this->span) { 55 | return $this; 56 | } 57 | $this->span->operationName = $this->nameGenerator->generate(); 58 | 59 | return $this; 60 | } 61 | 62 | public function finish(): void 63 | { 64 | if (null === $this->span) { 65 | return; 66 | } 67 | $this->durationUsec = microtime(true) * 1000000 - $this->span->startTime; 68 | } 69 | 70 | public function flush(): void 71 | { 72 | if (null === $this->span || null === $this->durationUsec) { 73 | return; 74 | } 75 | $this->span->finish((int)$this->durationUsec); 76 | $this->reset(); 77 | } 78 | 79 | public function reset(): void 80 | { 81 | $this->span = null; 82 | $this->durationUsec = null; 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/Context/Extractor/HeaderContextExtractor.php: -------------------------------------------------------------------------------- 1 | registry = $registry; 27 | $this->format = $format; 28 | $this->headerName = $headerName; 29 | } 30 | 31 | public static function getSubscribedEvents(): array 32 | { 33 | return [ 34 | RequestEvent::class => ['onRequest', 16384], 35 | TerminateEvent::class => ['onTerminate'], 36 | ]; 37 | } 38 | 39 | public function extract(): ?SpanContext 40 | { 41 | return $this->context; 42 | } 43 | 44 | public function onTerminate(TerminateEvent $event): void 45 | { 46 | if (false === $this->isMainRequestEvent($event)) { 47 | return; 48 | } 49 | 50 | $this->reset(); 51 | } 52 | 53 | public function onRequest(RequestEvent $event): void 54 | { 55 | if (false === $this->isMainRequestEvent($event)) { 56 | return; 57 | } 58 | $request = $event->getRequest(); 59 | if ($request->headers->has($this->headerName) 60 | && ($context = $this->registry[$this->format]->decode($request->headers->get($this->headerName)))) { 61 | $this->context = $context; 62 | } 63 | } 64 | 65 | /** 66 | * Use non-deprecated check method if availble 67 | * 68 | * @param KernelEvent $event 69 | * 70 | * @return bool 71 | */ 72 | private function isMainRequestEvent(KernelEvent $event): bool 73 | { 74 | if (\method_exists($event, 'isMainRequest')) { 75 | return $event->isMainRequest(); 76 | } 77 | 78 | return $event->isMasterRequest(); 79 | } 80 | 81 | public function reset(): void 82 | { 83 | $this->context = null; 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/DependencyInjection/JaegerExtension.php: -------------------------------------------------------------------------------- 1 | load('services.yml'); 21 | 22 | $configuration = new Configuration(); 23 | $config = $this->processConfiguration($configuration, $configs); 24 | 25 | if ($this->isConfigEnabled($container, $config['denylist'])) { 26 | $container->setParameter('jaeger.sampler.operation_denylist', $config['denylist']['operation_names']); 27 | $loader->load('denylist.yml'); 28 | } 29 | 30 | if ($this->isConfigEnabled($container, $config['name_generator'])) { 31 | if ($config['name_generator']['max_length']) { 32 | $loader->load('shorten.yml'); 33 | $container->setParameter('jaeger.name.max_length', $config['name_generator']['max_length']); 34 | } 35 | 36 | foreach ($config['name_generator']['request'] as $pattern => $customGeneratorId) { 37 | $regexp = \sprintf('/%s/', $pattern); 38 | 39 | $shortenedGeneratorId = \sprintf('jaeger.name.generator.%s', $customGeneratorId); 40 | if ($container->has($shortenedGeneratorId)) { 41 | $customGeneratorId = $shortenedGeneratorId; 42 | } 43 | 44 | $container->getDefinition('jaeger.name.generator.request') 45 | ->addMethodCall( 46 | 'add', 47 | [$regexp, new Reference($customGeneratorId)] 48 | ); 49 | } 50 | 51 | foreach ($config['name_generator']['command'] as $pattern => $customGeneratorId) { 52 | $regexp = \sprintf('/%s/', $pattern); 53 | 54 | $shortenedGeneratorId = \sprintf('jaeger.name.generator.%s', $customGeneratorId); 55 | if ($container->has($shortenedGeneratorId)) { 56 | $customGeneratorId = $shortenedGeneratorId; 57 | } 58 | 59 | $container->getDefinition('jaeger.name.generator.command') 60 | ->addMethodCall( 61 | 'add', 62 | [$regexp, new Reference($customGeneratorId)] 63 | ); 64 | } 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/Bridge/RequestSpanListener.php: -------------------------------------------------------------------------------- 1 | spans = $stack; 35 | $this->nameGenerator = $nameGenerator; 36 | $this->tracer = $tracer; 37 | } 38 | 39 | public static function getSubscribedEvents(): array 40 | { 41 | return [ 42 | RequestEvent::class => ['onRequest', 29], 43 | ResponseEvent::class => ['onResponse', -1024], 44 | ExceptionEvent::class => ['onKernelException', 0], 45 | ]; 46 | } 47 | 48 | public function onResponse(ResponseEvent $event): void 49 | { 50 | if ($this->spans->isEmpty()) { 51 | return; 52 | } 53 | $this->spans->pop()->addTag(new HttpCodeTag($event->getResponse()->getStatusCode()))->finish(); 54 | } 55 | 56 | public function onRequest(RequestEvent $event): void 57 | { 58 | $request = $event->getRequest(); 59 | $span = $this->tracer->start( 60 | $this->nameGenerator->generate(), 61 | [ 62 | new HttpMethodTag($request->getMethod()), 63 | new HttpUriTag($request->getRequestUri()), 64 | new SpanKindServerTag(), 65 | new SymfonyComponentTag(), 66 | new SymfonyVersionTag(), 67 | ] 68 | ); 69 | if ($this->isMainRequestEvent($event)) { 70 | $span->addTag(new SymfonyMainRequestTag()); 71 | } else { 72 | $span->addTag(new SymfonySubRequestTag()); 73 | } 74 | $this->spans->push($span); 75 | } 76 | 77 | public function onKernelException(ExceptionEvent $event): void 78 | { 79 | if ($this->spans->isEmpty()) { 80 | return; 81 | } 82 | $exception = $event->getThrowable(); 83 | $this->spans->top() 84 | ->addTag(new ErrorTag()) 85 | ->addLog(new ErrorLog($exception->getMessage(), $exception->getTraceAsString())); 86 | } 87 | 88 | /** 89 | * Use non-deprecated check method if availble 90 | * 91 | * @param KernelEvent $event 92 | * 93 | * @return bool 94 | */ 95 | private function isMainRequestEvent(KernelEvent $event): bool 96 | { 97 | if (\method_exists($event, 'isMainRequest')) { 98 | return $event->isMainRequest(); 99 | } 100 | 101 | return $event->isMasterRequest(); 102 | } 103 | 104 | public function reset(): void 105 | { 106 | // make stack empty to avoid memory leaks 107 | while (false === $this->spans->isEmpty()) { 108 | $this->spans->pop(); 109 | } 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /src/Resources/services.yml: -------------------------------------------------------------------------------- 1 | parameters: 2 | service_name: app 3 | env(JAEGER_HOST): localhost 4 | env(JAEGER_PORT): '6832' 5 | env(JAEGER_BUFFER_SIZE): '32768' 6 | env(JAEGER_SAMPLER_TYPE): adaptive 7 | env(JAEGER_SAMPLER_PARAM): '0.001' 8 | env(JAEGER_CONTEXT_FORMAT): 'text' 9 | env(JAEGER_CONTEXT_ENV): 'UBER_TRACE_ID' 10 | env(JAEGER_CONTEXT_HEADER): 'uber-trace-id' 11 | env(JAEGER_DEBUG_ENV): 'debug' 12 | env(JAEGER_DEBUG_COOKIE): 'debug' 13 | env(JAEGER_SERVICE_NAME): '%service_name%' 14 | env(JAEGER_SPAN_BATCH): '16' 15 | env(JAEGER_TRACE_128): '0' 16 | 17 | services: 18 | spl.stack: 19 | class: SplStack 20 | shared: false 21 | spl.priority.queue: 22 | class: SplPriorityQueue 23 | shared: false 24 | id.generator.random: 25 | class: Jaeger\Id\RandomIntGenerator 26 | id.generator.span: '@id.generator.random' 27 | jaeger.codec.text: 28 | class: Jaeger\Codec\TextCodec 29 | tags: 30 | - {name: 'jaeger.codec', alias: 'text'} 31 | jaeger.codec.registry: 32 | class: Jaeger\Codec\CodecRegistry 33 | calls: 34 | - 35 | method: offsetSet 36 | arguments: ['text', '@jaeger.codec.text'] 37 | jaeger.sampler.factory: 38 | class: Jaeger\Symfony\Bridge\JaegerSamplerFactory 39 | jaeger.sampler: 40 | class: Jaeger\Sampler\SamplerInterface 41 | factory: ['@jaeger.sampler.factory', 'sampler'] 42 | arguments: ['%env(JAEGER_SAMPLER_TYPE)%', '%env(JAEGER_SAMPLER_PARAM)%'] 43 | jaeger.span.factory: 44 | class: Jaeger\Span\Factory\SpanFactory 45 | arguments: ['@id.generator.span', '@jaeger.sampler', '%env(bool:JAEGER_TRACE_128)%'] 46 | client.thrift: 47 | class: Jaeger\Client\ThriftClient 48 | arguments: ['%env(JAEGER_SERVICE_NAME)%', '@thrift.agent', '%env(JAEGER_SPAN_BATCH)%'] 49 | thrift.agent: 50 | class: Jaeger\Thrift\Agent\AgentClient 51 | arguments: ['@thrift.protocol'] 52 | thrift.protocol.compact: 53 | class: Thrift\Protocol\TCompactProtocol 54 | arguments: ['@thrift.transport'] 55 | thrift.protocol.binary: 56 | class: Thrift\Protocol\TBinaryProtocol 57 | arguments: ['@thrift.transport'] 58 | thrift.protocol: '@thrift.protocol.binary' 59 | thrift.transport.udp: 60 | class: Jaeger\Symfony\Transport\SymfonyUDPTransport 61 | arguments: ['%env(JAEGER_HOST)%', '%env(JAEGER_PORT)%'] 62 | thrift.transport.buffered: 63 | class: Jaeger\Symfony\Transport\SymfonyBufferedTransport 64 | arguments: ['@thrift.transport.udp', '%env(JAEGER_BUFFER_SIZE)%', '%env(JAEGER_BUFFER_SIZE)%'] 65 | calls: 66 | - 67 | method: open 68 | arguments: [] 69 | thrift.transport: '@thrift.transport.udp' 70 | jaeger.span.manager.stack: 71 | class: Jaeger\Span\StackSpanManager 72 | jaeger.span.manager: '@jaeger.span.manager.stack' 73 | jaeger.context.manager: '@jaeger.span.manager' 74 | jaeger.tracer.abstract: 75 | class: Jaeger\Tracer\Tracer 76 | abstract: true 77 | arguments: 78 | - '@jaeger.span.manager' 79 | - '@jaeger.span.factory' 80 | - '@client.thrift' 81 | jaeger.tracer: 82 | class: Jaeger\Tracer\Tracer 83 | parent: jaeger.tracer.abstract 84 | tags: 85 | - { name: 'kernel.reset', method: 'reset' } 86 | jaeger.debuggable: '@jaeger.tracer' 87 | jaeger.flushable: '@jaeger.tracer' 88 | jaeger.context.extractor.env: 89 | class: Jaeger\Symfony\Context\Extractor\EnvContextExtractor 90 | arguments: 91 | - '@jaeger.codec.registry' 92 | - '%env(JAEGER_CONTEXT_FORMAT)%' 93 | - '%env(JAEGER_CONTEXT_ENV)%' 94 | tags: 95 | - {name: 'kernel.event_subscriber' } 96 | - {name: 'jaeger.context.extractor'} 97 | jaeger.context.extractor.header: 98 | class: Jaeger\Symfony\Context\Extractor\HeaderContextExtractor 99 | arguments: 100 | - '@jaeger.codec.registry' 101 | - '%env(JAEGER_CONTEXT_FORMAT)%' 102 | - '%env(JAEGER_CONTEXT_HEADER)%' 103 | tags: 104 | - {name: 'kernel.event_subscriber' } 105 | - {name: 'jaeger.context.extractor'} 106 | - {name: 'kernel.reset', method: 'reset'} 107 | jaeger.context.extractor.chain: 108 | class: Jaeger\Symfony\Context\Extractor\ContextExtractorChain 109 | arguments: 110 | - '@spl.priority.queue' 111 | jaeger.context.extractor: 112 | alias: 'jaeger.context.extractor.chain' 113 | jaeger.debug.extractor.env: 114 | class: Jaeger\Symfony\Debug\Extractor\EnvDebugExtractor 115 | arguments: 116 | - '%env(JAEGER_DEBUG_ENV)%' 117 | tags: 118 | - {name: 'kernel.event_subscriber' } 119 | - {name: 'jaeger.debug.extractor'} 120 | - {name: 'kernel.reset', method: 'reset'} 121 | jaeger.debug.extractor.cookie: 122 | class: Jaeger\Symfony\Debug\Extractor\CookieDebugExtractor 123 | arguments: 124 | - '%env(JAEGER_DEBUG_COOKIE)%' 125 | tags: 126 | - {name: 'kernel.event_subscriber' } 127 | - {name: 'jaeger.debug.extractor'} 128 | - {name: 'kernel.reset', method: 'reset'} 129 | jaeger.debug.extractor.chain: 130 | class: Jaeger\Symfony\Debug\Extractor\DebugExtractorChain 131 | arguments: 132 | - '@spl.priority.queue' 133 | jaeger.debug.extractor: 134 | alias: 'jaeger.debug.extractor.chain' 135 | jaeger.name.generator.controller: 136 | class: Jaeger\Symfony\Name\Generator\ControllerNameGenerator 137 | tags: 138 | - {name: 'kernel.event_subscriber' } 139 | - {name: 'kernel.reset', method: 'reset'} 140 | jaeger.name.generator.default: 141 | class: Jaeger\Symfony\Name\Generator\DefaultNameGenerator 142 | tags: 143 | - {name: 'kernel.event_subscriber' } 144 | - {name: 'jaeger.name.generator', priority: -16384} 145 | - {name: 'kernel.reset', method: 'reset'} 146 | jaeger.name.generator.request: 147 | class: Jaeger\Symfony\Name\Generator\RequestNameGenerator 148 | tags: 149 | - {name: 'kernel.event_subscriber' } 150 | - {name: 'jaeger.name.generator', priority: -1024} 151 | - {name: 'kernel.reset', method: 'reset'} 152 | jaeger.name.generator.command: 153 | class: Jaeger\Symfony\Name\Generator\CommandNameGenerator 154 | tags: 155 | - {name: 'kernel.event_subscriber' } 156 | - {name: 'jaeger.name.generator', priority: -1024} 157 | jaeger.name.generator.chain: 158 | class: Jaeger\Symfony\Name\Generator\NameGeneratorChain 159 | arguments: 160 | - '@spl.priority.queue' 161 | jaeger.name.generator: 162 | alias: 'jaeger.name.generator.chain' 163 | jaeger.span.handler.background: 164 | class: Jaeger\Symfony\Bridge\BackgroundSpanHandler 165 | arguments: ['@jaeger.tracer'] 166 | tags: 167 | - { name: 'kernel.reset', method: 'reset' } 168 | jaeger.span.handler.main: 169 | class: Jaeger\Symfony\Bridge\MainSpanHandler 170 | arguments: ['@jaeger.tracer', '@jaeger.name.generator'] 171 | tags: 172 | - { name: 'kernel.reset', method: 'reset' } 173 | jaeger.span.handler.global: '@jaeger.span.handler.main' 174 | jaeger.debug.listener: 175 | class: Jaeger\Symfony\Bridge\DebugListener 176 | arguments: 177 | - '@jaeger.debuggable' 178 | - '@jaeger.debug.extractor' 179 | tags: 180 | - {name: 'kernel.event_subscriber' } 181 | jaeger.context.listener: 182 | class: Jaeger\Symfony\Bridge\ContextListener 183 | arguments: 184 | - '@jaeger.span.manager' 185 | - '@jaeger.context.extractor' 186 | tags: 187 | - {name: 'kernel.event_subscriber' } 188 | jaeger.request.span.listener: 189 | class: Jaeger\Symfony\Bridge\RequestSpanListener 190 | arguments: 191 | - '@spl.stack' 192 | - '@jaeger.name.generator' 193 | - '@jaeger.tracer' 194 | tags: 195 | - { name: 'kernel.event_subscriber' } 196 | - { name: 'kernel.reset', method: 'reset' } 197 | jaeger.global.span.listener.lifecycle: 198 | class: Jaeger\Symfony\Bridge\MainSpanLifecycleListener 199 | arguments: ['@jaeger.span.handler.main'] 200 | tags: 201 | - { name: 'kernel.event_subscriber' } 202 | jaeger.global.span.listener.name: 203 | class: Jaeger\Symfony\Bridge\MainSpanNameListener 204 | arguments: ['@jaeger.span.handler.main'] 205 | tags: 206 | - {name: 'kernel.event_subscriber' } 207 | jaeger.app.start.listener: 208 | class: Jaeger\Symfony\Bridge\AppStartSpanListener 209 | arguments: ['@jaeger.tracer'] 210 | tags: 211 | - {name: 'kernel.event_subscriber' } 212 | jaeger.tracer.bridge.symfony: 213 | class: Jaeger\Symfony\Bridge\TracerBridge 214 | arguments: ['@jaeger.flushable'] 215 | tags: 216 | - {name: 'kernel.event_subscriber' } 217 | jaeger.span.background.listener.start: 218 | class: Jaeger\Symfony\Bridge\BackgroundStartListener 219 | arguments: ['@jaeger.span.handler.background'] 220 | tags: 221 | - {name: 'kernel.event_subscriber' } 222 | jaeger.span.handler.listener.flush: 223 | class: Jaeger\Symfony\Bridge\MainSpanFlushListener 224 | arguments: ['@jaeger.span.handler.background', '@jaeger.span.handler.main'] 225 | tags: 226 | - {name: 'kernel.event_subscriber' } 227 | jaeger.exception.listener: 228 | class: Jaeger\Symfony\Bridge\ExceptionListener 229 | arguments: 230 | - '@jaeger.span.manager' 231 | tags: 232 | - {name: 'kernel.event_subscriber'} 233 | # deprecated since 3.5.0 234 | jaeger.span.handler.gloabal: 235 | alias: jaeger.span.handler.global 236 | 237 | --------------------------------------------------------------------------------