lsr / otel
OpenTelemetry integration for the Laser framework.
Requires
- php: >=8.4
- guzzlehttp/guzzle: ^7.9
- nette/di: ^3.2
- open-telemetry/api: ^1.10
- open-telemetry/exporter-otlp: ^1.4
- open-telemetry/sdk: ^1.15
Requires (Dev)
- friendsofphp/php-cs-fixer: ^3.95
- lsr/auth: ^0.3.10
- lsr/caching: ^0.3.5
- lsr/core: ^0.4.5 || ^0.5
- lsr/cqrs: ^0.1.4
- lsr/db: ^0.3.15
- lsr/inertia: ^0.1.8
- lsr/logging: ^0.3.2
- lsr/orm: ^0.3.21
- lsr/request: ^0.3.10
- lsr/roadrunner: ^0.1.13
- lsr/routing: ^0.4.2 || ^0.5
- lsr/scheduler: ^0.1.2
- nyholm/psr7: ^1.8
- open-telemetry/opentelemetry-auto-psr3: ^0.3
- phpstan/extension-installer: ^1.2
- phpstan/phpstan: ^2.0
- phpunit/phpunit: ^12|^13
- roave/security-advisories: dev-latest
- symfony/console: ^8|^7
- symfony/event-dispatcher: ^8|^7
Suggests
- ext-opentelemetry: Enables hook-based automatic instrumentation.
- lsr/auth: Enables authentication outcome instrumentation.
- lsr/caching: Enables cache load instrumentation.
- lsr/core: Enables FPM and RoadRunner HTTP lifecycle instrumentation.
- lsr/cqrs: Enables synchronous command instrumentation.
- lsr/db: Enables database operation instrumentation.
- lsr/inertia: Enables Inertia render instrumentation.
- lsr/orm: Enables ORM model lifecycle instrumentation.
- lsr/request: Enables request mapping and validation instrumentation.
- lsr/roadrunner: Enables RoadRunner worker and task instrumentation.
- lsr/routing: Enables route resolution instrumentation through lsr/core.
- lsr/scheduler: Enables scheduled job and command instrumentation.
- open-telemetry/opentelemetry-auto-psr3: Injects trace context into PSR-3 logs or exports them as OpenTelemetry logs.
- open-telemetry/sdk-configuration: Loads declarative OpenTelemetry SDK configuration.
- open-telemetry/transport-grpc: Publishes OTLP over gRPC instead of the bundled HTTP transport.
- symfony/console: Enables command lifecycle instrumentation.
- symfony/event-dispatcher: Provides the dispatcher used by command lifecycle instrumentation.
Provides
None
Conflicts
None
Replaces
None
README
lsr/otel integrates OpenTelemetry providers, tracing and metric helpers with Nette DI and optional LSR lifecycle hooks. It can instrument supported framework services without making all framework packages mandatory dependencies.
Requirements
- PHP
>=8.4and Nette DI^3.2. - OpenTelemetry API
^1.10, SDK^1.15and OTLP exporter^1.4. - Guzzle
^7.9for the bundled HTTP transport stack. - No PHP extensions are mandatory in this package's manifest.
ext-opentelemetryis suggested for hook-based automatic instrumentation; the explicit LSR lifecycle bridges do not require it. - Install the optional LSR packages for the integrations you use. Console instrumentation additionally needs Symfony Console and Symfony EventDispatcher. PSR-3 auto-instrumentation, declarative SDK configuration and gRPC transport are separate suggested packages listed in composer.json.
- Configure exporters and reachable telemetry backends in the consuming environment; this library does not deploy a collector or storage backend.
Installation
composer require lsr/otel
Configuration
Register the extension in the application's Nette DI configuration:
extensions: otel: Lsr\Otel\DI\OtelExtension otel: enabled: true registerGlobal: true autoShutdown: true applicationInstrumentation: name: example/application version: '1.0.0'
applicationInstrumentation.name must be a Composer-style package name; replace example/application with the application's identity. Setting it registers autowired Lsr\Otel\Tracing and Lsr\Otel\Metrics helpers. Without it, use Lsr\Otel\InstrumentationRegistry to request explicitly named instrumentation scopes.
The extension creates trace, metric and log providers, a propagator and an SDK. ProviderFactory delegates resource and exporter configuration to the OpenTelemetry SDK factories, rather than defining separate endpoint or credential keys in NEON. Configure the installed SDK's environment settings before initializing the container. enabled: false selects no-op providers and skips framework bridges; registerGlobal: false prevents this extension from registering its SDK globally.
Manual instrumentation
Inject InstrumentationRegistry into an application service to use the same providers with a named scope:
use Lsr\Otel\InstrumentationRegistry; use OpenTelemetry\API\Trace\SpanInterface; function checksum(InstrumentationRegistry $registry, string $contents): string { $tracing = $registry->tracing('example/application'); $metrics = $registry->metrics('example/application'); $digest = $tracing->trace( 'document.checksum', static fn(SpanInterface $span): string => hash('sha256', $contents), ); $metrics->counter('application.documents.checksummed')->add(); return $digest; }
Tracing::trace() returns the callback result, records thrown exceptions and rethrows them, then ends the span. For manually scoped work, start() returns an ActiveSpan; call fail() on failure and always end() in a finally block.
Metrics::counter() and histogram() cache instruments by name. Reusing a name with a different instrument type, unit or description throws LogicException; keep definitions consistent within each instrumentation scope. The registry also exposes the underlying tracer, meter and logger APIs.
Framework bridges
The DI extension conditionally registers bridges for Core HTTP/request operations, RoadRunner HTTP and jobs, Console, CQRS, cache, routing, scheduler, authentication, request mapping, Inertia, database and ORM operations. Compatible lifecycle interfaces and the relevant service definitions must be present; installing an older optional package without its hook API is not enough.
Cache traces and metrics use the lsr/caching instrumentation scope. Update collector or dashboard filters that match the former lsr/cache scope; metric names remain lsr.cache.*.
Integration groups expose enabled, traces and metrics switches. For example:
otel: integrations: database: includeRawSql: false orm: hydration: false modelMetrics: false roadrunner: flushEvery: 100 flushInterval: 10.0
Raw SQL tracing, ORM hydration and model-specific metrics are disabled by default. Consider sensitive data and attribute cardinality before enabling additional detail or adding application attributes.
Automatic DI wiring attaches hooks to registered service definitions. Objects constructed directly or returned by another factory are not automatically covered by that wiring. In particular, the standard Inertia factory creates request-specific Inertia objects itself; applications using that path must attach an Inertia lifecycle hook to those instances if they want render instrumentation. See src/Bridge for each bridge's concrete scope.
Flush and shutdown
Lsr\Otel\Lifecycle\TelemetryLifecycleInterface exposes forceFlush(): bool and shutdown(): bool. The extension initializes lifecycle management when the compiled container is initialized; autoShutdown defaults to true.
The Core bridge adds an FPM flush handler, the RoadRunner bridge flushes periodically at worker iteration boundaries and once more when workers stop, and the Console bridge flushes on command termination. Provider shutdown is handled separately by the lifecycle shutdown registration. For other long-running execution models, call forceFlush() at appropriate boundaries and shutdown() when the process finishes. An iteration-based interval is not an independent background timer.
A RoadRunner-focused Grafana dashboard is included at grafana/lsr-roadrunner-dashboard.json; adapt its data sources to the deployed observability stack.
Development
CI runs the checks below on PHP 8.4 and 8.5. From a package checkout:
composer install --prefer-dist --no-interaction --no-progress composer cs vendor/bin/phpstan analyse --no-progress vendor/bin/phpunit --no-coverage
composer cs checks coding style without changing files. Run composer cs:fix (or composer cbf) to apply PHP CS Fixer rules from .php-cs-fixer.php.
The development dependencies include the optional LSR bridges, Nyholm PSR-7, Symfony Console/EventDispatcher and PSR-3 auto-instrumentation exercised by the suite; these remain optional for consumers. Tests use this checkout's Composer autoloader, not sibling workspace packages. No collector, Redis server, database server or RoadRunner binary is needed.
CI installs ext-opentelemetry for the PSR-3 integration tests, plus the framework dependency extensions (Redis, PDO SQLite, gettext, fileinfo, SimpleXML, ZIP and sockets) and PHPUnit's DOM, mbstring, XML and XMLWriter extensions. The composer test script enables Xdebug coverage; the CI command explicitly disables coverage collection.
AI coding assistance
See LSR Skills for AI agent skills for working with the LSR framework.
License
Licensed under the MIT License.