Skip to main content

Laravel and Horizon log parsing

Log Lens reads Laravel and Horizon log files line by line and turns them into structured events, so a single error, its stack trace, and any trailing context all become one entry you can search, group, and resolve.

The header format

Every Laravel event starts with a header line. Log Lens matches this exact shape:

[2026-07-25 14:03:11] production.ERROR: Something went wrong

That line is split into four parts:

PartExampleBecomes
Timestamp2026-07-25 14:03:11when the event occurred
Environmentproductionthe environment field
LevelERRORthe severity
MessageSomething went wrongthe start of the body

The level is normalized to a standard set: WARN becomes WARNING, ERR and FATAL become ERROR, TRACE becomes DEBUG, and a missing level defaults to INFO.

Multiline bodies and stack traces

A new header line begins a new event. Any line that does not match the header format is treated as a continuation and appended to the current event's body. This is how full exception stack traces, {"exception":...} context, and wrapped messages stay attached to the event that produced them, instead of scattering into dozens of fragments.

Each event records the exact byte range it spans in the file, so Log Lens can later show you the untouched original text. See byte-range storage and read a raw event.

To keep a single runaway trace from consuming memory, the captured body is capped. Once a body reaches the limit (ingestion.capture_limit, default 4,194,304 bytes / 4 MiB) it stops growing, though the event's byte range still covers the full extent on disk.

Detection

Log Lens decides which parser handles a file by name and content:

  • Horizon files are matched by filename and framing - any file whose name contains horizon and whose sample matches either the Laravel header format above or one of the two shapes horizon/queue:work print to the console. A horizon-named file in neither shape falls through to the console parser rather than parsing to nothing.
  • Laravel files are files whose name does not contain horizon and whose first line matches the header format above.

Horizon console output

A worker log captured from the console has no Laravel framing and no level:

[2026-08-20 03:00:02][7f3a1c2e] Failed: App\Jobs\SyncCustomer
2026-08-20 03:00:02 App\Jobs\SyncCustomer .................... 1s FAIL

Because the format carries no level, the verb is the level: Failed/FAIL, or an exception class where the verb would be, is an ERROR; every other line is INFO progress. Unheaded lines still append to the event above them, so a failed job keeps the trace that explains it. Events are stored with the horizon log type and the horizon environment.

The channel is taken from the file name, so laravel.log and laravel-2026-07-25.log are distinguished automatically. This ties into log rotation and generations and which files count as logs.