stock-bot/libs/utils/src/logger.ts

108 lines
2.7 KiB
TypeScript

/**
* Logger utility with consistent formatting and log levels
* Supports console and Loki logging
*/
import { loggingConfig } from '@stock-bot/config';
import { LokiClient } from './lokiClient';
// Singleton Loki client
let lokiClient: LokiClient | null = null;
function getLokiClient(): LokiClient {
if (!lokiClient) {
lokiClient = new LokiClient(loggingConfig);
}
return lokiClient;
}
export class Logger {
constructor(private serviceName: string, private level: LogLevel = LogLevel.INFO) {}
debug(message: string, ...args: any[]): void {
this.log(LogLevel.DEBUG, message, ...args);
}
info(message: string, ...args: any[]): void {
this.log(LogLevel.INFO, message, ...args);
}
warn(message: string, ...args: any[]): void {
this.log(LogLevel.WARN, message, ...args);
}
error(message: string, ...args: any[]): void {
this.log(LogLevel.ERROR, message, ...args);
}
private log(level: LogLevel, message: string, ...args: any[]): void {
if (level < this.level) return;
const timestamp = new Date().toISOString();
const levelStr = LogLevel[level].padEnd(5);
const formattedArgs = args.length ? this.formatArgs(args) : '';
const fullMessage = `${message}${formattedArgs}`;
const logMessage = `[${timestamp}] [${levelStr}] [${this.serviceName}] ${fullMessage}`;
// Console logging
if (loggingConfig.console) {
switch (level) {
case LogLevel.ERROR:
console.error(logMessage);
break;
case LogLevel.WARN:
console.warn(logMessage);
break;
case LogLevel.INFO:
console.info(logMessage);
break;
case LogLevel.DEBUG:
default:
console.debug(logMessage);
break;
}
}
// Loki logging
try {
const loki = getLokiClient();
loki.log(LogLevel[level].toLowerCase(), fullMessage, this.serviceName);
} catch (error) {
console.error('Failed to send log to Loki:', error);
}
}
private formatArgs(args: any[]): string {
try {
return args.map(arg => {
if (arg instanceof Error) {
return ` ${arg.message}\n${arg.stack}`;
} else if (typeof arg === 'object') {
return ` ${JSON.stringify(arg)}`;
} else {
return ` ${arg}`;
}
}).join('');
} catch (error) {
return ` [Error formatting log arguments: ${error}]`;
}
}
setLevel(level: LogLevel): void {
this.level = level;
}
}
export enum LogLevel {
DEBUG = 0,
INFO = 1,
WARN = 2,
ERROR = 3
}
/**
* Create a new logger instance
*/
export function createLogger(serviceName: string, level: LogLevel = LogLevel.INFO): Logger {
return new Logger(serviceName, level);
}