Winston для JavaScript (Node.js): полное руководство с примерами

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

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

Начать курс

Что такое Winston и зачем он нужен?

Winston — это мощная и гибкая библиотека для логирования в среде Node.js. Она была создана Charlie Robbins и является одной из самых популярных библиотек для логирования в экосистеме JavaScript. Winston позволяет разработчикам записывать сообщения с различными уровнями важности (info, warn, error, debug и т.д.), настраивать форматы вывода (JSON, простой текст, с метками времени), а также направлять логи в разные места (консоль, файлы, базы данных, внешние сервисы).

Зачем нужен Winston? В любом серьёзном приложении логирование — это не роскошь, а необходимость. Оно помогает:

  • Отлаживать приложение: Логи позволяют понять, что происходило в системе в момент ошибки.
  • Мониторить производительность: Можно записывать время выполнения запросов и выявлять узкие места.
  • Анализировать поведение пользователей: Логи помогают понять, как пользователи взаимодействуют с приложением.
  • Сохранять историю: Все события можно хранить в файлах или базах данных для последующего анализа.
  • Обеспечивать безопасность: Логи могут фиксировать подозрительные действия и попытки взлома.

Winston решает эти задачи элегантно и эффективно, предоставляя единый интерфейс для работы с логами.

Установка Winston

Установка Winston осуществляется через менеджер пакетов npm. Откройте терминал в корневой папке вашего проекта и выполните команду:

npm install winston

Если вы используете yarn:

yarn add winston

После установки вы можете импортировать Winston в свой проект:

const winston = require('winston');

Для проектов, использующих ES-модули (type: "module" в package.json):

import winston from 'winston';

Быстрый старт с примером кода

Давайте создадим простой логгер, который выводит сообщения в консоль и в файл:

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

// Создаём логгер с двумя транспортами: консоль и файл
const logger = winston.createLogger({
    level: 'info', // Минимальный уровень логирования
    format: winston.format.json(), // Формат вывода — JSON
    transports: [
        new winston.transports.Console(), // Вывод в консоль
        new winston.transports.File({ filename: 'combined.log' }) // Запись в файл
    ]
});

// Используем логгер
logger.info('Приложение запущено');
logger.warn('Предупреждение: низкий уровень памяти');
logger.error('Ошибка подключения к базе данных');

console.log('Логи записаны. Проверьте файл combined.log');

После запуска этого кода вы увидите логи в консоли, а также найдёте файл combined.log в корневой папке проекта.

Основные методы и функции Winston

Winston предоставляет богатый API. Рассмотрим 10 ключевых методов и функций с примерами.

1. winston.createLogger(options)

Что делает: Создаёт новый экземпляр логгера с заданной конфигурацией. Это основной способ создания логгера.

Параметры:

  • options.level (string): Минимальный уровень логирования (например, 'info', 'debug', 'error').
  • options.format (Format): Формат вывода логов (например, winston.format.json(), winston.format.simple()).
  • options.transports (Transport[]): Массив транспортов, определяющих, куда направлять логи.
  • options.defaultMeta (Object): Метаданные, которые будут добавляться к каждому сообщению.
  • options.exitOnError (boolean): Если true, процесс завершится при ошибке логирования (по умолчанию true).

Пример:

const logger = winston.createLogger({
    level: 'debug',
    format: winston.format.combine(
        winston.format.timestamp(),
        winston.format.json()
    ),
    defaultMeta: { service: 'user-service' },
    transports: [
        new winston.transports.Console(),
        new winston.transports.File({ filename: 'error.log', level: 'error' })
    ]
});

2. logger.log(level, message, meta)

Что делает: Универсальный метод для записи лога с указанным уровнем.

Параметры:

  • level (string): Уровень логирования ('error', 'warn', 'info', 'verbose', 'debug', 'silly').
  • message (string): Текст сообщения.
  • meta (Object, optional): Дополнительные метаданные (объект).

Пример:

logger.log('info', 'Запрос обработан', { userId: 123, duration: 45 });

3. logger.info(message, meta)

Что делает: Записывает лог с уровнем 'info'. Используется для стандартных информационных сообщений.

Параметры:

  • message (string): Текст сообщения.
  • meta (Object, optional): Дополнительные метаданные.

Пример:

logger.info('Сервер запущен на порту 3000');

4. logger.error(message, meta)

Что делает: Записывает лог с уровнем 'error'. Используется для критических ошибок.

