open-telemetry/sdk
OpenTelemetry PHP SDK for generating and exporting traces, metrics, and logs. Use with compatible exporters and configure via code or environment variables. Supports Composer autoload-based SDK initialization and global tracer/meter providers.
composer require open-telemetry/sdk
.env:
OTEL_PHP_AUTOLOAD_ENABLED=true
OTEL_SERVICE_NAME=your-laravel-app
OTEL_EXPORTER=otlp
OTEL_EXPORTER_OTLP_ENDPOINT=http://otel-collector:4318
use OpenTelemetry\API\Globals;
Route::get('/tracked', function () {
$tracer = Globals::tracerProvider()->getTracer(__CLASS__);
$span = $tracer->spanBuilder('route-handler')->startSpan();
$span->setAttribute('http.route', route()->getName());
try {
// Your logic here
$span->setStatusCode(200);
} finally {
$span->end();
}
});
examples/sdk_builder.php).otlp exporter with laravel-otel package (if available) or configure manually.// Auto-instrumentation (HTTP, DB, Queues)
$tracerProvider = new \OpenTelemetry\SDK\Trace\TracerProvider();
$tracerProvider->addSpanProcessor(new \OpenTelemetry\SDK\Trace\SpanProcessor\SimpleSpanProcessor(
new \OpenTelemetry\SDK\Trace\SpanExporter\ConsoleSpanExporter()
));
// Manual spans
$span = $tracer->spanBuilder('user-service')
->setAttribute('user.id', $userId)
->startSpan();
$span->addEvent('event-name', ['key' => 'value']);
$span->end();
$meter = Globals::meterProvider()->getMeter('app.metrics');
$counter = $meter->createCounter('request.count');
$counter->add(1, ['route' => 'home']);
// Extract context from HTTP headers
$carrier = [];
$context = \OpenTelemetry\Context\Propagator\TextMapPropagator::extract(
$carrier,
new \ArrayAccessArrayAccess($request->header())
);
// Inject into outbound requests
$outboundCarrier = [];
\OpenTelemetry\Context\Propagator\TextMapPropagator::inject(
$context,
$outboundCarrier,
new \ArrayAccessArrayAccess($response->headers)
);
$resource = new \OpenTelemetry\SemConv\ResourceInfo(
'your-service',
'1.0.0',
'PHP',
'production'
);
$resource->addAttribute('deployment.environment', 'staging');
Service Provider Bootstrapping:
public function boot()
{
$this->configureOtel();
}
protected function configureOtel()
{
$tracerProvider = new \OpenTelemetry\SDK\Trace\TracerProvider();
$tracerProvider->register();
// Add exporters, processors, etc.
}
Middleware for Auto-Tracing:
public function handle($request, Closure $next)
{
$tracer = Globals::tracerProvider()->getTracer('laravel-middleware');
$span = $tracer->spanBuilder('middleware')
->setAttribute('http.method', $request->method())
->startSpan();
try {
return $next($request);
} finally {
$span->end();
}
}
Queue Job Instrumentation:
public function handle()
{
$tracer = Globals::tracerProvider()->getTracer('queue-job');
$span = $tracer->spanBuilder('process-payment')
->setAttribute('job.id', $this->job->id)
->startSpan();
try {
// Job logic
} finally {
$span->end();
}
}
doctrine-dbal-otel or laravel-otel-db for auto-instrumentation.Http\Client\Instrumentation.OpenTelemetry\SDK\Logs\Logger for structured logs with trace context.TraceIdRatioBasedSampler or AlwaysOnSampler via environment variables:
OTEL_TRACES_SAMPLER=TraceIdRatioBased
OTEL_TRACES_SAMPLER_ARG=0.1 # 10% sampling rate
Autoloading Quirks:
OTEL_PHP_AUTOLOAD_ENABLED=true but config is missing, the SDK returns no-op implementations.Span Leaks:
try-finally or context managers:
$span = $tracer->spanBuilder('operation')->startSpan();
// ...
$span->end(); // Critical!
Attribute Limits:
Span::setStatus() for critical metadata instead of attributes.Context Propagation:
Context::with() for explicit context management:
$context = Context::with(\OpenTelemetry\Context\Context::getCurrent(), $span);
Exporter Failures:
ConsoleSpanExporter as fallback:
$exporter = new \OpenTelemetry\SDK\Trace\SpanExporter\ConsoleSpanExporter();
$processor = new \OpenTelemetry\SDK\Trace\SpanProcessor\BatchSpanProcessor($exporter);
Enable Debug Logging:
OTEL_PHP_LOG_LEVEL=debug
OTEL_PHP_LOG_FILE=storage/logs/otel.log
Validate Configuration:
$config = \OpenTelemetry\SDK\Common\Configuration::getDefault();
dump($config->toArray());
Check for Deprecated APIs:
Meter::isEnabled() was removed in v1.1.0. Use MeterProvider::getMeter() directly.Memory Profiling:
SpanProcessor\SimpleSpanProcessor for development to avoid batching overhead.Custom Span Processors:
class CustomProcessor implements \OpenTelemetry\SDK\Trace\SpanProcessor\SpanProcessorInterface
{
public function onStart(\OpenTelemetry\SDK\Trace\Span $span) {}
public function onEnd(\OpenTelemetry\SDK\Trace\Span $span) {
if ($span->getStatus()->isError()) {
// Custom error handling
}
}
public function shutdown() {}
}
Dynamic Resource Attributes:
$resource = new \OpenTelemetry\SemConv\ResourceInfo(...);
$resource->addDetector(new class implements \OpenTelemetry\SDK\Resource\ResourceDetectorInterface {
public function detect(): array {
return ['custom.attr' => config('app.env')];
}
});
Sampler Overrides:
$sampler = new \OpenTelemetry\SDK\Trace\Sampler\AlwaysOnSampler();
$tracerProvider = new \OpenTelemetry\SDK\Trace\TracerProvider();
$tracerProvider->setSampler($sampler);
Exporter Chaining:
$primaryExporter = new \OpenTelemetry\SDK\Trace\SpanExporter\OtlpSpanExporter();
$fallbackExporter = new \OpenTelemetry\SDK\Trace\SpanExporter\ConsoleSpanExporter();
$processor = new \OpenTelemetry\SDK\Trace\SpanProcessor\BatchSpanProcessor(
new \OpenTelemetry\SDK\Trace\SpanExporter\CompositeSpanExporter([$primaryExporter, $fallbackExporter])
);
How can I help you explore Laravel packages today?