@node-dlc/logger
Version:
148 lines (126 loc) • 3.63 kB
text/typescript
/* eslint-disable @typescript-eslint/no-explicit-any */
import util from 'util';
import { LogLevel } from './log-level';
import { ITransport } from './transport';
import { shouldLog } from './util';
export interface ILogger {
area: string;
instance: string;
trace(...args: any[]): void;
debug(...args: any[]): void;
info(...args: any[]): void;
warn(...args: any[]): void;
error(...args: any[]): void;
sub(area: string, instance?: string): ILogger;
}
export class Logger implements ILogger {
public readonly area: string;
public readonly instance: string;
private _transports: ITransport[];
private _level: LogLevel;
private _root: Logger;
constructor(area = '', instance?: string) {
this._root = this;
this.area = area;
this.instance = instance;
this._level = LogLevel.Info;
this._transports = [];
// create bound methods so consumer doesnt lose context
this.trace = this.trace.bind(this);
this.debug = this.debug.bind(this);
this.info = this.info.bind(this);
this.warn = this.warn.bind(this);
this.error = this.error.bind(this);
}
/**
* Configured log-level
*/
get level(): LogLevel {
return this._root._level;
}
set level(value: LogLevel) {
this._root._level = value;
}
/**
* Gets the available transports
*/
get transports(): ITransport[] {
return this._root._transports;
}
/**
* Constructs a sub-logger under the current parent
* @param area optional area, if not provided it inherits from the parent
* @param instance optional instance, if not provied it inherits from the parent
*/
public sub(area?: string, instance?: string): Logger {
const logger = new Logger(area || this.area, instance || this.instance);
logger._root = this._root;
return logger;
}
/**
* Write a trace message
*/
public trace(...args: any[]): void {
this._log(LogLevel.Trace, this.area, this.instance, args);
}
/**
* Write a debug message
* @param args variadic arguments
*/
public debug(...args: any[]): void {
this._log(LogLevel.Debug, this.area, this.instance, args);
}
/**
* Write an info message
* @param args variadic arguments
*/
public info(...args: any[]): void {
this._log(LogLevel.Info, this.area, this.instance, args);
}
/**
* Write a warning message
* @param args variadic arguments
*/
public warn(...args: any[]): void {
this._log(LogLevel.Warn, this.area, this.instance, args);
}
/**
* Write an error message
* @param args variadic arguments
*/
public error(...args: any[]): void {
this._log(LogLevel.Error, this.area, this.instance, args);
}
/////////////////////////////
private _log(
level: LogLevel,
area: string,
instance: string,
args: any[],
): void {
if (!shouldLog(this.level, level)) return;
const formattedMsg = this._format(level, area, instance, args);
this._write(formattedMsg);
}
private _format(
level: LogLevel,
area: string,
instance: string,
args: any[],
): string {
const date = new Date().toISOString();
const formattedArea = area ? ' ' + area : '';
const instanceFmt = instance ? ' ' + instance : '';
// convert buffers to hex encodings
args = args.map((arg) =>
Buffer.isBuffer(arg) ? arg.toString('hex') : arg,
);
const msg = util.format(args[0], ...args.slice(1));
return `${date} [${level}]${formattedArea}${instanceFmt}: ${msg}`;
}
private _write(msg: string): void {
for (const transport of this._root.transports) {
transport.write(msg);
}
}
}