import winston, { LogEntry, LoggerOptions } from "winston";
import Transport from "winston-transport";
import {
Logger,
LoggerFactory,
LogMeta,
LoggingConfig,
StringLike,
} from "../types";
import { Logging, MiniLogger } from "../logging";
import { LogLevel } from "../constants";
/**
* @description A logger implementation that uses Winston.
* @summary This class extends {@link MiniLogger} to provide logging functionality using the Winston library. It configures Winston with the appropriate transports and formats based on the logging configuration.
* @param {string} [cont] - The context (typically the class name) that this logger is associated with.
* @param {Partial<LoggingConfig>} [conf] - Optional configuration to override global settings.
* @class WinstonLogger
* @example
* // Create a Winston logger for a class
* const logger = new WinstonLogger('MyClass');
*
* // Log messages at different levels
* logger.info('Application started');
* logger.error(new Error('Something went wrong'));
*
* // Create a child logger for a specific method
* const methodLogger = logger.for('myMethod');
* methodLogger.debug('Processing data...');
*/
export class WinstonLogger extends MiniLogger implements Logger {
protected winston: winston.Logger;
constructor(cont?: string, conf?: Partial<LoggingConfig>) {
super(cont, conf);
const config = Object.assign(
{},
Logging.getConfig(),
this.conf || {}
) as LoggingConfig<Transport>;
const transports = this.resolveTransports(
(config.transports as Transport[] | undefined) || undefined
);
const passThrough = winston.format.printf(({ message }) =>
typeof message === "string" ? message : JSON.stringify(message)
);
const winstonConfig: LoggerOptions = {
level: config.level,
transports,
format: passThrough,
};
this.winston = winston.createLogger(winstonConfig);
}
private resolveTransports(transports?: Transport[]): Transport[] {
if (transports && transports.length) return transports;
return [new winston.transports.Console()];
}
/**
* @description Logs a message with the specified log level using Winston.
* @summary This method overrides the base log method to use Winston for logging.
* @param {LogLevel} level - The log level of the message.
* @param {(StringLike|Error)} msg - The message to be logged or an Error object.
* @param {Error} [error] - An optional stack trace to include in the log.
* @return {void}
*/
protected override log(
level: LogLevel,
msg: StringLike | Error,
error?: Error,
meta?: LogMeta
) {
const logData: LogEntry = {
level: level,
message: this.createLog(level, msg, error, meta),
};
if (this.config("correlationId"))
logData["correlationId"] = this.config("correlationId");
this.winston.log(logData);
}
}
/**
* @description A factory function for creating Winston loggers.
* @summary This is a {@link LoggerFactory} implementation that creates {@link WinstonLogger} instances.
* @param {string} [context] - The context (typically the class name) for the logger.
* @param {Partial<LoggingConfig>} [conf] - Optional configuration to override global settings.
* @param {...any} _args - Additional arguments to pass to the WinstonLogger constructor.
* @return {WinstonLogger} A new WinstonLogger instance.
* @const WinstonFactory
* @memberOf module:Logging
*/
export const WinstonFactory: LoggerFactory = (
context?: string,
conf?: Partial<LoggingConfig>,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
..._args: any[]
): WinstonLogger => new WinstonLogger(context, conf);
Source