thrilled-be-core
Version:
Core Express backend package with middleware, logging, security, and base application setup
126 lines (125 loc) • 4.75 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.defaultLogger = exports.Logger = void 0;
exports.createLogger = createLogger;
const tslib_1 = require("tslib");
const fs_1 = require("fs");
const path_1 = require("path");
const winston_1 = tslib_1.__importDefault(require("winston"));
const winston_daily_rotate_file_1 = tslib_1.__importDefault(require("winston-daily-rotate-file"));
class Logger {
winston;
config;
constructor(config) {
this.config = {
level: 'info',
dir: './logs',
format: 'simple',
httpLogging: true,
maxFiles: 30,
correlationId: true,
...config,
};
this.winston = this.createLogger();
}
static create(config) {
return new Logger(config);
}
info(message, meta) {
this.winston.info(message, this.addCorrelation(meta));
}
error(error, context) {
if (error instanceof Error) {
this.winston.error(error.message, this.addCorrelation({
...context,
stack: error.stack,
name: error.name,
}));
}
else {
this.winston.error(error, this.addCorrelation(context));
}
}
warn(message, meta) {
this.winston.warn(message, this.addCorrelation(meta));
}
debug(message, meta) {
this.winston.debug(message, this.addCorrelation(meta));
}
createLogger() {
// Ensure log directory exists
const logDir = this.config.dir || './logs';
if (!(0, fs_1.existsSync)(logDir)) {
(0, fs_1.mkdirSync)(logDir, { recursive: true });
}
const format = this.config.format === 'json'
? winston_1.default.format.combine(winston_1.default.format.timestamp({
format: 'YYYY-MM-DD HH:mm:ss',
}), winston_1.default.format.errors({ stack: true }), winston_1.default.format.json())
: winston_1.default.format.combine(winston_1.default.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }), winston_1.default.format.errors({ stack: true }), winston_1.default.format.printf(({ timestamp, level, message }) => {
return `${timestamp} ${level}: ${message}`;
}));
// Console format for development (timestamp first, then colorized)
const consoleFormat = winston_1.default.format.combine(winston_1.default.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }), winston_1.default.format.errors({ stack: true }), winston_1.default.format.printf(({ timestamp, level, message }) => {
return `${timestamp} ${level}: ${message}`;
}), winston_1.default.format.colorize({ all: true }));
const transports = [
// Console transport for development
new winston_1.default.transports.Console({
level: process.env.NODE_ENV === 'production' ? 'info' : 'debug',
format: consoleFormat,
}),
// File transport for all logs
new winston_daily_rotate_file_1.default({
level: this.config.level,
datePattern: 'YYYY-MM-DD',
dirname: (0, path_1.join)(logDir, 'combined'),
filename: '%DATE%.log',
maxFiles: this.config.maxFiles,
zippedArchive: true,
format,
}),
// Error-only file transport
new winston_daily_rotate_file_1.default({
level: 'error',
datePattern: 'YYYY-MM-DD',
dirname: (0, path_1.join)(logDir, 'error'),
filename: '%DATE%.log',
maxFiles: this.config.maxFiles,
zippedArchive: true,
format,
}),
];
return winston_1.default.createLogger({
level: this.config.level,
format,
transports,
exitOnError: false,
});
}
addCorrelation(meta) {
if (!this.config.correlationId) {
return meta || {};
}
// In a real implementation, you'd get this from async local storage
// or from the request context
return {
...meta,
correlationId: this.generateCorrelationId(),
};
}
generateCorrelationId() {
return Math.random().toString(36).substring(2, 15);
}
}
exports.Logger = Logger;
// Default logger instance for convenience
exports.defaultLogger = new Logger({
level: 'info',
dir: './logs',
format: 'simple',
});
// Convenience function to create a logger with custom config
function createLogger(config) {
return new Logger(config);
}