Laravel OpenTelemetry Integration

repository·main·Indexed 41 days ago

https://github.com/keepsuit/laravel-opentelemetry

A package providing OpenTelemetry integration for Laravel applications to generate and export traces, metrics, and logs. It includes automatic instrumentation for HTTP requests, database queries, Redis, queues, cache, events, views, Livewire, and Scout, as well as support for head and tail sampling strategies.

Tokens
13K
Snippets
36
Records
56
Agent score
52%

What's inside Laravel OpenTelemetry

  1. Overview of OpenTelemetry integration for Laravel

    main
    This package provides a way to integrate OpenTelemetry into Laravel applications, allowing you to instrument your application to generate, collect, and export telemetry data such as metrics, logs, and traces to analyze performance and behavior.
  2. Configure Tail Sampling for intelligent trace filtering

    main

    Tail sampling allows you to make sampling decisions based on complete trace data (e.g., keeping traces that contain errors or are slow) rather than just the initial span.

    Note: Application-level tail sampling is best suited for single-service scenarios. For multi-service environments, use an OpenTelemetry Collector.

    Built-in Rules

    • ErrorsRule: Keeps traces containing error/exception spans.
    • SlowTraceRule: Keeps traces exceeding a specific threshold_ms.

    Configuration

    • enabled: Boolean to enable/disable tail sampling.
    • decision_wait: Maximum time (ms) to wait for the end of a trace before making a decision.
    • rules: An array of rules to apply.
    'tail_sampling' => [
        'enabled' => false,
        'decision_wait' => 5000,  
        'rules' => [
            TailSampling\Rules\ErrorsRule::class => true,
            TailSampling\Rules\SlowTraceRule::class => [
                'enabled' => true,
                'threshold_ms' => 2000,
            ],
        ],
    ],
  3. Configure Trace Sampling (Head vs Tail)

    main

    The package supports two sampling strategies to control which traces are exported:

    Head Sampling

    Decisions are made at the start of a span. It is fast and ideal for rate limiting or percentage-based sampling. Configure this in the traces.sampler section of your config.

    Tail Sampling

    Decisions are made after the trace completes, allowing you to keep traces based on full data (e.g., errors or slow duration).

    Note: Tail sampling implemented at the application level is best for single-service scenarios. For multi-service environments, use an OpenTelemetry Collector.

    Built-in Tail Sampling Rules

    • Errors Rule: Keeps traces containing any span with an error status.
    • Slow Trace Rule: Keeps traces exceeding a duration threshold (default 2000ms).

    Tail Sampling Configuration Variables

    VariableDescriptionDefault
    OTEL_TRACES_TAIL_SAMPLING_ENABLEDEnable tail samplingfalse
    OTEL_TRACES_TAIL_SAMPLING_DECISION_WAITMax time to wait for trace completion (ms)5000
    OTEL_TRACES_TAIL_SAMPLING_RULE_KEEP_ERRORSEnable Errors Ruletrue
    OTEL_TRACES_TAIL_SAMPLING_RULE_SLOW_TRACESEnable Slow Trace Ruletrue
    OTEL_TRACES_TAIL_SAMPLING_SLOW_TRACES_THRESHOLD_MSThreshold for Slow Trace Rule (ms)2000
  4. Send logs to OpenTelemetry

    main

    You can send logs to OpenTelemetry using two methods:

    1. Laravel Log Channels: Use the injected otlp channel in your config/logging.php. This uses the OpenTelemetryMonologHandler.
    2. Logger Facade: Use the Logger facade to send logs directly to OpenTelemetry.

    If you use the otlp logs driver, trace IDs are automatically injected into the log context.

    // Using the Logger facade
    use Keepsuit\LaravelOpenTelemetry\Facades\Logger;
    
    Logger::error('my log message');
    Logger::info('my log message');
  5. Use the Makefile for development setup

    main

    The project includes a Makefile to simplify development using Docker. The containers are configured to mirror your host user's UID and GID to prevent file permission issues.

    Workflow Note: Before using make shell, ensure the containers are already running by executing make start in a separate terminal.

    # Build the Docker image with your UID/GID
    make build
    
    # Start containers in the background
    make start
    
    # Stop and remove containers
    make stop
    
    # Open a Bash shell in the 'app' container
    make shell
  6. Trace Console Commands

    main

    Console commands are not traced by default. To trace them, add their signature or class name to the commands array within the ConsoleInstrumentation configuration.

    Disabling: Set OTEL_INSTRUMENTATION_CONSOLE=false or remove ConsoleInstrumentation::class.

    // By signature
    'instrumentation' => [
        Instrumentation\ConsoleInstrumentation::class => [
            'enabled' => env('OTEL_INSTRUMENTATION_CONSOLE', true),
            'commands' => [
                'app:example-command',
             ],
        ],
    ],
    
    // By class name
    'instrumentation' => [
        Instrumentation\ConsoleInstrumentation::class => [
            'enabled' => env('OTEL_INSTRUMENTATION_CONSOLE', true),
            'commands' => [
                App\Console\Commands\ExampleCommand::class,
             ],
        ],
    ],
  7. Publish the OpenTelemetry configuration file

    main

    After installing the package, publish the configuration file to your application's config directory using the following Artisan command:

    php artisan vendor:publish --provider="Keepsuit\LaravelOpenTelemetry\LaravelOpenTelemetryServiceProvider" --tag="opentelemetry-config"
  8. Upgrade to v2.0: Breaking Changes

    main

    Upgrading to v2.0 involves several breaking changes in configuration, namespaces, and the Meter API. If you have a published configuration file, you must compare it with the new version and update it manually.

    Configuration Changes

    • Event Instrumentation: Rename ignored to excluded.
    • Console Instrumentation: Behavior is reversed. Instead of excluded, use commands to specify which commands to include. By default, commands are not traced.
    • Logs Configuration: The trace_id_field default value changed from traceid to trace_id.
    • HTTP Instrumentation: A new sensitive_query_parameters option is available for both server and client instrumentations to redact sensitive data.

    Namespace Changes

    If you import these classes directly, update your imports:

    • Keepsuit\LaravelOpenTelemetry\Support\InstrumentationUtilities $\rightarrow$ Keepsuit\LaravelOpenTelemetry\Instrumentation\Support\InstrumentationUtilities
    • Keepsuit\LaravelOpenTelemetry\Support\View\TracedViewEngine $\rightarrow$ Keepsuit\LaravelOpenTelemetry\Instrumentation\Support\View\TracedViewEngine
    • Keepsuit\LaravelOpenTelemetry\Support\HttpClient\GuzzleTraceMiddleware $\rightarrow$ Keepsuit\LaravelOpenTelemetry\Instrumentation\Support\Http\Client\GuzzleTraceMiddleware
    • Keepsuit\LaravelOpenTelemetry\Support\HttpServer\TraceRequestMiddleware $\rightarrow$ Keepsuit\LaravelOpenTelemetry\Instrumentation\Support\Http\Server\TraceRequestMiddleware

    Exporter Behavior

    • In v2.0, setting the exporter to null uses a no-op exporter that discards all data.
    • To use the in-memory exporter, set the exporter to memory.
  9. Enable Scout Instrumentation

    main

    v2.0 provides first-class support for tracing Laravel Scout search, update, and delete operations.

    Requirements:

    • Laravel Scout 10.23+
    • OpenTelemetry PHP extension installed

    Configuration: Enable it in your configuration array using the ScoutInstrumentation class.

    Instrumentation\ScoutInstrumentation::class => env('OTEL_INSTRUMENTATION_SCOUT', true),
  10. Configure Http Client instrumentation

    main

    Http client requests are traced by default. You can switch to manual mode by setting 'manual' => true in the configuration. In manual mode, you must explicitly call withTrace() on the request builder.

    Route Name Resolution: Because low-cardinality URL templates cannot be automatically detected for client requests, you can manually resolve them using HttpClientInstrumentation::setRouteNameResolver() in your service provider.

    Metrics:

    • http.client.request.duration (histogram, seconds): Outgoing HTTP request duration.

    Disabling: Set OTEL_INSTRUMENTATION_HTTP_CLIENT=false or remove HttpClientInstrumentation::class from the config.

    // Manual mode usage
    Http::withTrace()->get('https://example.com');
    
    // Custom route name resolver
    use Keepsuit\LaravelOpenTelemetry\Instrumentation\HttpClientInstrumentation;
    use Psr\Http\Message\RequestInterface;
    
    public function boot(): void
    {
        HttpClientInstrumentation::setRouteNameResolver(function (RequestInterface $request): ?string {
            return match (true) {
                str_starts_with($request->getUri()->getPath(), '/products/') => '/products/{id}',
                default => null,
            };
        });
    }