snglpi/src/utils/logger.js

120 lines
4.0 KiB
JavaScript
Raw Normal View History

2025-08-30 19:04:35 -03:00
const winston = require('winston');
const path = require('path');
require('winston-daily-rotate-file');
const fs = require('fs');
2025-08-30 19:04:35 -03:00
// verifica se a pasta de logs existe, se não, cria
const logsDir = path.join(__dirname, '../../logs');
if (!fs.existsSync(logsDir)) {
fs.mkdirSync(logsDir, { recursive: true });
}
const isProduction = process.env.NODE_ENV === 'production';
const logLevel = process.env.LOG_LEVEL || 'info';
const logToConsole = process.env.LOG_TO_CONSOLE
? process.env.LOG_TO_CONSOLE === 'true'
: !isProduction;
// Configuração do logger com winston
2025-08-30 19:04:35 -03:00
const logger = winston.createLogger({
level: logLevel,
format: winston.format.combine(winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }), winston.format.errors({ stack: true })),
2025-08-30 19:04:35 -03:00
transports: [
// Log geral da aplicação
new winston.transports.DailyRotateFile({
filename: path.join(logsDir, 'app-%DATE%.log'),
datePattern: 'YYYY-MM-DD',
zippedArchive: true,
maxSize: '5m',
maxFiles: '10d',
format: winston.format.combine(
winston.format.printf((info) => {
const { timestamp, level, message, stack, ...meta } = info;
let logMessage = `${timestamp} [${level}]: ${message}${stack ? `\n${stack}` : ''}`;
if (Object.keys(meta).length) {
logMessage += ` ${JSON.stringify(meta, null, 2)}`;
}
return logMessage;
})
),
}),
// Log de erros
new winston.transports.DailyRotateFile({
filename: path.join(logsDir, 'error-%DATE%.log'),
level: 'error',
datePattern: 'YYYY-MM-DD',
zippedArchive: true,
maxSize: '5m',
maxFiles: '10d',
format: winston.format.combine(
winston.format.printf((info) => {
const { timestamp, level, message, stack, ...meta } = info;
let logMessage = `${timestamp} [${level}]: ${message}${stack ? `\n${stack}` : ''}`;
if (Object.keys(meta).length) {
logMessage += ` ${JSON.stringify(meta, null, 2)}`;
}
return logMessage;
})
),
})
2025-08-30 19:04:35 -03:00
],
});
// Log no console (controlado por variavel de ambiente)
if (logToConsole) {
2025-08-30 19:04:35 -03:00
logger.add(new winston.transports.Console({
format: winston.format.combine(
winston.format.colorize(),
winston.format.printf((info) => {
const { timestamp, level, message, stack, ...meta } = info;
let logMessage = `${timestamp} [${level}]: ${message}${stack ? `\n${stack}` : ''}`;
if (Object.keys(meta).length) {
logMessage += ` ${JSON.stringify(meta, null, 2)}`;
}
return logMessage;
})
)
2025-08-30 19:04:35 -03:00
}));
}
// Funções utilitárias
const logError = (error, context = '') => {
if (error instanceof Error) {
logger.error(`${context} - ${error.message}`, { stack: error.stack });
} else {
logger.error(`${context} - ${error}`);
}
};
const logInfo = (message, meta = {}) => {
logger.info(message, meta);
};
const logWarning = (message, meta = {}) => {
logger.warn(message, meta);
2025-08-30 19:04:35 -03:00
};
const logDebug = (message, meta = {}) => {
logger.debug(message, meta);
};
// Log de sincronização específico. Fica em debug: por causa da margem de seguranca do
// watermark, esse log dispara toda vez que ha qualquer ticket "quente" no lote, mesmo sem
// mudanca real de campo - o sinal de mudanca de verdade e logado no chamador.
const logSync = (service, count, type) => {
logger.debug(`SYNC: ${service} - ${count} ${type} sincronizados`, {
service,
count,
type
});
2025-08-30 19:04:35 -03:00
};
module.exports = {
logger,
2025-08-30 19:04:35 -03:00
logError,
logInfo,
logWarning,
logDebug,
logSync,
};