2020-01-02 15:13:47 -05:00
|
|
|
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
2020-08-24 19:43:54 -04:00
|
|
|
import { LogLevels, getLevelByName, getLevelName } from "./levels.ts";
|
2020-08-12 06:01:36 -04:00
|
|
|
import type { LevelName } from "./levels.ts";
|
2020-07-08 05:26:39 -04:00
|
|
|
import type { BaseHandler } from "./handlers.ts";
|
2019-01-02 09:12:48 -05:00
|
|
|
|
2020-08-24 19:43:54 -04:00
|
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
|
|
export type GenericFunction = (...args: any[]) => any;
|
|
|
|
|
2020-06-18 06:50:18 -04:00
|
|
|
export interface LogRecordOptions {
|
|
|
|
msg: string;
|
|
|
|
args: unknown[];
|
|
|
|
level: number;
|
|
|
|
loggerName: string;
|
|
|
|
}
|
|
|
|
|
2020-04-09 07:45:24 -04:00
|
|
|
export class LogRecord {
|
|
|
|
readonly msg: string;
|
|
|
|
#args: unknown[];
|
|
|
|
#datetime: Date;
|
|
|
|
readonly level: number;
|
|
|
|
readonly levelName: string;
|
2020-06-18 06:50:18 -04:00
|
|
|
readonly loggerName: string;
|
2020-04-09 07:45:24 -04:00
|
|
|
|
2020-06-18 06:50:18 -04:00
|
|
|
constructor(options: LogRecordOptions) {
|
|
|
|
this.msg = options.msg;
|
|
|
|
this.#args = [...options.args];
|
|
|
|
this.level = options.level;
|
|
|
|
this.loggerName = options.loggerName;
|
2020-04-09 07:45:24 -04:00
|
|
|
this.#datetime = new Date();
|
2020-06-18 06:50:18 -04:00
|
|
|
this.levelName = getLevelName(options.level);
|
2020-04-09 07:45:24 -04:00
|
|
|
}
|
|
|
|
get args(): unknown[] {
|
|
|
|
return [...this.#args];
|
|
|
|
}
|
|
|
|
get datetime(): Date {
|
|
|
|
return new Date(this.#datetime.getTime());
|
|
|
|
}
|
2019-01-06 14:19:15 -05:00
|
|
|
}
|
2018-12-19 13:16:45 -05:00
|
|
|
|
2020-06-18 06:50:18 -04:00
|
|
|
export interface LoggerOptions {
|
|
|
|
handlers?: BaseHandler[];
|
|
|
|
}
|
|
|
|
|
2018-12-19 13:16:45 -05:00
|
|
|
export class Logger {
|
2020-07-05 23:57:31 -04:00
|
|
|
#level: LogLevels;
|
|
|
|
#handlers: BaseHandler[];
|
|
|
|
readonly #loggerName: string;
|
2018-12-19 13:16:45 -05:00
|
|
|
|
2020-06-18 06:50:18 -04:00
|
|
|
constructor(
|
|
|
|
loggerName: string,
|
|
|
|
levelName: LevelName,
|
2020-07-14 15:24:17 -04:00
|
|
|
options: LoggerOptions = {},
|
2020-06-18 06:50:18 -04:00
|
|
|
) {
|
2020-07-05 23:57:31 -04:00
|
|
|
this.#loggerName = loggerName;
|
|
|
|
this.#level = getLevelByName(levelName);
|
|
|
|
this.#handlers = options.handlers || [];
|
|
|
|
}
|
|
|
|
|
|
|
|
get level(): LogLevels {
|
|
|
|
return this.#level;
|
|
|
|
}
|
|
|
|
set level(level: LogLevels) {
|
|
|
|
this.#level = level;
|
|
|
|
}
|
2019-01-06 14:19:15 -05:00
|
|
|
|
2020-07-05 23:57:31 -04:00
|
|
|
get levelName(): LevelName {
|
|
|
|
return getLevelName(this.#level);
|
|
|
|
}
|
|
|
|
set levelName(levelName: LevelName) {
|
|
|
|
this.#level = getLevelByName(levelName);
|
|
|
|
}
|
|
|
|
|
|
|
|
get loggerName(): string {
|
|
|
|
return this.#loggerName;
|
|
|
|
}
|
|
|
|
|
|
|
|
set handlers(hndls: BaseHandler[]) {
|
|
|
|
this.#handlers = hndls;
|
|
|
|
}
|
|
|
|
get handlers(): BaseHandler[] {
|
|
|
|
return this.#handlers;
|
2018-12-19 13:16:45 -05:00
|
|
|
}
|
|
|
|
|
2020-06-12 09:27:41 -04:00
|
|
|
/** If the level of the logger is greater than the level to log, then nothing
|
|
|
|
* is logged, otherwise a log record is passed to each log handler. `msg` data
|
|
|
|
* passed in is returned. If a function is passed in, it is only evaluated
|
|
|
|
* if the msg will be logged and the return value will be the result of the
|
|
|
|
* function, not the function itself, unless the function isn't called, in which
|
|
|
|
* case undefined is returned. All types are coerced to strings for logging.
|
|
|
|
*/
|
2020-07-05 23:57:31 -04:00
|
|
|
private _log<T>(
|
2020-06-12 09:27:41 -04:00
|
|
|
level: number,
|
2020-08-24 19:43:54 -04:00
|
|
|
msg: (T extends GenericFunction ? never : T) | (() => T),
|
2020-06-12 09:27:41 -04:00
|
|
|
...args: unknown[]
|
|
|
|
): T | undefined {
|
|
|
|
if (this.level > level) {
|
|
|
|
return msg instanceof Function ? undefined : msg;
|
|
|
|
}
|
2019-01-02 09:12:48 -05:00
|
|
|
|
2020-06-12 09:27:41 -04:00
|
|
|
let fnResult: T | undefined;
|
|
|
|
let logMessage: string;
|
|
|
|
if (msg instanceof Function) {
|
|
|
|
fnResult = msg();
|
|
|
|
logMessage = this.asString(fnResult);
|
|
|
|
} else {
|
|
|
|
logMessage = this.asString(msg);
|
|
|
|
}
|
2020-06-18 06:50:18 -04:00
|
|
|
const record: LogRecord = new LogRecord({
|
|
|
|
msg: logMessage,
|
|
|
|
args: args,
|
|
|
|
level: level,
|
|
|
|
loggerName: this.loggerName,
|
|
|
|
});
|
2020-04-09 07:45:24 -04:00
|
|
|
|
2020-07-05 23:57:31 -04:00
|
|
|
this.#handlers.forEach((handler): void => {
|
2019-11-13 13:42:34 -05:00
|
|
|
handler.handle(record);
|
|
|
|
});
|
2020-06-12 09:27:41 -04:00
|
|
|
|
|
|
|
return msg instanceof Function ? fnResult : msg;
|
|
|
|
}
|
|
|
|
|
|
|
|
asString(data: unknown): string {
|
|
|
|
if (typeof data === "string") {
|
|
|
|
return data;
|
|
|
|
} else if (
|
|
|
|
data === null ||
|
|
|
|
typeof data === "number" ||
|
|
|
|
typeof data === "bigint" ||
|
|
|
|
typeof data === "boolean" ||
|
|
|
|
typeof data === "undefined" ||
|
|
|
|
typeof data === "symbol"
|
|
|
|
) {
|
|
|
|
return String(data);
|
|
|
|
} else if (typeof data === "object") {
|
|
|
|
return JSON.stringify(data);
|
|
|
|
}
|
|
|
|
return "undefined";
|
2018-12-19 13:16:45 -05:00
|
|
|
}
|
|
|
|
|
2020-06-12 09:27:41 -04:00
|
|
|
debug<T>(msg: () => T, ...args: unknown[]): T | undefined;
|
2020-08-24 19:43:54 -04:00
|
|
|
debug<T>(msg: T extends GenericFunction ? never : T, ...args: unknown[]): T;
|
2020-06-12 09:27:41 -04:00
|
|
|
debug<T>(
|
2020-08-24 19:43:54 -04:00
|
|
|
msg: (T extends GenericFunction ? never : T) | (() => T),
|
2020-06-12 09:27:41 -04:00
|
|
|
...args: unknown[]
|
|
|
|
): T | undefined {
|
|
|
|
return this._log(LogLevels.DEBUG, msg, ...args);
|
2018-12-19 13:16:45 -05:00
|
|
|
}
|
|
|
|
|
2020-06-12 09:27:41 -04:00
|
|
|
info<T>(msg: () => T, ...args: unknown[]): T | undefined;
|
2020-08-24 19:43:54 -04:00
|
|
|
info<T>(msg: T extends GenericFunction ? never : T, ...args: unknown[]): T;
|
2020-06-12 09:27:41 -04:00
|
|
|
info<T>(
|
2020-08-24 19:43:54 -04:00
|
|
|
msg: (T extends GenericFunction ? never : T) | (() => T),
|
2020-06-12 09:27:41 -04:00
|
|
|
...args: unknown[]
|
|
|
|
): T | undefined {
|
|
|
|
return this._log(LogLevels.INFO, msg, ...args);
|
2018-12-19 13:16:45 -05:00
|
|
|
}
|
|
|
|
|
2020-06-12 09:27:41 -04:00
|
|
|
warning<T>(msg: () => T, ...args: unknown[]): T | undefined;
|
2020-08-24 19:43:54 -04:00
|
|
|
warning<T>(msg: T extends GenericFunction ? never : T, ...args: unknown[]): T;
|
2020-06-12 09:27:41 -04:00
|
|
|
warning<T>(
|
2020-08-24 19:43:54 -04:00
|
|
|
msg: (T extends GenericFunction ? never : T) | (() => T),
|
2020-06-12 09:27:41 -04:00
|
|
|
...args: unknown[]
|
|
|
|
): T | undefined {
|
|
|
|
return this._log(LogLevels.WARNING, msg, ...args);
|
2018-12-19 13:16:45 -05:00
|
|
|
}
|
|
|
|
|
2020-06-12 09:27:41 -04:00
|
|
|
error<T>(msg: () => T, ...args: unknown[]): T | undefined;
|
2020-08-24 19:43:54 -04:00
|
|
|
error<T>(msg: T extends GenericFunction ? never : T, ...args: unknown[]): T;
|
2020-06-12 09:27:41 -04:00
|
|
|
error<T>(
|
2020-08-24 19:43:54 -04:00
|
|
|
msg: (T extends GenericFunction ? never : T) | (() => T),
|
2020-06-12 09:27:41 -04:00
|
|
|
...args: unknown[]
|
|
|
|
): T | undefined {
|
|
|
|
return this._log(LogLevels.ERROR, msg, ...args);
|
2018-12-19 13:16:45 -05:00
|
|
|
}
|
|
|
|
|
2020-06-12 09:27:41 -04:00
|
|
|
critical<T>(msg: () => T, ...args: unknown[]): T | undefined;
|
|
|
|
critical<T>(
|
2020-08-24 19:43:54 -04:00
|
|
|
msg: T extends GenericFunction ? never : T,
|
|
|
|
...args: unknown[]
|
|
|
|
): T;
|
|
|
|
critical<T>(
|
|
|
|
msg: (T extends GenericFunction ? never : T) | (() => T),
|
2020-06-12 09:27:41 -04:00
|
|
|
...args: unknown[]
|
|
|
|
): T | undefined {
|
|
|
|
return this._log(LogLevels.CRITICAL, msg, ...args);
|
2018-12-19 13:16:45 -05:00
|
|
|
}
|
|
|
|
}
|