mirror of
https://github.com/nestjs/nest.git
synced 2026-02-21 23:11:44 +00:00
183 lines
5.1 KiB
TypeScript
183 lines
5.1 KiB
TypeScript
import { Injectable } from '../decorators/core/injectable.decorator';
|
|
import { Optional } from '../decorators/core/optional.decorator';
|
|
import { clc, yellow } from '../utils/cli-colors.util';
|
|
import { isObject, isPlainObject } from '../utils/shared.utils';
|
|
|
|
declare const process: any;
|
|
|
|
export type LogLevel = 'log' | 'error' | 'warn' | 'debug' | 'verbose';
|
|
|
|
export interface LoggerService {
|
|
log(message: any, context?: string);
|
|
error(message: any, trace?: string, context?: string);
|
|
warn(message: any, context?: string);
|
|
debug?(message: any, context?: string);
|
|
verbose?(message: any, context?: string);
|
|
}
|
|
|
|
@Injectable()
|
|
export class Logger implements LoggerService {
|
|
private static logLevels: LogLevel[] = [
|
|
'log',
|
|
'error',
|
|
'warn',
|
|
'debug',
|
|
'verbose',
|
|
];
|
|
private static lastTimestamp?: number;
|
|
protected static instance?: typeof Logger | LoggerService = Logger;
|
|
|
|
constructor(
|
|
@Optional() protected context?: string,
|
|
@Optional() private readonly isTimestampEnabled = false,
|
|
) {}
|
|
|
|
error(message: any, trace = '', context?: string) {
|
|
const instance = this.getInstance();
|
|
if (!this.isLogLevelEnabled('error')) {
|
|
return;
|
|
}
|
|
instance &&
|
|
instance.error.call(instance, message, trace, context || this.context);
|
|
}
|
|
|
|
log(message: any, context?: string) {
|
|
this.callFunction('log', message, context);
|
|
}
|
|
|
|
warn(message: any, context?: string) {
|
|
this.callFunction('warn', message, context);
|
|
}
|
|
|
|
debug(message: any, context?: string) {
|
|
this.callFunction('debug', message, context);
|
|
}
|
|
|
|
verbose(message: any, context?: string) {
|
|
this.callFunction('verbose', message, context);
|
|
}
|
|
|
|
setContext(context: string) {
|
|
this.context = context;
|
|
}
|
|
|
|
getTimestamp() {
|
|
return Logger.getTimestamp();
|
|
}
|
|
|
|
static overrideLogger(logger: LoggerService | LogLevel[] | boolean) {
|
|
if (Array.isArray(logger)) {
|
|
this.logLevels = logger;
|
|
return;
|
|
}
|
|
this.instance = isObject(logger) ? (logger as LoggerService) : undefined;
|
|
}
|
|
|
|
static log(message: any, context = '', isTimeDiffEnabled = true) {
|
|
this.printMessage(message, clc.green, context, isTimeDiffEnabled);
|
|
}
|
|
|
|
static error(
|
|
message: any,
|
|
trace = '',
|
|
context = '',
|
|
isTimeDiffEnabled = true,
|
|
) {
|
|
this.printMessage(message, clc.red, context, isTimeDiffEnabled, 'stderr');
|
|
this.printStackTrace(trace);
|
|
}
|
|
|
|
static warn(message: any, context = '', isTimeDiffEnabled = true) {
|
|
this.printMessage(message, clc.yellow, context, isTimeDiffEnabled);
|
|
}
|
|
|
|
static debug(message: any, context = '', isTimeDiffEnabled = true) {
|
|
this.printMessage(message, clc.magentaBright, context, isTimeDiffEnabled);
|
|
}
|
|
|
|
static verbose(message: any, context = '', isTimeDiffEnabled = true) {
|
|
this.printMessage(message, clc.cyanBright, context, isTimeDiffEnabled);
|
|
}
|
|
|
|
static getTimestamp() {
|
|
const localeStringOptions = {
|
|
year: 'numeric',
|
|
hour: 'numeric',
|
|
minute: 'numeric',
|
|
second: 'numeric',
|
|
day: '2-digit',
|
|
month: '2-digit',
|
|
};
|
|
return new Date(Date.now()).toLocaleString(undefined, localeStringOptions);
|
|
}
|
|
|
|
private callFunction(
|
|
name: 'log' | 'warn' | 'debug' | 'verbose',
|
|
message: any,
|
|
context?: string,
|
|
) {
|
|
if (!this.isLogLevelEnabled(name)) {
|
|
return;
|
|
}
|
|
const instance = this.getInstance();
|
|
const func = instance && (instance as typeof Logger)[name];
|
|
func &&
|
|
func.call(
|
|
instance,
|
|
message,
|
|
context || this.context,
|
|
this.isTimestampEnabled,
|
|
);
|
|
}
|
|
|
|
protected getInstance(): typeof Logger | LoggerService {
|
|
const { instance } = Logger;
|
|
return instance === this ? Logger : instance;
|
|
}
|
|
|
|
private isLogLevelEnabled(level: LogLevel): boolean {
|
|
return Logger.logLevels.includes(level);
|
|
}
|
|
|
|
private static printMessage(
|
|
message: any,
|
|
color: (message: string) => string,
|
|
context = '',
|
|
isTimeDiffEnabled?: boolean,
|
|
writeStreamType?: 'stdout' | 'stderr',
|
|
) {
|
|
const output = isPlainObject(message)
|
|
? `${color('Object:')}\n${JSON.stringify(message, null, 2)}\n`
|
|
: color(message);
|
|
|
|
const pidMessage = color(`[Nest] ${process.pid} - `);
|
|
const contextMessage = context ? yellow(`[${context}] `) : '';
|
|
const timestampDiff = this.updateAndGetTimestampDiff(isTimeDiffEnabled);
|
|
const instance = (this.instance as typeof Logger) ?? Logger;
|
|
const timestamp = instance.getTimestamp
|
|
? instance.getTimestamp()
|
|
: Logger.getTimestamp?.();
|
|
const computedMessage = `${pidMessage}${timestamp} ${contextMessage}${output}${timestampDiff}\n`;
|
|
|
|
process[writeStreamType ?? 'stdout'].write(computedMessage);
|
|
}
|
|
|
|
private static updateAndGetTimestampDiff(
|
|
isTimeDiffEnabled?: boolean,
|
|
): string {
|
|
const includeTimestamp = Logger.lastTimestamp && isTimeDiffEnabled;
|
|
const result = includeTimestamp
|
|
? yellow(` +${Date.now() - Logger.lastTimestamp}ms`)
|
|
: '';
|
|
Logger.lastTimestamp = Date.now();
|
|
return result;
|
|
}
|
|
|
|
private static printStackTrace(trace: string) {
|
|
if (!trace) {
|
|
return;
|
|
}
|
|
process.stderr.write(`${trace}\n`);
|
|
}
|
|
}
|