Як реалізувати логування в Express.js (Morgan, Winston)?
Логування в Express.js
Правильне логування є важливим для налагодження, моніторингу та аудиту виробничих застосунків. Express використовує дві основні бібліотеки для логування: Morgan для логування HTTP запитів та Winston для логування на рівні застосунку.
Morgan — Логгер HTTP Запитів
Morgan логує кожен вхідний HTTP запит:
bash
npm install morganjs
const morgan = require('morgan');
// Попередньо визначені формати
app.use(morgan('dev')); // Кольоровий вивід для розробки
app.use(morgan('combined')); // Apache-стиль для виробництва
app.use(morgan('tiny')); // Мінімальний вивідПриклади форматів:
// dev формат:
GET /api/users 200 12.345 ms - 250
// combined формат:
::1 - - [01/Mar/2026:10:00:00 +0000] "GET /api/users HTTP/1.1" 200 250
// tiny формат:
GET /api/users 200 250 - 12.345 msКористувацький формат:
js
morgan.token('body', (req) => JSON.stringify(req.body));
app.use(morgan(':method :url :status :response-time ms - :body'));Логування у файл:
js
const fs = require('fs');
const path = require('path');
const accessLogStream = fs.createWriteStream(
path.join(__dirname, 'access.log'),
{ flags: 'a' }
);
app.use(morgan('combined', { stream: accessLogStream }));Winston — Логгер Застосунку
Winston є універсальною бібліотекою для логування з кількома транспортами:
bash
npm install winstonjs
const winston = require('winston');
const logger = winston.createLogger({
level: 'info',
format: winston.format.combine(
winston.format.timestamp(),
winston.format.errors({ stack: true }),
winston.format.json()
),
defaultMeta: { service: 'my-api' },
transports: [
new winston.transports.File({ filename: 'logs/error.log', level: 'error' }),
new winston.transports.File({ filename: 'logs/combined.log' })
]
});
// Додати консоль у розробці
if (process.env.NODE_ENV !== 'production') {
logger.add(new winston.transports.Console({
format: winston.format.combine(
winston.format.colorize(),
winston.format.simple()
)
}));
}Використання:
js
logger.info('Сервер запущено', { port: 3000 });
logger.warn('Виявлено повільний запит', { query: 'SELECT...', duration: 5000 });
logger.error('Не вдалося підключитися до бази даних', { error: err.message });Комбінування Morgan + Winston
js
const morganStream = {
write: (message) => logger.http(message.trim())
};
app.use(morgan('combined', { stream: morganStream }));Рівні Логування
| Рівень | Пріоритет | Використання |
|---|---|---|
error | 0 | Помилки застосунку |
warn | 1 | Депрекації, повільні запити |
info | 2 | Ключові події (запуск, зупинка) |
http | 3 | HTTP запити |
debug | 4 | Детальне налагодження |
verbose | 5 | Ще більше деталей |
silly | 6 | Все |
Найкращі Практики
| Практика | Опис |
|---|---|
| Структуроване логування | Використовуйте формат JSON для машинного парсингу |
| ID запиту | Додайте унікальний ID для відстеження запитів у логах |
| Не логувати секрети | Фільтруйте паролі, токени, кредитні картки |
| Ротація логів | Використовуйте winston-daily-rotate-file |
| Централізоване логування | Відправляйте в ELK Stack, Datadog або CloudWatch |
| Різні рівні для середовища | debug у розробці, info у виробництві |
js
// Middleware для ID запиту
const { v4: uuid } = require('uuid');
app.use((req, res, next) => {
req.requestId = req.headers['x-request-id'] || uuid();
res.setHeader('x-request-id', req.requestId);
next();
});Порада для виробництва: Завжди використовуйте структуроване JSON логування. Прикріплюйте ID запитів для відстеження. Відправляйте логи до централізованого сервісу. Ніколи не логуйте чутливі дані, такі як паролі, токени або особисту інформацію.
Коротка відповідь
Для співбесідиPremium
Коротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.