Логирование в Node.js: от console.log к нормальным логам

Содержание

О проверке кода. Примеры не запускались в этой сессии (по договорённости — фокус на контенте, а не прогонах). Говорим прямо, а не ставим бейдж «проверено».

Логи — глаза приложения в продакшене: когда что-то ломается, только они говорят, что произошло. console.log для этого не годится. Разберём, как логировать по-взрослому в Node.js.

Почему console.log не для продакшена

console.log('пользователь вошёл');   // а какой? когда? насколько это важно?

console.log неплох для отладки на своей машине, но в продакшене у него серьёзные изъяны:

  • нет уровней важности — ошибка и рутинное событие в одной куче, важное тонет;
  • нет структуры — произвольный текст, по которому не поиск, ни фильтрация;
  • не пишет в файлы и системы сбора логов — только в консоль;
  • синхронный — под нагрузкой запись в консоль блокирует event loop, замедляя сервер.

Для продакшена берут библиотеку логирования. Но сначала — принципы, они важнее инструмента.

Уровни логирования

logger.error('платёж не прошёл', { orderId, error });  // критично, требует внимания
logger.warn('медленный ответ БД', { ms: 1500 });       // подозрительно
logger.info('пользователь вошёл', { userId });          // важное событие
logger.debug('промежуточное значение', { data });       // детали для отладки
Уровни логов: что куда

Всегда в проде

info и выше

  • error — сбой, нужно внимание
  • warn — подозрительное, но не сбой
  • info — ключевые события (вход, заказ)
  • Фильтр: показывать info и выше

Только при отладке

debug/trace

  • debug — детали для диагностики
  • trace — совсем подробно
  • В проде отключены — иначе шум и объём
  • Включают по NODE_ENV или флагу

Уровни задают важность и позволяют фильтровать. В продакшене показывают info и выше, а debug держат выключенным — иначе логи распухают и важное теряется. При диагностике проблемы debug включают через переменную окружения. Это ровно то, чего лишён плоский console.log.

Структурное логирование

Ключевая идея для серьёзного проекта — логи как данные, а не текст:

// ❌ текстовый лог — не поискать, не отфильтровать
console.log(`Пользователь ${userId} купил ${item} за ${price}`);

// ✅ структурный лог — JSON с полями
logger.info('покупка', { userId, item, price, requestId });
// {"level":"info","msg":"покупка","userId":42,"item":"книга","price":500,"requestId":"abc"}

Структурные логи — это JSON с полями, а не произвольная строка. Их преимущество раскрывается в системах сбора логов (Elasticsearch, Loki, облачные сервисы): можно искать «все события userId=42», фильтровать по requestId, строить графики по полям. С текстовым логом такое невозможно — только грубый поиск по строке. Поле requestId, общее для всех логов одного запроса, позволяет проследить весь путь запроса через сервис.

Библиотеки: pino и winston

// pino — самый быстрый, структурный JSON из коробки
const pino = require('pino');
const logger = pino();

logger.info({ userId: 42 }, 'пользователь вошёл');
logger.error({ err }, 'ошибка обработки');
  • pino — самая быстрая библиотека, пишет структурные JSON-логи с минимальными накладными расходами (важно: логирование не должно тормозить сервер). Оптимальный выбор для большинства новых проектов;
  • winston — гибче в настройке: несколько назначений вывода (файл, консоль, внешний сервис), форматы, ротация. Берут, когда нужна сложная маршрутизация логов.

Обе решают всё, чего не может console.log: уровни, структура, асинхронная запись, вывод куда угодно. Правило прежнее: инструмент под задачу — для старта достаточно pino с настройками по умолчанию.

Что НЕЛЬЗЯ логировать

// ❌ КАТАСТРОФА — секреты и персданные в логах
logger.info('вход', { email, password });        // пароль в логах!
logger.info('оплата', { cardNumber, cvv });      // данные карты!

// ✅ маскируем или исключаем
logger.info('вход', { email });                  // без пароля
logger.info('оплата', { cardLast4: '1234' });    // только последние цифры

Логи — не место для секретов. Они хранятся, просматриваются многими людьми и уходят в системы сбора, где живут долго. Пароль, токен, номер карты, персональные данные в логах — это утечка, иногда с юридическими последствиями (GDPR, 152-ФЗ). Чувствительные поля маскируют (последние 4 цифры) или исключают перед записью. pino умеет автоматически вырезать заданные поля (redaction).

Что стоит логировать

  • входящие запросы — метод, путь, статус ответа, время обработки, requestId;
  • ошибки — с полным стеком и контекстом (что за операция, какие данные);
  • ключевые бизнес-события — вход, регистрация, оплата, важное действие;
  • проблемы производительности — медленные запросы к БД, долгие внешние вызовы;
  • старт и остановку сервиса, подключение к БД.

Хороший лог отвечает на вопрос «что происходило перед сбоем» без необходимости воспроизводить проблему. Плохой — либо пуст в нужный момент, либо утонул в мусоре из-за отсутствия уровней.


Смежные темы: переменные окружения — уровень логов по NODE_ENV; обработка ошибок — что логировать при сбое; отладка — логи против отладчика. Полный список — в уроках Node.js.

Частые вопросы

Чем плох console.log для логирования?
Он не различает уровни важности, не структурирует данные, не умеет писать в файлы и системы сбора логов и синхронно тормозит под нагрузкой. Для разработки годится, для продакшена берут библиотеку логирования вроде pino или winston.
Что такое уровни логирования?
Градация важности сообщений: error, warn, info, debug и подобные. Они позволяют фильтровать вывод — в продакшене показывать только info и выше, а debug включать при отладке. Так важное не тонет в мелочах.
Что такое структурное логирование?
Запись логов в виде структурированных данных, обычно JSON, а не простого текста. Такие логи легко фильтровать, искать и агрегировать в системах сбора логов по полям вроде userId или requestId, чего не сделать с произвольным текстом.
Что нельзя записывать в логи?
Пароли, токены, номера карт, персональные данные. Логи хранятся и просматриваются многими, а также попадают в системы сбора, поэтому секреты в них — это утечка. Чувствительные поля маскируют или исключают перед записью.
Какую библиотеку логирования выбрать для Node?
pino — самая быстрая, пишет структурные JSON-логи с минимальными накладными расходами, популярна в продакшене. winston — гибче по настройке и назначениям вывода. Для большинства новых проектов pino оптимален по скорости и простоте.