mirror of
https://github.com/portainer/portainer.git
synced 2025-07-25 08:19:40 +02:00
fix(logging): default to pretty logging [EE-4371] (#7847)
* fix(logging): default to pretty logging EE-4371 * feat(app/logs): prettify stack traces in JSON logs * feat(nomad/logs): prettify JSON logs in log viewer * feat(kubernetes/logs): prettigy JSON logs in log viewers * feat(app/logs): format and color zerolog prettified logs * fix(app/logs): pre-parse logs when they are double serialized Co-authored-by: andres-portainer <andres-portainer@users.noreply.github.com> Co-authored-by: LP B <xAt0mZ@users.noreply.github.com>
This commit is contained in:
parent
ee5600b6af
commit
535a26412f
27 changed files with 935 additions and 279 deletions
119
app/docker/helpers/logHelper/formatZerologLogs.ts
Normal file
119
app/docker/helpers/logHelper/formatZerologLogs.ts
Normal file
|
@ -0,0 +1,119 @@
|
|||
import {
|
||||
formatCaller,
|
||||
formatKeyValuePair,
|
||||
formatLevel,
|
||||
formatMessage,
|
||||
formatStackTrace,
|
||||
formatTime,
|
||||
} from './formatters';
|
||||
import {
|
||||
FormattedLine,
|
||||
JSONStackTrace,
|
||||
Level,
|
||||
Span,
|
||||
TIMESTAMP_LENGTH,
|
||||
} from './types';
|
||||
|
||||
const dateRegex = /(\d{4}\/\d{2}\/\d{2} \d{2}:\d{2}[AP]M) /; // "2022/02/01 04:30AM "
|
||||
const levelRegex = /(\w{3}) /; // "INF " or "ERR "
|
||||
const callerRegex = /(.+?.go:\d+) /; // "path/to/file.go:line "
|
||||
const chevRegex = /> /; // "> "
|
||||
const messageAndPairsRegex = /(.*)/; // include the rest of the string in a separate group
|
||||
|
||||
const keyRegex = /(\S+=)/g; // ""
|
||||
|
||||
export const ZerologRegex = concatRegex(
|
||||
dateRegex,
|
||||
levelRegex,
|
||||
callerRegex,
|
||||
chevRegex,
|
||||
messageAndPairsRegex
|
||||
);
|
||||
|
||||
function concatRegex(...regs: RegExp[]) {
|
||||
const flags = Array.from(
|
||||
new Set(
|
||||
regs
|
||||
.map((r) => r.flags)
|
||||
.join('')
|
||||
.split('')
|
||||
)
|
||||
).join('');
|
||||
const source = regs.map((r) => r.source).join('');
|
||||
return new RegExp(source, flags);
|
||||
}
|
||||
|
||||
type Pair = {
|
||||
key: string;
|
||||
value: string;
|
||||
};
|
||||
|
||||
export function formatZerologLogs(rawText: string, withTimestamps?: boolean) {
|
||||
const spans: Span[] = [];
|
||||
const lines: FormattedLine[] = [];
|
||||
let line = '';
|
||||
|
||||
const text = withTimestamps ? rawText.substring(TIMESTAMP_LENGTH) : rawText;
|
||||
|
||||
const [, date, level, caller, messageAndPairs] =
|
||||
text.match(ZerologRegex) || [];
|
||||
|
||||
const [message, pairs] = extractPairs(messageAndPairs);
|
||||
|
||||
line += formatTime(date, spans, line);
|
||||
line += formatLevel(level as Level, spans, line);
|
||||
line += formatCaller(caller, spans, line);
|
||||
line += formatMessage(message, spans, line, !!pairs.length);
|
||||
|
||||
let stackTrace: JSONStackTrace | undefined;
|
||||
const stackTraceIndex = pairs.findIndex((p) => p.key === 'stack_trace');
|
||||
|
||||
if (stackTraceIndex !== -1) {
|
||||
stackTrace = JSON.parse(pairs[stackTraceIndex].value);
|
||||
pairs.splice(stackTraceIndex);
|
||||
}
|
||||
|
||||
pairs.forEach(({ key, value }, idx) => {
|
||||
line += formatKeyValuePair(
|
||||
key,
|
||||
value,
|
||||
spans,
|
||||
line,
|
||||
idx === pairs.length - 1
|
||||
);
|
||||
});
|
||||
lines.push({ line, spans });
|
||||
|
||||
formatStackTrace(stackTrace, lines);
|
||||
|
||||
return lines;
|
||||
}
|
||||
|
||||
function extractPairs(messageAndPairs: string): [string, Pair[]] {
|
||||
const pairs: Pair[] = [];
|
||||
let [message, rawPairs] = messageAndPairs.split('|');
|
||||
|
||||
if (!messageAndPairs.includes('|') && !rawPairs) {
|
||||
rawPairs = message;
|
||||
message = '';
|
||||
}
|
||||
message = message.trim();
|
||||
rawPairs = rawPairs.trim();
|
||||
|
||||
const matches = [...rawPairs.matchAll(keyRegex)];
|
||||
|
||||
matches.forEach((m, idx) => {
|
||||
const rawKey = m[0];
|
||||
const key = rawKey.slice(0, -1);
|
||||
const start = m.index || 0;
|
||||
const end = idx !== matches.length - 1 ? matches[idx + 1].index : undefined;
|
||||
const value = (
|
||||
end
|
||||
? rawPairs.slice(start + rawKey.length, end)
|
||||
: rawPairs.slice(start + rawKey.length)
|
||||
).trim();
|
||||
pairs.push({ key, value });
|
||||
});
|
||||
|
||||
return [message, pairs];
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue