Express.jsのログ出力設定(Morgan、Winston、log4js比較)

更新日:2025/03/15

Express.jsのログ出力システム 基本的なMorganログシステム クライアント リクエスト Express サーバー Morgan access.log ログ書き込み Winstonを使った高度なログシステム クライアント リクエスト Express サーバー Morgan Winston error.log combined.log コンソール Winstonを使うと、ログレベル、出力形式、複数の出力先をカスタマイズできます
Expressログのローテーションと環境別設定 ログローテーションシステム Express + Winston winston-daily-rotate-file app-2025- 03-13.log app-2025- 03-14.log app-2025- 03-15.log 日付ごとに新しいログファイルを作成 古いログは自動的に管理・削除 環境別ログ設定 config.js development: debug development: debug 開発環境 詳細なログ development- combined.log 本番環境 重要なログのみ production- combined.log 環境変数(NODE_ENV)に基づいて 最適なログレベルと出力先を自動設定

Express.jsのロギングモジュール比較

機能MorganWinstonlog4js
Express用ミドルウェア✓ (専用)△ (要設定)△ (要設定)
カスタムログフォーマット△ (限定的)✓ (高度)✓ (高度)
複数出力先サポート
ログレベル対応
ログローテーション✗ (要別モジュール)△ (拡張必要)✓ (標準機能)
JSONフォーマット△ (限定的)
非同期処理
人気度 (npmダウンロード数)★★★★★★★★★★★★★★☆
メンテナンス状況★★★☆☆★★★★★★★★★☆
実装の容易さ★★★★★
(もっとも簡単)
★★★☆☆
(設定が複雑)
★★★★☆
(標準的)
拡張性★★★☆☆★★★★★★★★★☆
プラグインエコシステム★★★☆☆
(限定的)
★★★★★
(豊富)
★★★★☆
(充実)
学習曲線★★★★★
(低い)
★★★☆☆
(高い)
★★★★☆
(中程度)

それぞれの特徴と利用シーン

ロギングモジュール主な特徴最適な利用シーン実装の簡単さ
MorganHTTPリクエストのロギングに特化 Express.jsに最適化された設計 プリセットされたログフォーマット シンプルな設定アクセスログのみが必要な場合 小〜中規模のアプリケーション 迅速な実装が必要な場合 他のロギングシステムとの併用★★★★★
app.use(morgan('combined'));
のみで実装可能
Winston高度にカスタマイズ可能なロギング 複数のトランスポート(出力先) 豊富なプラグイン 非同期ロギング 強力なクエリ機能エンタープライズアプリケーション 複雑なロギング要件 カスタムログフォーマットが必要な場合 複数の出力先(ファイル、DB、APIなど) 高度なエラー処理とモニタリング★★★☆☆
設定はより複雑だが、柔軟性が高い
log4jslog4jに似た使い慣れたAPI 組み込みのログローテーション 階層的なロガー設定 複数の出力先サポート クラスタモードサポートJava開発者に馴染みのある環境 ログローテーションが重要な場合 中〜大規模アプリケーション 階層的なログ構造が必要な場合 Expressと他のサーバーロジックの両方でロギング★★★★☆
Morganよりは複雑だが、Winstonより直感的

結論

  • もっとも一般的: Winstonが現在のNode.jsエコシステムでもっとも広く採用され、活発にメンテナンスされています。
  • もっともシンプル: Morganは実装が最も簡単で、特にHTTPリクエストのロギング専用です。
  • バランス良好: log4jsは機能とシンプルさのバランスが良く、特にログローテーション機能が標準装備されている点が優れています。

推奨アプローチ

  1. 小規模プロジェクト: Morganのみ(シンプルなアクセスログ)
  2. 中規模プロジェクト: Morgan + log4js(アクセスログとアプリケーションログの分離)
  3. 大規模プロジェクト: Morgan + Winston(最大の拡張性と柔軟性)

Morgan実装手順

必要なパッケージのインストール

npm install express morgan winston

基本的なMorganを使ったログ出力

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

const app = express();

// ログディレクトリの作成
const logDirectory = path.join(__dirname, 'logs');
fs.existsSync(logDirectory) || fs.mkdirSync(logDirectory);

// ログファイルストリームの作成
const accessLogStream = fs.createWriteStream(
  path.join(logDirectory, 'access.log'), 
  { flags: 'a' }
);

// morganミドルウェアの設定
app.use(morgan('combined', { stream: accessLogStream }));

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

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

log4jsの導入手順

log4jsをプロジェクトにインストールします

npm install log4js

Winstonを使った高度なログ管理

