2022-07-19 09:36:59 +05:00
|
|
|
import { consoleReporter } from "./reporters/console";
|
|
|
|
|
import { ILogReporter, LoggerConfig, LogLevel } from "./types";
|
|
|
|
|
|
2022-07-19 16:39:49 +05:00
|
|
|
type LogLevelFunc = (message: string, extras?: Record<string, any>) => void;
|
|
|
|
|
type ErrorLogLevelFunc = (
|
|
|
|
|
error: Error,
|
|
|
|
|
fallbackMessage?: string,
|
|
|
|
|
extras?: Record<string, any>
|
|
|
|
|
) => void;
|
|
|
|
|
export interface ILogger {
|
|
|
|
|
fatal: ErrorLogLevelFunc;
|
|
|
|
|
warn: LogLevelFunc;
|
|
|
|
|
debug: LogLevelFunc;
|
|
|
|
|
error: ErrorLogLevelFunc;
|
|
|
|
|
info: LogLevelFunc;
|
|
|
|
|
log: LogLevelFunc;
|
|
|
|
|
measure: (tag: string) => void;
|
2022-07-19 17:08:54 +05:00
|
|
|
scope: (scope: string) => ILogger;
|
2022-07-19 16:39:49 +05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export class Logger implements ILogger {
|
2022-07-19 09:36:59 +05:00
|
|
|
constructor(
|
|
|
|
|
private readonly config: LoggerConfig = {
|
|
|
|
|
reporter: consoleReporter,
|
|
|
|
|
lastTime: Date.now(),
|
|
|
|
|
}
|
|
|
|
|
) {}
|
|
|
|
|
|
|
|
|
|
scope(scope: string) {
|
|
|
|
|
return new Logger({ ...this.config, scope });
|
|
|
|
|
}
|
|
|
|
|
fatal = errorLogLevelFactory(LogLevel.Fatal, this.config);
|
|
|
|
|
warn = logLevelFactory(LogLevel.Warn, this.config);
|
|
|
|
|
debug = logLevelFactory(LogLevel.Debug, this.config);
|
|
|
|
|
error = errorLogLevelFactory(LogLevel.Error, this.config);
|
|
|
|
|
info = logLevelFactory(LogLevel.Info, this.config);
|
|
|
|
|
log = logLevelFactory(LogLevel.Log, this.config);
|
|
|
|
|
|
|
|
|
|
measure(tag: string) {
|
|
|
|
|
performance.mark(tag);
|
|
|
|
|
|
|
|
|
|
const marks = performance.getEntriesByName(tag, "mark");
|
|
|
|
|
if (marks.length === 2) {
|
|
|
|
|
const duration = marks[1].startTime - marks[0].startTime;
|
|
|
|
|
this.info(`${tag} took ${duration.toFixed(2)}ms`);
|
|
|
|
|
|
|
|
|
|
performance.clearMarks(tag);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-07-19 16:39:49 +05:00
|
|
|
|
|
|
|
|
export class NoopLogger implements ILogger {
|
|
|
|
|
fatal() {}
|
|
|
|
|
warn() {}
|
|
|
|
|
debug() {}
|
|
|
|
|
error() {}
|
|
|
|
|
info() {}
|
|
|
|
|
log() {}
|
|
|
|
|
measure(_tag: string) {}
|
2022-07-19 17:08:54 +05:00
|
|
|
scope(_scope: string) {
|
|
|
|
|
return this;
|
|
|
|
|
}
|
2022-07-19 16:39:49 +05:00
|
|
|
}
|
|
|
|
|
|
2022-07-19 09:36:59 +05:00
|
|
|
export * from "./types";
|
|
|
|
|
export * from "./reporters";
|
|
|
|
|
|
|
|
|
|
function logLevelFactory(level: LogLevel, config: LoggerConfig) {
|
|
|
|
|
return (message: string, extras?: Record<string, any>) => {
|
|
|
|
|
const now = Date.now();
|
|
|
|
|
config.reporter.write({
|
|
|
|
|
level,
|
|
|
|
|
message,
|
|
|
|
|
timestamp: now,
|
|
|
|
|
extras,
|
|
|
|
|
scope: config.scope,
|
|
|
|
|
elapsed: now - config.lastTime,
|
|
|
|
|
});
|
|
|
|
|
config.lastTime = now;
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function errorLogLevelFactory(level: LogLevel, config: LoggerConfig) {
|
2022-07-19 16:39:49 +05:00
|
|
|
return (
|
|
|
|
|
error: Error,
|
|
|
|
|
fallbackMessage?: string,
|
|
|
|
|
extras?: Record<string, any>
|
|
|
|
|
) => {
|
2022-07-19 09:36:59 +05:00
|
|
|
const now = Date.now();
|
|
|
|
|
config.reporter.write({
|
|
|
|
|
level,
|
2022-07-19 16:39:49 +05:00
|
|
|
message: error.stack
|
|
|
|
|
? error.stack.trim()
|
|
|
|
|
: fallbackMessage
|
|
|
|
|
? fallbackMessage
|
|
|
|
|
: "An error occurred.",
|
2022-07-19 09:36:59 +05:00
|
|
|
timestamp: now,
|
|
|
|
|
extras,
|
|
|
|
|
scope: config.scope,
|
|
|
|
|
elapsed: now - config.lastTime,
|
|
|
|
|
});
|
|
|
|
|
config.lastTime = now;
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function combineReporters(reporters: ILogReporter[]): ILogReporter {
|
|
|
|
|
return {
|
|
|
|
|
write(log) {
|
|
|
|
|
for (const reporter of reporters) {
|
|
|
|
|
reporter.write(log);
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
}
|