From 60112d84a5792716b183b3aba2d2840cbdb54134 Mon Sep 17 00:00:00 2001 From: Mauricio Siu Date: Mon, 3 Aug 2026 04:24:02 -0600 Subject: [PATCH] fix(logs): require complete no-error values in colon pairs --- apps/dokploy/__test__/logs/log-classification.test.ts | 11 +++++++++++ .../dokploy/components/dashboard/docker/logs/utils.ts | 10 +++++++--- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/apps/dokploy/__test__/logs/log-classification.test.ts b/apps/dokploy/__test__/logs/log-classification.test.ts index 6f04f491a..d97d76a29 100644 --- a/apps/dokploy/__test__/logs/log-classification.test.ts +++ b/apps/dokploy/__test__/logs/log-classification.test.ts @@ -23,6 +23,17 @@ test("does not classify explicit non-error key/values as error (#4538)", () => { expect(getLogType("request done, error: null").type).not.toBe("error"); expect(getLogType("checks passed, failures=0").type).not.toBe("error"); expect(getLogType('shutdown clean, error=""').type).not.toBe("error"); + expect(getLogType('job done failed=false error=""').type).not.toBe("error"); +}); + +test("keeps errors whose value merely starts with a no-error word", () => { + expect(getLogType("connect failed: no route to host").type).toBe("error"); + expect(getLogType("connection failed: no such host").type).toBe("error"); + expect(getLogType("error: none of the configured nodes are available").type).toBe( + "error", + ); + expect(getLogType("error: nil pointer dereference").type).toBe("error"); + expect(getLogType("request failed: 0 bytes received").type).toBe("error"); }); test("keeps statusCode-based classification", () => { diff --git a/apps/dokploy/components/dashboard/docker/logs/utils.ts b/apps/dokploy/components/dashboard/docker/logs/utils.ts index 1624a3828..2973b78b7 100644 --- a/apps/dokploy/components/dashboard/docker/logs/utils.ts +++ b/apps/dokploy/components/dashboard/docker/logs/utils.ts @@ -99,9 +99,13 @@ export const getLogType = (message: string): LogStyle => { // Key/value pairs that explicitly report a non-error (e.g. "error: none", // "failed: false") must not trigger the error keyword patterns below - const nonErrorKeyValues = - /\b(?:error|err|errors|failed|failure|failures)s?\s*[:=]\s*(?:none|null|nil|false|0|no|-|""|'')(?=[\s,;.)\]]|$)/gi; - const errorScope = lowerMessage.replace(nonErrorKeyValues, ""); + const nonErrorColonPairs = + /\b(?:error|err|errors|failed|failure|failures)\s*:\s*(?:none|null|nil|false|0|no|-|""|'')(?=[,;.)\]]|$)/gi; + const nonErrorLogfmtPairs = + /\b(?:error|err|errors|failed|failure|failures)\s*=\s*(?:none|null|nil|false|0|no|-|""|'')(?=[\s,;.)\]]|$)/gi; + const errorScope = lowerMessage + .replace(nonErrorColonPairs, "") + .replace(nonErrorLogfmtPairs, ""); if ( /(?:^|\s)(?:error|err):?\s/i.test(errorScope) ||