use winstonlog

This commit is contained in:
2025-03-13 18:35:35 +08:00
parent 6d29a208f1
commit bb98531073
2 changed files with 83 additions and 66 deletions

View File

@@ -31,6 +31,7 @@
"pg": "^8.14.0", "pg": "^8.14.0",
"redis": "^4.7.0", "redis": "^4.7.0",
"uuid": "^11.1.0", "uuid": "^11.1.0",
"winston": "^3.17.0",
"yargs": "^17.7.2" "yargs": "^17.7.2"
}, },
"devDependencies": { "devDependencies": {

View File

@@ -1,71 +1,79 @@
import winston from 'winston';
import fs from 'fs'; import fs from 'fs';
import path from 'path'; import path from 'path';
import config from '../config'; import config from '../config';
/** // Define log levels matching existing implementation
* Logger levels const levels = {
*/ error: 0,
export enum LogLevel { warn: 1,
DEBUG = 'DEBUG', info: 2,
INFO = 'INFO', debug: 3
WARN = 'WARN', };
ERROR = 'ERROR'
}
/**
* Utility class for logging messages to console and file
*/
class Logger {
private logDir: string;
private logFile: string;
private debugEnabled: boolean;
constructor() {
// Set up log directory
this.logDir = path.join(process.cwd(), 'logs');
// Create logs directory if it doesn't exist // Create logs directory if it doesn't exist
if (!fs.existsSync(this.logDir)) { const logDir = path.join(process.cwd(), 'logs');
fs.mkdirSync(this.logDir, { recursive: true }); if (!fs.existsSync(logDir)) {
fs.mkdirSync(logDir, { recursive: true });
} }
// Set log file path with date in filename // Set log file path with date in filename
const now = new Date(); const now = new Date();
const dateStr = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}-${String(now.getDate()).padStart(2, '0')}`; const dateStr = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}-${String(now.getDate()).padStart(2, '0')}`;
this.logFile = path.join(this.logDir, `app-${dateStr}.log`); const logFile = path.join(logDir, `app-${dateStr}.log`);
// Enable debug logs based on environment (NODE_ENV) // Define log format
this.debugEnabled = process.env.NODE_ENV !== 'production'; const logFormat = winston.format.printf(({ timestamp, level, message, ...metadata }) => {
} let logMessage = `[${timestamp}] [${level.toUpperCase()}] ${message}`;
/** // Add metadata if exists and is not empty
* Format log message with timestamp and level if (metadata && Object.keys(metadata).length > 0) {
*/
private formatMessage(level: LogLevel, message: string, data?: any): string {
const timestamp = new Date().toISOString();
let formattedMessage = `[${timestamp}] [${level}] ${message}`;
if (data) {
if (typeof data === 'object') {
try { try {
const dataStr = JSON.stringify(data); logMessage += ` - ${JSON.stringify(metadata)}`;
formattedMessage += ` - ${dataStr}`;
} catch (error) { } catch (error) {
formattedMessage += ` - [Object cannot be stringified]`; logMessage += ` - [Object cannot be stringified]`;
}
} else {
formattedMessage += ` - ${data}`;
} }
} }
return formattedMessage; return logMessage;
} });
// Create Winston logger
const winstonLogger = winston.createLogger({
levels,
level: process.env.NODE_ENV !== 'production' ? 'debug' : 'info',
format: winston.format.combine(
winston.format.timestamp(),
winston.format.errors({ stack: true }),
logFormat
),
transports: [
// Console transport
new winston.transports.Console({
format: winston.format.combine(
winston.format.colorize(),
winston.format.timestamp(),
logFormat
)
}),
// File transport
new winston.transports.File({
filename: logFile
})
],
exitOnError: false
});
/** /**
* Write log to file * Logger interface that matches the previous implementation
*/ */
private writeToFile(message: string): void { class Logger {
fs.appendFileSync(this.logFile, message + '\n'); private logFile: string;
private debugEnabled: boolean;
constructor() {
this.logFile = logFile;
this.debugEnabled = process.env.NODE_ENV !== 'production';
} }
/** /**
@@ -74,27 +82,33 @@ class Logger {
debug(message: string, data?: any): void { debug(message: string, data?: any): void {
if (!this.debugEnabled) return; if (!this.debugEnabled) return;
const formattedMessage = this.formatMessage(LogLevel.DEBUG, message, data); if (data) {
console.debug(formattedMessage); winstonLogger.debug(message, data);
this.writeToFile(formattedMessage); } else {
winstonLogger.debug(message);
}
} }
/** /**
* Info level log * Info level log
*/ */
info(message: string, data?: any): void { info(message: string, data?: any): void {
const formattedMessage = this.formatMessage(LogLevel.INFO, message, data); if (data) {
console.info(formattedMessage); winstonLogger.info(message, data);
this.writeToFile(formattedMessage); } else {
winstonLogger.info(message);
}
} }
/** /**
* Warning level log * Warning level log
*/ */
warn(message: string, data?: any): void { warn(message: string, data?: any): void {
const formattedMessage = this.formatMessage(LogLevel.WARN, message, data); if (data) {
console.warn(formattedMessage); winstonLogger.warn(message, data);
this.writeToFile(formattedMessage); } else {
winstonLogger.warn(message);
}
} }
/** /**
@@ -112,9 +126,11 @@ class Logger {
}; };
} }
const formattedMessage = this.formatMessage(LogLevel.ERROR, message, errorData); if (errorData) {
console.error(formattedMessage); winstonLogger.error(message, errorData);
this.writeToFile(formattedMessage); } else {
winstonLogger.error(message);
}
} }
/** /**