Initial commit: Inventory Barcode System
This commit is contained in:
166
utils/logger.js
Normal file
166
utils/logger.js
Normal file
@ -0,0 +1,166 @@
|
||||
const winston = require('winston');
|
||||
const DailyRotateFile = require('winston-daily-rotate-file');
|
||||
const path = require('path');
|
||||
|
||||
// Create logs directory if it doesn't exist
|
||||
const logsDir = path.join(__dirname, '..', 'logs');
|
||||
|
||||
// Define log levels and colors
|
||||
const logLevels = {
|
||||
error: 0,
|
||||
warn: 1,
|
||||
info: 2,
|
||||
http: 3,
|
||||
debug: 4
|
||||
};
|
||||
|
||||
const logColors = {
|
||||
error: 'red',
|
||||
warn: 'yellow',
|
||||
info: 'green',
|
||||
http: 'magenta',
|
||||
debug: 'blue'
|
||||
};
|
||||
|
||||
winston.addColors(logColors);
|
||||
|
||||
// Custom format for structured logging
|
||||
const logFormat = winston.format.combine(
|
||||
winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }),
|
||||
winston.format.errors({ stack: true }),
|
||||
winston.format.json(),
|
||||
winston.format.printf(({ timestamp, level, message, stack, ...meta }) => {
|
||||
let logMessage = `${timestamp} [${level.toUpperCase()}]: ${message}`;
|
||||
|
||||
// Add stack trace for errors
|
||||
if (stack) {
|
||||
logMessage += `\nStack: ${stack}`;
|
||||
}
|
||||
|
||||
// Add metadata if present
|
||||
if (Object.keys(meta).length > 0) {
|
||||
logMessage += `\nMeta: ${JSON.stringify(meta, null, 2)}`;
|
||||
}
|
||||
|
||||
return logMessage;
|
||||
})
|
||||
);
|
||||
|
||||
// Console format for development
|
||||
const consoleFormat = winston.format.combine(
|
||||
winston.format.colorize({ all: true }),
|
||||
winston.format.timestamp({ format: 'HH:mm:ss' }),
|
||||
winston.format.printf(({ timestamp, level, message, stack }) => {
|
||||
let logMessage = `${timestamp} ${level}: ${message}`;
|
||||
if (stack) {
|
||||
logMessage += `\n${stack}`;
|
||||
}
|
||||
return logMessage;
|
||||
})
|
||||
);
|
||||
|
||||
// Create transports
|
||||
const transports = [
|
||||
// Console transport for development
|
||||
new winston.transports.Console({
|
||||
level: process.env.NODE_ENV === 'production' ? 'info' : 'debug',
|
||||
format: consoleFormat,
|
||||
handleExceptions: true,
|
||||
handleRejections: true
|
||||
}),
|
||||
|
||||
// File transport for all logs
|
||||
new DailyRotateFile({
|
||||
filename: path.join(logsDir, 'application-%DATE%.log'),
|
||||
datePattern: 'YYYY-MM-DD',
|
||||
maxSize: '20m',
|
||||
maxFiles: '14d',
|
||||
level: 'debug',
|
||||
format: logFormat,
|
||||
handleExceptions: true,
|
||||
handleRejections: true
|
||||
}),
|
||||
|
||||
// Separate file for errors
|
||||
new DailyRotateFile({
|
||||
filename: path.join(logsDir, 'error-%DATE%.log'),
|
||||
datePattern: 'YYYY-MM-DD',
|
||||
maxSize: '20m',
|
||||
maxFiles: '30d',
|
||||
level: 'error',
|
||||
format: logFormat,
|
||||
handleExceptions: true,
|
||||
handleRejections: true
|
||||
}),
|
||||
|
||||
// HTTP requests log
|
||||
new DailyRotateFile({
|
||||
filename: path.join(logsDir, 'http-%DATE%.log'),
|
||||
datePattern: 'YYYY-MM-DD',
|
||||
maxSize: '20m',
|
||||
maxFiles: '7d',
|
||||
level: 'http',
|
||||
format: logFormat
|
||||
})
|
||||
];
|
||||
|
||||
// Create logger instance
|
||||
const logger = winston.createLogger({
|
||||
levels: logLevels,
|
||||
transports,
|
||||
exitOnError: false
|
||||
});
|
||||
|
||||
// Add request logging helper
|
||||
logger.logRequest = (req, res, responseTime) => {
|
||||
const logData = {
|
||||
method: req.method,
|
||||
url: req.originalUrl,
|
||||
ip: req.ip || req.connection.remoteAddress,
|
||||
userAgent: req.get('User-Agent'),
|
||||
statusCode: res.statusCode,
|
||||
responseTime: `${responseTime}ms`,
|
||||
contentLength: res.get('Content-Length') || 0
|
||||
};
|
||||
|
||||
// Log based on status code
|
||||
if (res.statusCode >= 500) {
|
||||
logger.error('HTTP Request Error', logData);
|
||||
} else if (res.statusCode >= 400) {
|
||||
logger.warn('HTTP Request Warning', logData);
|
||||
} else {
|
||||
logger.http('HTTP Request', logData);
|
||||
}
|
||||
};
|
||||
|
||||
// Add database operation logging helper
|
||||
logger.logDbOperation = (operation, table, data = {}, duration = null) => {
|
||||
const logData = {
|
||||
operation,
|
||||
table,
|
||||
duration: duration ? `${duration}ms` : null,
|
||||
...data
|
||||
};
|
||||
|
||||
logger.debug('Database Operation', logData);
|
||||
};
|
||||
|
||||
// Add error context helper
|
||||
logger.logError = (error, context = {}) => {
|
||||
const errorData = {
|
||||
message: error.message,
|
||||
stack: error.stack,
|
||||
name: error.name,
|
||||
code: error.code,
|
||||
...context
|
||||
};
|
||||
|
||||
logger.error('Application Error', errorData);
|
||||
};
|
||||
|
||||
// Add business logic logging helper
|
||||
logger.logBusinessEvent = (event, data = {}) => {
|
||||
logger.info(`Business Event: ${event}`, data);
|
||||
};
|
||||
|
||||
module.exports = logger;
|
||||
Reference in New Issue
Block a user