Skip to content

fix(logs): respect log level explicitly declared by structured loggers#4624

Open
fcsouza wants to merge 1 commit into
Dokploy:canaryfrom
fcsouza:fix/structured-log-level
Open

fix(logs): respect log level explicitly declared by structured loggers#4624
fcsouza wants to merge 1 commit into
Dokploy:canaryfrom
fcsouza:fix/structured-log-level

Conversation

@fcsouza

@fcsouza fcsouza commented Jun 12, 2026

Copy link
Copy Markdown

What

The Docker log viewer classifies log lines purely by keyword matching and ignores the log level the application actually declared. Structured log lines (pino, bunyan, winston, zap, slog, logfmt) end up with wrong badges:

  • {"level":"error",...} never matches the error patterns (they expect whitespace-delimited words like error: ), so a pino error line falls through to the debug branch via \b(?:version|...|get|post)\b — pino lines always carry "version" / "method":"GET".
  • {"level":"warn","msg":"Webhook status event..."} is classified as info because \bstatus\b matches first.
  • {"level":"info","msg":"Request completed"} is classified as success because of \bcompleted\b.

Fix

Check for an explicitly declared level before any inference, and only fall back to the existing keyword heuristics when none is present:

  • JSON string levels: "level":"error", "severity":"ERROR" (GCP), "log.level" (ECS)
  • JSON numeric levels: "level":50 (pino/bunyan 10–60 scale, syslog/GELF 0–7 scale)
  • logfmt: level=error

A declared level also wins over the inferred statusCode classification. Unknown level names fall back to the keyword detection, which is unchanged.

Kept intentionally minimal (no scoring system) per the maintainer feedback on #3070.

Issues related

Closes #4589. Related: #4538, #1996.

Before / After

Same container (pino JSON + logfmt lines), tested on a local dev instance (pnpm dokploy:dev):

Before"level":"error" shows as debug, "level":"warn" as info, "level":"info" as success:

before: pino error line classified as debug

After — badges match the declared level; numeric pino levels and logfmt are also respected:

after: badges match the declared level

Tests

Added __test__/utils/log-type.test.ts — 12 tests covering pino/winston/zap string levels, pino/bunyan numeric levels, syslog/GELF numeric levels, GCP severity, ECS log.level, logfmt, precedence over statusCode and keywords, fallback for unknown level names, and the regression cases from #4589/#4538. Full vitest suite, tsc --noEmit and Biome pass.

Checklist

@fcsouza fcsouza requested a review from Siumauricio as a code owner June 12, 2026 14:16
@dosubot dosubot Bot added the size:M This PR changes 30-99 lines, ignoring generated files. label Jun 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M This PR changes 30-99 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Log viewer incorrectly marks lines as 'error' based on text keywords instead of actual log level

1 participant