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

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

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

Начать курс

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

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

1. Почему не стоит полагаться на console.log?

Многие начинающие разработчики используют console.log для всего. Это удобно на этапе разработки, но в production-среде такой подход приводит к проблемам:

  • Нет уровней логирования — вы не можете отфильтровать ошибки от информационных сообщений.
  • Сложно управлять выводом — нельзя отключить логи для определенных модулей.
  • Плохая производительность — сериализация объектов в console.log может быть затратной.
  • Отсутствие структуры — логи не имеют единого формата (JSON, время, уровень).

Вместо этого используйте специализированные библиотеки. Вот простой, но правильный пример с использованием Winston:

// logger.js
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' }),
  ],
});

if (process.env.NODE_ENV !== 'production') {
  logger.add(new winston.transports.Console({
    format: winston.format.simple(),
  }));
}

module.exports = logger;

2. Уровни логирования: когда что использовать

Стандартные уровни логирования (по возрастанию серьезности): debug, info, warn, error. Важно понимать, когда какой уровень применять:

  • debug — детальная информация для разработчиков (значения переменных, состояние системы). Отключается в production.
  • info — обычные события работы приложения (запрос обработан, пользователь зарегистрирован).
  • warn — потенциально опасные ситуации (низкий запас памяти, устаревший API).
  • error — ошибки, которые требуют вмешательства (исключения, сбои БД).

Пример правильного использования с библиотекой Pino (самая быстрая для Node.js):

const pino = require('pino');

const logger = pino({
  level: process.env.LOG_LEVEL || 'info',
  transport: {
    target: 'pino-pretty',
    options: { colorize: true }
  }
});

// Использование
logger.info({ userId: 123 }, 'Пользователь вошел в систему');
logger.error(new Error('Ошибка подключения к БД'), 'Критическая ошибка');
logger.debug('Значение переменной x = 42'); // не выведется, если level = 'info'

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

Вместо текстовых строк используйте структурированные логи (обычно JSON). Это позволяет:

  • Легко парсить логи инструментами (ELK, Graylog).
  • Добавлять контекст (ID запроса, пользователь, версия).
  • Фильтровать и агрегировать данные.

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

const logger = require('./logger');

app.use((req, res, next) => {
  req.requestId = uuidv4();
  next();
});

app.get('/api/users', async (req, res) => {
  logger.info({
    requestId: req.requestId,
    method: req.method,
    url: req.originalUrl,
    ip: req.ip
  }, 'Входящий запрос');

  try {
    const users = await getUsers();
    logger.info({ requestId: req.requestId, count: users.length }, 'Пользователи получены');
    res.json(users);
  } catch (err) {
    logger.error({
      requestId: req.requestId,
      error: err.message,
      stack: err.stack
    }, 'Ошибка получения пользователей');
    res.status(500).send('Internal Server Error');
  }
});

4. Лучшие практики для production

При развертывании приложения в production соблюдайте следующие правила:

  • Не логируйте пароли и секреты — используйте санитайзеры для удаления чувствительных данных.
  • Ротация логов — используйте winston-daily-rotate-file или средства системы (logrotate).
  • Асинхронное логирование — библиотеки вроде Pino работают асинхронно, не блокируя event loop.
  • Централизованный сбор — отправляйте логи в ELK (Elasticsearch, Logstash, Kibana) или Sentry для ошибок.
  • Логирование HTTP-запросов — используйте morgan для Express:
const morgan = require('morgan');
const express = require('express');
const app = express();

// Формат combined для production
app.use(morgan('combined', {
  skip: (req, res) => res.statusCode < 400 // логировать только ошибки
}));

5. Пример: настройка Winston для Express

Соберем все вместе — полный пример настройки логирования для Express-приложения с Winston:

const winston = require('winston');
const express = require('express');
const app = express();

// 1. Создаем логгер
const logger = winston.createLogger({
  level: 'info',
  format: winston.format.combine(
    winston.format.timestamp(),
    winston.format.json()
  ),
  transports: [
    new winston.transports.File({ filename: 'error.log', level: 'error' }),
    new winston.transports.File({ filename: 'combined.log' }),
  ],
});

// 2. Добавляем форматированный вывод в консоль для разработки
if (process.env.NODE_ENV !== 'production') {
  logger.add(new winston.transports.Console({
    format: winston.format.combine(
      winston.format.colorize(),
      winston.format.simple()
    )
  }));
}

// 3. Middleware для логирования запросов
app.use((req, res, next) => {
  const start = Date.now();
  res.on('finish', () => {
    logger.info({
      method: req.method,
      url: req.originalUrl,
      status: res.statusCode,
      duration: Date.now() - start,
    });
  });
  next();
});

// 4. Пример обработчика
app.get('/error', (req                

Блоги

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