summaryrefslogtreecommitdiff
path: root/lib/trace/log/trace.ts
blob: 3f71e064d5bc9780e780fbd5cfbbdb01d0e2cb1d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
import { isDebug, ITrace, ITraceWith, memoize, Supplier } from '@emprespresso/pengueno';
import { ILogger, isLogLevel, LogLevel, logLevelOrder, PrettyJsonConsoleLogger } from '.';

export type LogTraceSupplier = ITraceWith<Supplier<string>> | ITraceWith<Error>;

export class LogTrace implements ITrace<LogTraceSupplier> {
    constructor(
        private readonly logger: ILogger = new PrettyJsonConsoleLogger(),
        private readonly traces: Array<LogTraceSupplier> = [defaultTrace],
        private readonly defaultLevel: LogLevel = LogLevel.INFO,
        private readonly allowedLevels: Supplier<Set<LogLevel>> = defaultAllowedLevelsSupplier,
    ) {}

    public traceScope(trace: LogTraceSupplier): ITrace<LogTraceSupplier> {
        return new LogTrace(this.logger, this.traces.concat(trace), this.defaultLevel, this.allowedLevels);
    }

    public trace(trace: LogTraceSupplier) {
        const { traces, level: _level } = this.foldTraces(this.traces.concat(trace));
        if (!this.allowedLevels().has(_level)) return;

        const level = _level === LogLevel.UNKNOWN ? this.defaultLevel : _level;
        this.logger.log(level, ...traces);
    }

    private foldTraces(_traces: Array<LogTraceSupplier>) {
        const _logTraces = _traces.map((trace) => (typeof trace === 'function' ? trace() : trace));
        const _level = _logTraces
            .filter((trace) => isLogLevel(trace))
            .reduce((acc, level) => Math.max(logLevelOrder.indexOf(level), acc), -1);
        const level = logLevelOrder[_level] ?? LogLevel.UNKNOWN;

        const traces = _logTraces
            .filter((trace) => !isLogLevel(trace))
            .map((trace) => {
                if (typeof trace === 'object') {
                    return `TracedException.Name = ${trace.name}, TracedException.Message = ${trace.message}, TracedException.Stack = ${trace.stack}`;
                }
                return trace;
            });
        return {
            level,
            traces,
        };
    }
}

const defaultTrace = () => `TimeStamp = ${new Date().toISOString()}`;
const defaultAllowedLevels = memoize(
    (isDebug: boolean) =>
        new Set([
            LogLevel.UNKNOWN,
            ...(isDebug ? [LogLevel.DEBUG] : []),
            LogLevel.INFO,
            LogLevel.WARN,
            LogLevel.ERROR,
            LogLevel.SYS,
        ]),
);
const defaultAllowedLevelsSupplier = () => defaultAllowedLevels(isDebug());