Express.jsのログ出力設定(Morgan、Winston、log4js比較)
更新日:2025/03/15

Express.jsのロギングモジュール比較
機能 | Morgan | Winston | log4js |
---|---|---|---|
Express用ミドルウェア | ✓ (専用) | △ (要設定) | △ (要設定) |
カスタムログフォーマット | △ (限定的) | ✓ (高度) | ✓ (高度) |
複数出力先サポート | ✗ | ✓ | ✓ |
ログレベル対応 | ✗ | ✓ | ✓ |
ログローテーション | ✗ (要別モジュール) | △ (拡張必要) | ✓ (標準機能) |
JSONフォーマット | △ (限定的) | ✓ | ✓ |
非同期処理 | △ | ✓ | ✓ |
人気度 (npmダウンロード数) | ★★★★★ | ★★★★★ | ★★★★☆ |
メンテナンス状況 | ★★★☆☆ | ★★★★★ | ★★★★☆ |
実装の容易さ | ★★★★★ (もっとも簡単) | ★★★☆☆ (設定が複雑) | ★★★★☆ (標準的) |
拡張性 | ★★★☆☆ | ★★★★★ | ★★★★☆ |
プラグインエコシステム | ★★★☆☆ (限定的) | ★★★★★ (豊富) | ★★★★☆ (充実) |
学習曲線 | ★★★★★ (低い) | ★★★☆☆ (高い) | ★★★★☆ (中程度) |
それぞれの特徴と利用シーン
ロギングモジュール | 主な特徴 | 最適な利用シーン | 実装の簡単さ |
---|---|---|---|
Morgan | HTTPリクエストのロギングに特化 Express.jsに最適化された設計 プリセットされたログフォーマット シンプルな設定 | アクセスログのみが必要な場合 小〜中規模のアプリケーション 迅速な実装が必要な場合 他のロギングシステムとの併用 | ★★★★★app.use(morgan('combined')); のみで実装可能 |
Winston | 高度にカスタマイズ可能なロギング 複数のトランスポート(出力先) 豊富なプラグイン 非同期ロギング 強力なクエリ機能 | エンタープライズアプリケーション 複雑なロギング要件 カスタムログフォーマットが必要な場合 複数の出力先(ファイル、DB、APIなど) 高度なエラー処理とモニタリング | ★★★☆☆ 設定はより複雑だが、柔軟性が高い |
log4js | log4jに似た使い慣れたAPI 組み込みのログローテーション 階層的なロガー設定 複数の出力先サポート クラスタモードサポート | Java開発者に馴染みのある環境 ログローテーションが重要な場合 中〜大規模アプリケーション 階層的なログ構造が必要な場合 Expressと他のサーバーロジックの両方でロギング | ★★★★☆ Morganよりは複雑だが、Winstonより直感的 |
結論
- もっとも一般的: Winstonが現在のNode.jsエコシステムでもっとも広く採用され、活発にメンテナンスされています。
- もっともシンプル: Morganは実装が最も簡単で、特にHTTPリクエストのロギング専用です。
- バランス良好: log4jsは機能とシンプルさのバランスが良く、特にログローテーション機能が標準装備されている点が優れています。
推奨アプローチ
- 小規模プロジェクト: Morganのみ(シンプルなアクセスログ)
- 中規模プロジェクト: Morgan + log4js(アクセスログとアプリケーションログの分離)
- 大規模プロジェクト: 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`);
});

-
検索
(例) debug search etc.. -
カテゴリー
-
mixhostでのWordPress利用について
更新日:2024/04/02
299 view
-
scrollHint
更新日:2024/03/13
250 view
-
XML Sitemap Generator for Google不具合のダウングレード対応、代替プラグイン
更新日:2024/06/13
236 view
-
【SnowMonkey】納品までのフローまとめ
更新日:2025/02/15
163 view
-
ワードプレスでフォントを変えたいとき、プラグインを使えば初心者でも簡単
更新日:2025/02/16
144 view
-
【Googleサーチコンソール】検索画面で表示させたくない「Googleのインデックス削除」
更新日:2024/06/07
130 view
-
【ショートコード】編集画面で任意の場所にHTMLファイルを挿入
更新日:2024/01/26
122 view
-
キーワード検索で上位表示させる方法【SEO】
更新日:2023/10/28
120 view
-
tailwindcss使い方
更新日:2024/03/13
120 view
-
Recline: GitHub Copilotで動作するClaude 3.5 Sonnet搭載の開発支援ツール
更新日:2025/01/20
110 view
-
WordPressプラグイン「All-in-One WP Migration」のトラブル
更新日:2022/03/31
84 view
-
ワードプレスセキュリティー対策まとめ【2025年】「site guard wordpress」「BackWPup バージョン5でUI変更!?」
更新日:2025/02/25
76 view
-
SSHを使用してGitHubのリポジトリをクローン、複数の接続元で公開鍵をディレクトリで区別する方法
更新日:2025/01/13
47 view
-
VSCodeで開発効率を劇的に向上させる!Roo-Clineプラグイン完全ガイド【Gemini API】
更新日:2025/02/08
42 view
-
Express、FastAPIを使用し、二重fetch構成のメリット
更新日:2025/03/28
41 view
-
「JSONスキーマ」と「Few-shot Learning」で実現する次世代生成AIソフトウェア開発の可能性
更新日:2025/02/12
40 view
-
WordPressの無料画像素材のおすすめダウンロードサイト!
更新日:2022/02/22
35 view
-
リファクタリング【VSCode Javasctipt Python】
更新日:2025/03/09
35 view
-
形態素解析とは?初心者でもわかるツールの使い方と実践例
更新日:2025/02/08
33 view
-
【Next.js AWS】音声文字起こし&要約、分析アプリケーション(S3)(Transcribe)(Amazon Bedrock)
更新日:2025/02/13
30 view