Параметры:

  • message (string): Текст сообщения об ошибке.
  • meta (Object, optional): Дополнительные метаданные (часто передают объект ошибки).

Пример:

try {
    // какой-то код
} catch (err) {
    logger.error('Ошибка при обработке запроса', { error: err.message, stack: err.stack });
}

5. logger.warn(message, meta)

Что делает: Записывает лог с уровнем 'warn'. Используется для предупреждений.

Параметры:

  • message (string): Текст предупреждения.
  • meta (Object, optional): Дополнительные метаданные.

Пример:

logger.warn('Дисковое пространство заканчивается', { freeSpace: '500MB' });

6. logger.debug(message, meta)

Что делает: Записывает лог с уровнем 'debug'. Используется для отладочной информации, которая обычно не нужна в продакшене.

Параметры:

  • message (string): Отладочное сообщение.
  • meta (Object, optional): Дополнительные метаданные.

Пример:

logger.debug('Параметры запроса: %j', req.query);

7. logger.child(options)

Что делает: Создаёт дочерний логгер, который наследует конфигурацию родительского, но может добавлять свои метаданные или переопределять настройки.

Параметры:

  • options (Object): Объект с настройками для дочернего логгера (например, defaultMeta).

Пример:

const childLogger = logger.child({ requestId: 'abc-123' });
childLogger.info('Обработка запроса начата');
// В логе будет поле requestId: 'abc-123'

8. winston.format.combine(formats)

Что делает: Комбинирует несколько форматов в один. Позволяет применять несколько преобразований к сообщению.

Параметры:

  • formats (Format[]): Массив форматов, которые нужно применить последовательно.

Пример:

const myFormat = winston.format.combine(
    winston.format.timestamp(),
    winston.format.colorize(),
    winston.format.printf(({ timestamp, level, message, ...meta }) => {
        return `${timestamp} [${level}]: ${message} ${Object.keys(meta).length ? JSON.stringify(meta) : ''}`;
    })
);

9. winston.transports.File(options)

Что делает: Создаёт транспорт для записи логов в файл. Это один из самых часто используемых транспортов.

Параметры:

  • options.filename (string): Имя файла для записи логов.
  • options.level (string, optional): Уровень логирования для этого транспорта.
  • options.maxsize (number, optional): Максимальный размер файла в байтах. При превышении создаётся новый файл.
  • options.maxFiles (number, optional): Максимальное количество файлов для ротации.
  • options.tailable (boolean, optional): Если true, при ротации файлы будут переименовываться, а не удаляться.

Пример:

const fileTransport = new winston.transports.File({
    filename: 'logs/app.log',
    maxsize: 5242880, // 5MB
    maxFiles: 5,
    tailable: true
});

10. winston.addColors(colors)

Что делает: Добавляет пользовательские цвета для уровней логирования при использовании формата colorize.

Параметры:

  • colors (Object): Объект, где ключи — уровни логирования, а значения — цвета (строки).

Пример:

winston.addColors({
    error: 'red',
    warn: 'yellow',
    info: 'green',
    debug: 'blue'
});

const logger = winston.createLogger({
    format: winston.format.combine(
        winston.format.colorize(),
        winston.format.simple()
    ),
    transports: [new winston.transports.Console()]
});

Реальный практический пример использования

Давайте создадим полноценный логгер для веб-приложения на Express.js. Он будет записывать все HTTP-запросы, ошибки и предупреждения.

// logger.js
const winston = require('winston');
const path = require('path');

// Настраиваем форматы
const consoleFormat = winston.format.combine(
    winston.format.colorize(),
    winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }),
    winston.format.printf(({ timestamp, level, message, ...meta }) => {
        return `${timestamp} [${level}]: ${message} ${Object.keys(meta).length ? JSON.stringify(meta) : ''}`;
    })
);

const fileFormat = winston.format.combine(
    winston.format.timestamp(),
    winston.format.json()
);

// Создаём логгер
const logger = winston.createLogger({
    level: process.env.LOG_LEVEL || 'info',
    transports: [
        new winston.transports.Console({ format: consoleFormat }),
        new winston.transports.File({
            filename: path.join(__dirname, 'logs', 'error.log'),
            level: 'error',
            format: fileFormat,
            maxsize: 5242880,
            maxFiles: 5
        }),
        new winston.transports.File({
            filename: path.join(__dirname, 'logs', 'combined.log'),
            format: fileFormat,
            maxsize: 5242880,
            maxFiles: 10
        })
    ],
    exceptionHandlers: [
        new winston                    

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