Home » Начало работы с Morgan логгером в Node.js
Начало работы с Morgan логгером в Node.js

Начало работы с Morgan логгером в Node.js

Если ты настраиваешь серверное приложение на Node.js, то наверняка сталкивался с необходимостью логировать HTTP-запросы. Это не просто хорошая практика — это must-have для любого серьёзного проекта. Логи помогают отследить проблемы, анализировать трафик, мониторить производительность и просто понимать, что происходит с твоим приложением.

Morgan — это один из самых популярных и простых в использовании логгеров для Express.js. Он автоматически записывает информацию о каждом HTTP-запросе: метод, URL, статус код, время выполнения и многое другое. Настроить его можно буквально за пару минут, но возможности кастомизации впечатляют.

В этой статье разберём Morgan от А до Я: как он работает под капотом, как быстро его настроить, какие подводные камни могут встретиться и как выжать максимум из этого инструмента. Если ты уже арендовал VPS или думаешь о переходе на выделенный сервер, то правильное логирование станет твоим надёжным помощником в администрировании.

Как работает Morgan под капотом

Morgan работает как middleware для Express.js — он перехватывает каждый входящий запрос и исходящий ответ, собирает нужную информацию и форматирует её согласно заданному шаблону. Вся магия происходит в нескольких ключевых этапах:

  • Перехват запроса — Morgan регистрируется как middleware и получает доступ к объектам req и res
  • Сбор метрик — засекает время начала обработки, извлекает данные из заголовков
  • Мониторинг ответа — отслеживает момент завершения ответа для подсчёта времени выполнения
  • Форматирование и вывод — применяет заданный формат и выводит лог в нужное место

Интересный факт: Morgan использует токены (tokens) для форматирования логов. Каждый токен — это функция, которая извлекает определённую информацию из запроса или ответа. Можно создавать собственные токены для специфических нужд.

Быстрая установка и базовая настройка

Начнём с самого простого. Создаём новый проект или используем существующий:

mkdir morgan-example
cd morgan-example
npm init -y
npm install express morgan

Создаём базовый сервер с Morgan:

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

// Подключаем Morgan с форматом 'combined'
app.use(morgan('combined'));

app.get('/', (req, res) => {
  res.send('Hello World!');
});

app.get('/api/users', (req, res) => {
  res.json({ users: ['Alice', 'Bob'] });
});

app.listen(3000, () => {
  console.log('Server running on port 3000');
});

Запускаем сервер:

node app.js

Теперь каждый запрос будет автоматически логироваться. Попробуй открыть http://localhost:3000 в браузере — увидишь что-то вроде:

::1 - - [25/Dec/2023:10:30:15 +0000] "GET / HTTP/1.1" 200 12 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"

Встроенные форматы логирования

Morgan поставляется с несколькими предустановленными форматами. Вот самые полезные:

Формат Описание Пример вывода Рекомендации
combined Стандартный формат Apache 127.0.0.1 – – [25/Dec/2023:10:30:15 +0000] “GET / HTTP/1.1” 200 12 Для продакшена
common Упрощённый Apache формат 127.0.0.1 – – [25/Dec/2023:10:30:15 +0000] “GET / HTTP/1.1” 200 12 Базовое логирование
dev Цветной формат для разработки GET / 200 4.567 ms – 12 Только для разработки
short Короткий формат 127.0.0.1 – GET / HTTP/1.1 200 12 – 4.567 ms Для отладки
tiny Минимальный формат GET / 200 12 – 4.567 ms Для лёгкого логирования

Примеры использования:

// Для разработки - цветной и читаемый
app.use(morgan('dev'));

// Для продакшена - полная информация
app.use(morgan('combined'));

// Для высоконагруженных систем - минимум информации
app.use(morgan('tiny'));

Кастомные форматы и токены

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

// Создаём кастомный формат
app.use(morgan(':method :url :status :res[content-length] - :response-time ms'));

// Добавляем собственный токен
morgan.token('id', function getId(req) {
  return req.id || 'unknown';
});

// Токен для IP адреса (полезно за прокси)
morgan.token('real-ip', function(req) {
  return req.headers['x-forwarded-for'] || req.connection.remoteAddress;
});

// Токен для user agent
morgan.token('user-agent', function(req) {
  return req.get('User-Agent');
});

// Используем новые токены
app.use(morgan(':real-ip :id :method :url :status :response-time ms'));

Продвинутый пример с условным логированием:

// Логируем только ошибки
app.use(morgan('combined', {
  skip: function (req, res) { return res.statusCode < 400 }
}));

// Логируем только медленные запросы
app.use(morgan('combined', {
  skip: function (req, res) { 
    return res.responseTime < 1000; // меньше 1 секунды
  }
}));

Запись логов в файлы

В продакшене логи нужно сохранять в файлы. Вот несколько способов:

const fs = require('fs');
const path = require('path');

// Создаём директорию для логов
const logDir = path.join(__dirname, 'logs');
if (!fs.existsSync(logDir)) {
  fs.mkdirSync(logDir);
}

// Создаём поток для записи в файл
const accessLogStream = fs.createWriteStream(
  path.join(logDir, 'access.log'), 
  { flags: 'a' }
);

// Настраиваем Morgan для записи в файл
app.use(morgan('combined', { stream: accessLogStream }));

Для ротации логов можно использовать rotating-file-stream:

npm install rotating-file-stream
const rfs = require('rotating-file-stream');

