mirror of
https://github.com/Dokploy/dokploy.git
synced 2026-07-16 11:25:24 +02:00
fix(logs): don't classify explicit non-error key/values as error
Lines like 'failed: false, error: none' (e.g. ofelia job summaries for successful runs) were rendered red because the error patterns matched the key regardless of its value. Strip key/value pairs whose value explicitly reports a non-error before running the error keyword patterns. Fixes #4538
This commit is contained in:
33
apps/dokploy/__test__/logs/log-classification.test.ts
Normal file
33
apps/dokploy/__test__/logs/log-classification.test.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
import { getLogType } from "@/components/dashboard/docker/logs/utils";
|
||||
import { expect, test } from "vitest";
|
||||
|
||||
test("classifies real failures as error", () => {
|
||||
expect(getLogType("Error: connection refused at db:5432").type).toBe(
|
||||
"error",
|
||||
);
|
||||
expect(getLogType("[ERROR] something went wrong").type).toBe("error");
|
||||
expect(getLogType("Deployment failed").type).toBe("error");
|
||||
expect(
|
||||
getLogType(
|
||||
'NOTICE [Job "sync-1m" (e1305c5b54b1)] Finished in "326ms", failed: true, skipped: false, error: exit code 1',
|
||||
).type,
|
||||
).toBe("error");
|
||||
});
|
||||
|
||||
test("does not classify explicit non-error key/values as error (#4538)", () => {
|
||||
// ofelia job-completion summary for a successful run
|
||||
expect(
|
||||
getLogType(
|
||||
'NOTICE [Job "sync-1m" (e1305c5b54b1)] Finished in "326.16795ms", failed: false, skipped: false, error: none',
|
||||
).type,
|
||||
).not.toBe("error");
|
||||
|
||||
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");
|
||||
});
|
||||
|
||||
test("keeps statusCode-based classification", () => {
|
||||
expect(getLogType('{"statusCode": "500"}').type).toBe("error");
|
||||
expect(getLogType('{"statusCode": "204"}').type).toBe("success");
|
||||
});
|
||||
@@ -97,17 +97,23 @@ export const getLogType = (message: string): LogStyle => {
|
||||
return LOG_STYLES.info;
|
||||
}
|
||||
|
||||
// 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, "");
|
||||
|
||||
if (
|
||||
/(?:^|\s)(?:error|err):?\s/i.test(lowerMessage) ||
|
||||
/\b(?:exception|failed|failure)\b/i.test(lowerMessage) ||
|
||||
/(?:stack\s?trace):\s*$/i.test(lowerMessage) ||
|
||||
/^\s*at\s+[\w.]+\s*\(?.+:\d+:\d+\)?/.test(lowerMessage) ||
|
||||
/\b(?:uncaught|unhandled)\s+(?:exception|error)\b/i.test(lowerMessage) ||
|
||||
/Error:\s.*(?:in|at)\s+.*:\d+(?::\d+)?/.test(lowerMessage) ||
|
||||
/\b(?:errno|code):\s*(?:\d+|[A-Z_]+)\b/i.test(lowerMessage) ||
|
||||
/\[(?:error|err|fatal)\]/i.test(lowerMessage) ||
|
||||
/\b(?:crash|critical|fatal)\b/i.test(lowerMessage) ||
|
||||
/\b(?:fail(?:ed|ure)?|broken|dead)\b/i.test(lowerMessage)
|
||||
/(?:^|\s)(?:error|err):?\s/i.test(errorScope) ||
|
||||
/\b(?:exception|failed|failure)\b/i.test(errorScope) ||
|
||||
/(?:stack\s?trace):\s*$/i.test(errorScope) ||
|
||||
/^\s*at\s+[\w.]+\s*\(?.+:\d+:\d+\)?/.test(errorScope) ||
|
||||
/\b(?:uncaught|unhandled)\s+(?:exception|error)\b/i.test(errorScope) ||
|
||||
/Error:\s.*(?:in|at)\s+.*:\d+(?::\d+)?/.test(errorScope) ||
|
||||
/\b(?:errno|code):\s*(?:\d+|[A-Z_]+)\b/i.test(errorScope) ||
|
||||
/\[(?:error|err|fatal)\]/i.test(errorScope) ||
|
||||
/\b(?:crash|critical|fatal)\b/i.test(errorScope) ||
|
||||
/\b(?:fail(?:ed|ure)?|broken|dead)\b/i.test(errorScope)
|
||||
) {
|
||||
return LOG_STYLES.error;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user