Логирование в JavaScript приложениях: лучшие практики и советы

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Логирование в JavaScript приложениях: лучшие практики

Логирование — это не просто запись событий в файл. В современных Node.js приложениях это мощный инструмент мониторинга, отладки и аудита. Без качественного логирования найти причину падения продакшн-сервера становится игрой в угадайку. В этой статье мы разберем лучшие практики логирования в JavaScript (Node.js), которые помогут вам строить надежные и поддерживаемые системы.

Почему стандартный console.log — это плохая практика

Многие начинающие разработчики используют console.log для отладки. Однако в продакшене это приводит к проблемам:

  • Отсутствие уровней: вы не можете разделить информационные сообщения и критические ошибки.
  • Нет структуры: вывод в консоль — это просто строка, которую сложно парсить.
  • Блокирующий ввод-вывод: синхронная запись может замедлить приложение.
  • Отсутствие ротации: файлы логов будут расти бесконечно.

Вместо этого используйте специализированные библиотеки, такие как winston или pino. Они предоставляют гибкую настройку транспортов (вывод в файл, консоль, внешние сервисы) и асинхронную запись.

Выбор библиотеки для логирования: winston vs pino

На рынке Node.js есть два явных лидера. Рассмотрим их особенности:

Winston

Самая популярная библиотека. Поддерживает множество транспортов (файл, HTTP, MongoDB, Elasticsearch) и кастомные форматы. Отлично подходит для монолитных приложений.

const winston = require('winston');

const logger = winston.createLogger({
    level: 'info',
    format: winston.format.json(),
    transports: [
        new winston.transports.File({ filename: 'error.log', level: 'error' }),
        new winston.transports.File({ filename: 'combined.log' }),
        new winston.transports.Console({ format: winston.format.simple() })
    ]
});

logger.info('Сервер запущен на порту 3000');
logger.error('Ошибка подключения к БД', { db: 'mongo', code: 500 });

Pino

Сверхбыстрая библиотека, которая в 5-10 раз быстрее winston. Идеальна для high-load систем и микросервисов. По умолчанию выводит JSON.

const pino = require('pino');

const logger = pino({
    level: process.env.LOG_LEVEL || 'info',
    transport: {
        target: 'pino/file',
        options: { destination: './app.log' }
    }
});

logger.info({ user: 'admin' }, 'Пользователь вошел в систему');
logger.error(new Error('Timeout'), 'Ошибка запроса');

Совет: для большинства проектов выбирайте winston из-за его гибкости. Если производительность критична — используйте pino.

Уровни логирования: как не утонуть в сообщениях

Правильное использование уровней — основа хорошего логирования. В Node.js принята следующая иерархия (от наименее к наиболее критичным):

  • trace / silly — максимально детальная отладочная информация (обычно отключена в продакшене).
  • debug — отладочные сообщения для разработчиков.
  • info — подтверждение нормальной работы (запросы, запуск сервисов).
  • warn — нештатная ситуация, но приложение продолжает работать (например, превышение лимита запросов).
  • error — ошибка, требующая внимания (падение запроса, сбой внешнего сервиса).
  • fatal — критическая ошибка, после которой приложение не может продолжать работу.

Настраивайте уровень логирования через переменные окружения:

const LOG_LEVEL = process.env.LOG_LEVEL || 'info';
const logger = winston.createLogger({ level: LOG_LEVEL });

В разработке ставьте debug, в продакшене — info или warn.

Структурированное логирование: JSON вместо строк

Строковые логи — это прошлый век. Современные системы (ELK, Grafana, DataDog) лучше всего работают с JSON-форматом. Преимущества:

  • Машиночитаемость — легко парсить и фильтровать.
  • Дополнительные поля — можно добавить ID запроса, пользователя, версию кода.
  • Поддержка корреляции — связывание логов в распределенных системах.

Пример структурированного лога:

{
    "level": "error",
    "message": "Ошибка валидации",
    "timestamp": "2025-03-15T10:30:00.000Z",
    "requestId": "abc-123",
    "userId": 42,
    "error": {
        "message": "Неверный email",
        "code": "VALIDATION_ERR"
    }
}

В winston это настраивается через формат:

const logger = winston.createLogger({
    format: winston.format.combine(
        winston.format.timestamp(),
        winston.format.json()
    )
});

Ротация логов и управление файлами

Если вы пишете логи в файлы, они будут расти бесконечно. Используйте ротацию, чтобы автоматически архивировать или удалять старые логи. Для winston есть пакет winston-daily-rotate-file:

const DailyRotateFile = require('winston-daily-rotate-file');

const transport = new DailyRotateFile({
    filename: 'logs/application-%DATE%.log',
    datePattern: 'YYYY-MM-DD',
    maxSize: '20m',
    maxFiles: '14d'
});

const logger = winston.createLogger({
    transports: [transport]
});

Этот код создает новый файл каждый день, удаляет файлы старше 14 дней и ограничивает размер каждого файла 20 МБ.

Лучшие практики: чек-лист

Соберите все рекомендации в один список для быстрой проверки:

  • Не логируйте секреты: пароли, токены, ключи API. Используйте фильтры или библиотеку fast-redact.
  • Добавляйте контекст: ID запроса, пользователя, версию приложения. Это упрощает поиск проблем.
  • Используйте асинхронную запись: чтобы не блоки

Блоги

Рекомендаций по книгам