nakama/backend/middleware/logger.js

106 lines
3.3 KiB
JavaScript
Raw Normal View History

2025-11-04 21:51:05 +00:00
const fs = require('fs');
const path = require('path');
// Создать директорию для логов если её нет
const logsDir = path.join(__dirname, '../logs');
if (!fs.existsSync(logsDir)) {
fs.mkdirSync(logsDir, { recursive: true });
}
2025-11-10 20:13:22 +00:00
const getDatePrefix = () => {
return new Date().toISOString().slice(0, 10);
};
const appendLog = (fileName, message) => {
const filePath = path.join(logsDir, fileName);
fs.appendFile(filePath, `${message}\n`, (err) => {
if (err) {
console.error('Ошибка записи в лог файл:', err);
}
});
};
2025-11-04 21:51:05 +00:00
// Функция для логирования
const log = (level, message, data = {}) => {
const timestamp = new Date().toISOString();
const logMessage = `[${timestamp}] [${level.toUpperCase()}] ${message}`;
2025-11-10 20:13:22 +00:00
const serializedData = Object.keys(data).length ? ` ${JSON.stringify(data)}` : '';
const fullMessage = `${logMessage}${serializedData}`;
2025-11-04 21:51:05 +00:00
// Логирование в консоль
if (level === 'error') {
console.error(logMessage, data);
} else if (level === 'warn') {
console.warn(logMessage, data);
} else {
console.log(logMessage, data);
}
2025-11-10 20:13:22 +00:00
const fileName = `${level}-${getDatePrefix()}.log`;
appendLog(fileName, fullMessage);
2025-11-04 21:51:05 +00:00
};
// Middleware для логирования запросов
const requestLogger = (req, res, next) => {
const start = Date.now();
// Логировать после завершения запроса
res.on('finish', () => {
const duration = Date.now() - start;
const logData = {
method: req.method,
path: req.path,
status: res.statusCode,
duration: `${duration}ms`,
ip: req.ip,
userAgent: req.get('user-agent'),
userId: req.user?.id || 'anonymous'
};
2025-11-04 22:41:35 +00:00
// Пропустить логирование для публичных роутов (health, корневой роут)
if (req.path === '/health' || req.path === '/') {
// Логировать только ошибки для публичных роутов
if (res.statusCode >= 400) {
log('error', 'Request failed', logData);
}
return; // Не логировать успешные запросы к публичным роутам
}
2025-11-04 21:51:05 +00:00
if (res.statusCode >= 400) {
log('error', 'Request failed', logData);
2025-11-04 22:41:35 +00:00
} else if (res.statusCode >= 300 && res.statusCode !== 304) {
// 304 - это нормально (кеш), не логируем
2025-11-04 21:51:05 +00:00
log('warn', 'Request redirect', logData);
} else {
log('info', 'Request completed', logData);
}
});
next();
};
// Логирование подозрительной активности
const logSecurityEvent = (type, req, details = {}) => {
const securityData = {
type,
ip: req.ip,
userAgent: req.get('user-agent'),
path: req.path,
method: req.method,
userId: req.user?.id || 'anonymous',
...details
};
log('warn', 'Security event', securityData);
// В production можно отправить уведомление
2025-11-10 20:13:22 +00:00
const securityMessage = `[${new Date().toISOString()}] [SECURITY] ${type}: ${JSON.stringify(securityData)}`;
appendLog(`security-${getDatePrefix()}.log`, securityMessage);
2025-11-04 21:51:05 +00:00
};
module.exports = {
log,
requestLogger,
logSecurityEvent
};