// Создаём ротирующийся файл лога
const accessLogStream = rfs.createStream('access.log', {
  interval: '1d', // ротация каждый день
  path: path.join(__dirname, 'logs'),
  size: '10M', // или при достижении 10MB
  compress: 'gzip' // сжимаем старые файлы
});

app.use(morgan('combined', { stream: accessLogStream }));

Интеграция с другими системами логирования

Morgan отлично работает с Winston, Bunyan и другими логгерами:

const winston = require('winston');

// Настраиваем 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' })
  ]
});

// Создаём поток для Morgan
const stream = {
  write: function(message) {
    logger.info(message.trim());
  }
};

app.use(morgan('combined', { stream }));

Мониторинг производительности

Morgan можно использовать для сбора метрик производительности:

// Токен для размера запроса
morgan.token('req-size', function(req) {
  return req.get('content-length') || '0';
});

// Токен для размера ответа
morgan.token('res-size', function(req, res) {
  return res.get('content-length') || '0';
});

// Детальный формат для анализа производительности
const performanceFormat = ':date[iso] :real-ip :method :url :status :req-size :res-size :response-time ms';

app.use(morgan(performanceFormat, {
  stream: fs.createWriteStream('performance.log', { flags: 'a' })
}));

Безопасность и фильтрация чувствительных данных

Важно не логировать чувствительную информацию:

// Фильтруем чувствительные URL
app.use(morgan('combined', {
  skip: function(req, res) {
    // Не логируем запросы к админке
    return req.url.includes('/admin/');
  }
}));

// Кастомный токен с фильтрацией
morgan.token('safe-url', function(req) {
  let url = req.url;
  // Удаляем токены и пароли из URL
  url = url.replace(/([?&]token=)[^&]*/, '$1***');
  url = url.replace(/([?&]password=)[^&]*/, '$1***');
  return url;
});

app.use(morgan(':method :safe-url :status :response-time ms'));

Альтернативы Morgan

Хотя Morgan отличный выбор, есть и другие решения:

  • Winston — мощная система логирования с множеством транспортов
  • Bunyan — структурированное логирование в JSON формате
  • Pino — очень быстрый логгер с низкими накладными расходами
  • express-winston — интеграция Winston с Express

Сравнение производительности показывает, что Morgan один из самых быстрых HTTP-логгеров для Node.js, добавляя минимальные накладные расходы.

Продвинутые кейсы использования

Вот несколько нестандартных способов использования Morgan:

// Логирование в базу данных
const stream = {
  write: function(message) {
    // Парсим лог и сохраняем в MongoDB/PostgreSQL
    const logEntry = parseLogMessage(message);
    db.logs.insert(logEntry);
  }
};

// Отправка критических ошибок в Slack
app.use(morgan('combined', {
  skip: function(req, res) { return res.statusCode < 500; },
  stream: {
    write: function(message) {
      sendToSlack(`🚨 Server Error: ${message}`);
    }
  }
}));

// Геолокация по IP
morgan.token('country', function(req) {
  const ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress;
  return geoip.lookup(ip)?.country || 'Unknown';
});

app.use(morgan(':method :url :status :country :response-time ms'));

Автоматизация и DevOps

Morgan логи можно легко интегрировать в CI/CD пайплайны:

// Скрипт для анализа логов
const fs = require('fs');
const readline = require('readline');

async function analyzeAccessLogs() {
  const fileStream = fs.createReadStream('access.log');
  const rl = readline.createInterface({
    input: fileStream,
    crlfDelay: Infinity
  });

  let errorCount = 0;
  let totalRequests = 0;
  const slowRequests = [];

  for await (const line of rl) {
    totalRequests++;
    
    if (line.includes(' 5')) errorCount++;
    
    const responseTime = line.match(/(\d+\.\d+) ms/);
    if (responseTime && parseFloat(responseTime[1]) > 1000) {
      slowRequests.push(line);
    }
  }

  console.log(`Total requests: ${totalRequests}`);
  console.log(`Error rate: ${(errorCount/totalRequests*100).toFixed(2)}%`);
  console.log(`Slow requests: ${slowRequests.length}`);
}

Для Docker контейнеров можно настроить логирование в stdout:

// В продакшене логи идут в stdout для Docker
const isProduction = process.env.NODE_ENV === 'production';

if (isProduction) {
  app.use(morgan('combined')); // логи в stdout
} else {
  app.use(morgan('dev')); // цветные логи для разработки
}

Заключение и рекомендации

Morgan — это простой, но мощный инструмент для логирования HTTP-запросов в Node.js приложениях. Его главные преимущества: минимальные накладные расходы, гибкость настройки и отличная интеграция с Express.js.

Рекомендации по использованию:

  • Для разработки используй формат 'dev' — он цветной и читаемый
  • В продакшене выбирай между 'combined' для полной информации или 'tiny' для высоконагруженных систем
  • Обязательно настрой ротацию логов, чтобы они не съели всё место на диске
  • Фильтруй чувствительную информацию — токены, пароли, API ключи
  • Используй условное логирование для фокуса на важных событиях
  • Интегрируй с системами мониторинга и алертинга

Если планируешь развернуть приложение на VPS или выделенном сервере, правильно настроенное логирование станет незаменимым инструментом для мониторинга и отладки. Morgan поможет быстро обнаружить проблемы, проанализировать нагрузку и оптимизировать производительность.

Дополнительную информацию можно найти в официальной документации: https://github.com/expressjs/morgan


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

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

Leave a reply

Your email address will not be published. Required fields are marked