import winston from 'winston';
import { config } from '../config/index.js';
import path from 'path';
import fs from 'fs';
// Create logs directory if it doesn't exist
const logsDir = path.join(process.cwd(), 'logs');
if (!fs.existsSync(logsDir)) {
fs.mkdirSync(logsDir, { recursive: true });
}
// Define log format
const logFormat = winston.format.combine(
winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }),
winston.format.errors({ stack: true }),
winston.format.splat(),
winston.format.json()
);
// Define console format (more readable for development)
const consoleFormat = winston.format.combine(
winston.format.colorize(),
winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }),
winston.format.printf(({ level, message, timestamp, ...meta }) => {
const metaString = Object.keys(meta).length ? `\n${JSON.stringify(meta, null, 2)}` : '';
return `${timestamp} [${level}]: ${message}${metaString}`;
})
);
// Create the logger
const logger = winston.createLogger({
level: config.logging.level || 'info',
format: logFormat,
defaultMeta: { service: 'frontapp-mcp' },
transports: [
// Write logs to files
new winston.transports.File({
filename: path.join(logsDir, 'error.log'),
level: 'error',
maxsize: 10 * 1024 * 1024, // 10MB
maxFiles: 5,
}),
new winston.transports.File({
filename: path.join(logsDir, 'combined.log'),
maxsize: 10 * 1024 * 1024, // 10MB
maxFiles: 5,
}),
],
});
// If we're not in production, also log to the console
if (process.env.NODE_ENV !== 'production') {
logger.add(
new winston.transports.Console({
format: consoleFormat,
})
);
}
// Create a stream object for Morgan (HTTP request logging)
export const logStream = {
write: (message: string): void => {
logger.info(message.trim());
},
};
// Export a function to add request context to logs
export function createRequestLogger(requestId: string): winston.Logger {
return logger.child({ requestId });
}
// Export the logger
export default logger;