Skip to content

Logs

Logs

The telemetry log channel turns ordinary Laravel logging into OTLP log records — with Monolog severity mapped onto the OTLP range and, crucially, correlated to the active trace, so a log line appears on the exact span that produced it.

Setup

Add the channel to your stack in config/logging.php:

'channels' => [
    'stack' => [
        'driver' => 'stack',
        'channels' => ['single', 'telemetry'],
    ],

    'telemetry' => [
        'driver' => 'telemetry',
        'level' => env('TELEMETRY_LOG_LEVEL', 'info'),
    ],
],

Nothing else changes — Log::info(), report(), logger() all flow through the stack as usual:

Telemetry::span('import.customers', function () {
    Log::info('Import started', ['file' => $path]);
    // → OTLP log record with this span's traceId + spanId
});

What gets exported

Log record part OTLP field
message body
Monolog level severityNumber (DEBUG 5, INFO 9, NOTICE 10, WARNING 13, ERROR 17, CRITICAL 21, ALERT 22, EMERGENCY 23) + severityText
channel log.channel attribute
scalar context log.context.* attributes
exception context exception.type + exception.message attributes
other non-scalars JSON-encoded log.context.*
active trace traceId + spanId

Records buffer with spans/events and export at terminate to every exporter supporting the events signal (/v1/logs on OTLP).

Feedback-loop protection

Log records emitted while a flush is exporting are dropped — a failing exporter that reports through the logging stack can never feed itself.

Agent prompt

Wire cboxdk/laravel-telemetry's log channel into this Laravel app:

1. In config/logging.php add:
   'telemetry' => ['driver' => 'telemetry', 'level' => env('TELEMETRY_LOG_LEVEL', 'info')]
   and append 'telemetry' to the channels array of the 'stack' channel.
   If LOG_CHANNEL is not 'stack', ask me before changing it.
2. Leave all existing channels untouched — telemetry is additive.
3. Verify with a Pest test: Telemetry::fake(), then
   Log::channel('telemetry')->warning('test', ['k' => 'v']) and assert via
   $fake->recordedEvents() that severityNumber is 13 and the context
   attribute log.context.k equals 'v'.
4. Note in your summary: records correlate to the active trace
   automatically; nothing else to configure.

Logs vs. events

  • telemetry channel — your existing operational logging, exported. Free-text messages, severities, exceptions.
  • Telemetry::event() — deliberate structured records (decisions, state transitions) with a stable name you'll query by.

Both end up as OTLP log records; use the channel for what you already log and events for what you want to query.