open-telemetry/api
OpenTelemetry PHP API package providing the core interfaces and no-op implementations for tracing, metrics, and context propagation. Use it to instrument libraries and apps while remaining exporter/SDK agnostic and compatible with OpenTelemetry.
Install the package:
composer require open-telemetry/api
Initialize OpenTelemetry (requires a compatible SDK like open-telemetry/sdk):
use OpenTelemetry\API\Common\Instrumentation\Configuration;
use OpenTelemetry\API\Common\Instrumentation\ConfigurationProvider;
use OpenTelemetry\API\Common\Instrumentation\HookManager;
// Initialize configuration (example with file-based config)
$config = Configuration::fromFile(__DIR__ . '/otel-config.yaml');
$provider = new ConfigurationProvider($config);
// Register hooks (e.g., for auto-instrumentation)
HookManager::registerHooks();
First Use Case: Tracing a Request
use OpenTelemetry\API\Trace\TracerInterface;
use OpenTelemetry\API\Trace\Span;
$tracer = \OpenTelemetry\API\GlobalTracer::getTracer('my-app');
$span = $tracer->spanBuilder('process-request')->startSpan();
try {
// Business logic here
$span->addEvent('request-processed');
} finally {
$span->end();
}
GlobalTracer::getTracer() for spans.GlobalMeter::getMeter() for counters, gauges, etc.GlobalLogger::getLogger() for structured logging.Propagator::getTextMapPropagator() for HTTP/async contexts.$span = $tracer->spanBuilder('user-auth')
->setAttribute('user.id', $userId)
->startSpan();
// Nest spans
$dbSpan = $tracer->spanBuilder('query-db')
->setParent($span)
->startSpan();
$dbSpan->end();
$span->end();
HookManager::registerHooks() to auto-instrument HTTP requests, database queries, etc.
HookManager::registerHooks([
'http' => true,
'pdo' => true,
]);
$counter = $meter->getCounter('api.requests');
$counter->add(1, ['method' => 'GET']);
$histogram = $meter->getHistogram('api.latency');
$histogram->record($executionTime, ['endpoint' => '/users']);
$propagator = Propagator::getTextMapPropagator();
$carrier = []; // e.g., $_SERVER or custom array
$propagator->inject($carrier, \OpenTelemetry\Context\Context::current());
// Later, extract context
$context = $propagator->extract($carrier);
\OpenTelemetry\Context\Context::storage()->activate($context);
$logger = \OpenTelemetry\API\Logs\GlobalLogger::getLogger('my-app');
$logger->logRecordBuilder()
->setSeverityText('info')
->setBody('User logged in')
->setAttribute('user.id', $userId)
->emit();
Service Provider Integration:
// In AppServiceProvider::boot()
$this->app->singleton(TracerInterface::class, function () {
return \OpenTelemetry\API\GlobalTracer::getTracer('laravel-app');
});
Middleware for Tracing:
use OpenTelemetry\API\Trace\TracerInterface;
class TraceMiddleware
{
public function __construct(private TracerInterface $tracer) {}
public function handle($request, Closure $next)
{
$span = $this->tracer->spanBuilder('http.request')
->setAttribute('http.method', $request->method())
->setAttribute('http.url', $request->url())
->startSpan();
try {
return $next($request);
} finally {
$span->end();
}
}
}
Queue Job Tracing:
use OpenTelemetry\API\Trace\TracerInterface;
class ProcessOrderJob implements ShouldQueue
{
public function __construct(private TracerInterface $tracer) {}
public function handle()
{
$span = $this->tracer->spanBuilder('process-order')->startSpan();
try {
// Job logic
} finally {
$span->end();
}
}
}
Database Query Tracing:
Use the PDO hook (via HookManager) to auto-instrument queries:
HookManager::registerHooks(['pdo' => true]);
Deprecated Interfaces:
InstrumentationInterface and ConfigurationResolver are deprecated (since v1.9.0). Use ConfigurationProvider instead.// Old (deprecated)
$configResolver = new InstrumentationInterface();
// New
$config = Configuration::fromEnv();
$provider = new ConfigurationProvider($config);
Context Leaks:
Context::storage()->activate($context) and Context::storage()->deactivate($context).Span Suppression:
Span::isRecording() before adding events/attributes.Attribute Validation:
string/int) are dropped. Ensure consistent types:
// Bad (may be dropped)
$span->setAttribute('tags', ['key1' => 'value1', 'key2' => 123]);
// Good
$span->setAttribute('tags', ['key1' => 'value1', 'key2' => '123']);
Logger Deprecations:
EventLogger is deprecated. Use GlobalLogger for structured logging.Enable Debug Logging:
Set the OTEL_LOG_LEVEL environment variable:
export OTEL_LOG_LEVEL=debug
Or in code:
putenv('OTEL_LOG_LEVEL=debug');
Span Debugging:
Span::setAttribute('debug', true) to mark spans for detailed logging.Span::getStatus() for errors:
if (!$span->getStatus()->isOk()) {
error_log('Span failed: ' . $span->getStatus()->getDescription());
}
Context Propagation Issues:
traceparent, tracestate) are correctly injected/extracted.Propagator::getTextMapPropagator()->getKeys() to inspect expected keys.Performance Overhead:
HookManager::registerHooks(['pdo' => false]); // Disable PDO hook
Custom Propagators:
Implement PropagatorInterface for custom context propagation (e.g., gRPC, Kafka):
class CustomPropagator implements PropagatorInterface {
public function inject(Context $context, array &$carrier) { /* ... */ }
public function extract(array $carrier): Context { /* ... */ }
}
Span Processors:
Use SpanProcessorInterface to filter/modify spans before export:
$processor = new class implements SpanProcessorInterface {
public function onStart(Span $span, ?Span $parent) {}
public function onEnd(Span $span) {
if ($span->getName() === 'internal.healthcheck') {
$span->setAttribute('internal', true);
}
}
};
Resource Attributes:
Add custom resource attributes (e.g., service version) via ResourceInfo:
$resource = ResourceInfo::create([
'service.version' => '1.0.0',
'deployment.environment' => 'production',
]);
Hook Customization:
Extend auto-instrumentation hooks by implementing HookInterface:
class CustomHook implements HookInterface {
public function handle(InstrumentationContext $context) {
// Custom logic (e.g., modify spans before they're recorded)
How can I help you explore Laravel packages today?