const express = require('express');
const morgan = require('morgan');
const winston = require('winston');
const { format, transports } = winston;

const app = express();

// Winstonロガーの設定
const logger = winston.createLogger({
  level: 'info',
  format: format.combine(
    format.timestamp({
      format: 'YYYY-MM-DD HH:mm:ss'
    }),
    format.errors({ stack: true }),
    format.splat(),
    format.json()
  ),
  defaultMeta: { service: 'express-app' },
  transports: [
    new transports.File({ filename: 'logs/error.log', level: 'error' }),
    new transports.File({ filename: 'logs/combined.log' })
  ]
});

// 開発環境ではコンソールにも出力
if (process.env.NODE_ENV !== 'production') {
  logger.add(new transports.Console({
    format: format.combine(
      format.colorize(),
      format.simple()
    )
  }));
}

// Morganの出力をWinstonに流す
app.use(morgan('combined', {
  stream: {
    write: (message) => logger.info(message.trim())
  }
}));

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

// エラーログの例
app.get('/error', (req, res, next) => {
  try {
    throw new Error('Something went wrong');
  } catch (error) {
    logger.error(`Error occurred: ${error.message}`, { 
      stack: error.stack, 
      url: req.originalUrl 
    });
    res.status(500).send('Error');
  }
});

app.listen(3000, () => {
  logger.info('Server is running on port 3000');
});

ログローテーション機能の追加

// まず、パッケージをインストール
// npm install winston-daily-rotate-file

const express = require('express');
const morgan = require('morgan');
const winston = require('winston');
const { format, transports } = winston;
require('winston-daily-rotate-file');

const app = express();

// ログローテーション設定
const fileRotateTransport = new winston.transports.DailyRotateFile({
  filename: 'logs/application-%DATE%.log',
  datePattern: 'YYYY-MM-DD',
  maxSize: '20m',
  maxFiles: '14d',
  format: format.combine(
    format.timestamp(),
    format.json()
  )
});

// Winstonロガーの設定
const logger = winston.createLogger({
  level: 'info',
  format: format.combine(
    format.timestamp({
      format: 'YYYY-MM-DD HH:mm:ss'
    }),
    format.errors({ stack: true }),
    format.splat(),
    format.json()
  ),
  defaultMeta: { service: 'express-app' },
  transports: [
    new transports.File({ filename: 'logs/error.log', level: 'error' }),
    fileRotateTransport
  ]
});

// 開発環境ではコンソールにも出力
if (process.env.NODE_ENV !== 'production') {
  logger.add(new transports.Console({
    format: format.combine(
      format.colorize(),
      format.simple()
    )
  }));
}

// Morganの出力をWinstonに流す
app.use(morgan('combined', {
  stream: {
    write: (message) => logger.info(message.trim())
  }
}));

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

app.listen(3000, () => {
  logger.info('Server is running on port 3000');
});

環境ごとにログレベルを変更する設定

// config.js
module.exports = {
  logging: {
    development: {
      level: 'debug',
      console: true
    },
    production: {
      level: 'info',
      console: false
    }
  }
};

// app.js
const express = require('express');
const morgan = require('morgan');
const winston = require('winston');
const { format, transports } = winston;
const config = require('./config');

const app = express();
const environment = process.env.NODE_ENV || 'development';
const logConfig = config.logging[environment];

// Winstonロガーの設定
const logger = winston.createLogger({
  level: logConfig.level,
  format: format.combine(
    format.timestamp({
      format: 'YYYY-MM-DD HH:mm:ss'
    }),
    format.errors({ stack: true }),
    format.splat(),
    format.json()
  ),
  defaultMeta: { service: 'express-app', environment },
  transports: [
    new transports.File({ filename: `logs/${environment}-error.log`, level: 'error' }),
    new transports.File({ filename: `logs/${environment}-combined.log` })
  ]
});

// 開発環境ではコンソールにも出力
if (logConfig.console) {
  logger.add(new transports.Console({
    format: format.combine(
      format.colorize(),
      format.simple()
    )
  }));
}

// 異なるログ形式の設定
const morganFormat = environment === 'production' ? 'combined' : 'dev';

// Morganの出力をWinstonに流す
app.use(morgan(morganFormat, {
  stream: {
    write: (message) => logger.info(message.trim())
  }
}));

app.get('/', (req, res) => {
  // デバッグログの例
  logger.debug('デバッグ情報:ホームページにアクセスがありました');
  logger.info('ホームページにアクセスがありました');
  res.send('Hello World!');
});

app.listen(3000, () => {
  logger.info(`Server is running on port 3000 in ${environment} mode`);
});
人気記事ランキング
話題のキーワードから探す