eerzho/opentelemetry-auto-class-symfony
Install Dependencies:
Ensure ext-opentelemetry is installed (PECL or via Docker) and PHP ≥8.2, Symfony ≥6.0.
pecl install opentelemetry
composer require eerzho/opentelemetry-auto-class-symfony
Register Bundle:
Add to config/bundles.php:
return [
OpenTelemetry\Contrib\Instrumentation\Class\Symfony\TraceableBundle::class => ['all' => true],
];
Annotate a Service:
Add #[Traceable] to a container-managed class:
#[Traceable]
class OrderService {
public function create(array $items) { /* Auto-traced */ }
}
Verify Tracing:
Trigger the method and check your OpenTelemetry backend (e.g., Jaeger) for spans named:
App\Service\OrderService::create.
Debugging a Slow API Endpoint:
#[Traceable].Attribute-Based Instrumentation:
#[Traceable]) for full method coverage.#[Traceable(exclude: ['healthCheck'])]
class PaymentService { ... }
#[Traceable(name: "ProcessOrder")]
class OrderProcessor { ... }
Integration with Symfony Services:
#[Traceable]
class ProcessOrderCommandHandler { ... }
#[Traceable]
class OrderCreatedListener { ... }
#[Traceable]
class OrderRepository { ... }
Context Propagation:
symfony/http-client instrumentation for full request/response tracing.Dynamic Tracing:
#[Arguments(exclude: [...])] to hide sensitive data (e.g., passwords, tokens) in spans.#[Arguments(exclude: ['creditCard'])]
public function charge(CreditCard $card, float $amount) { ... }
Conditional Instrumentation:
OTEL_PHP_DISABLED_INSTRUMENTATIONS=class.%kernel.environment% to toggle via compiler passes:
if ('prod' !== $container->getParameter('kernel.environment')) {
$container->setParameter('otel.class.instrumentation.enabled', false);
}
Custom Span Attributes:
use OpenTelemetry\API\Trace\TracerInterface;
#[Traceable]
class AnalyticsService {
public function __construct(private TracerInterface $tracer) {}
public function trackEvent(string $event) {
$span = $this->tracer->spanBuilder('track_event')->startSpan();
$span->setAttribute('event.type', $event);
// ...
}
}
Symfony Compiler Passes:
// src/Compiler/TraceablePass.php
use OpenTelemetry\Contrib\Instrumentation\Class\Symfony\Compiler\TraceableCompilerPass;
class CustomTraceablePass extends TraceableCompilerPass {
public function process(ContainerConfigurator $container): void {
// Custom logic (e.g., filter services by tag)
$container->attributes()
->loadFromConfig($this->findServicesToInstrument());
}
}
OpenTelemetry Configuration:
opentelemetry.ini:
opentelemetry.sampler = always_on
opentelemetry.exporter = otlp
opentelemetry.endpoint = "http://otel-collector:4317"
Testing:
use OpenTelemetry\API\Trace\TracerInterface;
$tracer = $this->createMock(TracerInterface);
$this->container->set(TracerInterface::class, $tracer);
$tracer->expects($this->once())->method('spanBuilder')->with('App\Service\OrderService::create');
Extension Dependency:
ext-opentelemetry may not be available in shared hosting or CI environments.php -m | grep opentelemetry || exit 1
Container Compilation Errors:
TraceableBundle is loaded after conflicting passes in bundles.php.Attribute Reflection Overhead:
#[Traceable] may slow container compilation.symfony/var-dumper:
php bin/console debug:container --env=prod --dump
Span Name Collisions:
App\Service\Method::name) may be too verbose.name parameter:
#[Traceable(name: "Order.Created")]
Argument Serialization:
__toString() or use #[Arguments(exclude: [...])] for sensitive data.Symfony 7+ Changes:
Verify Instrumentation:
php bin/console debug:container --parameter=otel.class.instrumentation.methods
Disable Tracing Temporarily:
OTEL_PHP_DISABLED_INSTRUMENTATIONS=class bin/console your:command
Log Spans:
opentelemetry.exporter = console
Check for Missing Spans:
// ❌ Won't be traced (new instance)
$service = new OrderService();
// ✅ Will be traced (container-managed)
$service = $container->get(OrderService::class);
Bundle Loading Order:
TraceableBundle after FrameworkBundle to avoid conflicts:
return [
Symfony\Bundle\FrameworkBundle\FrameworkBundle::class => ['all' => true],
OpenTelemetry\Contrib\Instrumentation\Class\Symfony\TraceableBundle::class => ['all' => true],
];
Environment-Specific Tracing:
dev environment via compiler pass:
if ('dev' === $container->getParameter('kernel.environment')) {
$container->setParameter('otel.class.instrumentation.enabled', false);
}
Custom Attribute Parsing:
namespace App\Attribute;
use OpenTelemetry\Contrib\Instrumentation\Class\Attribute\Traceable as BaseTraceable;
#[Attribute(Attribute::TARGET_CLASS)]
class Traceable extends BaseTraceable {
public function __construct(
public array $customConfig = [],
public bool $logArguments = true
) {}
}
use OpenTelemetry\Contrib\Instrumentation\Class\Symfony\Compiler\TraceableCompilerPass;
class CustomTraceablePass extends TraceableCompilerPass {
protected function getServicesToInstrument
How can I help you explore Laravel packages today?