🦓
[Express.js]WinstonとMorganでロギングを導入する
はじめに
ExpressとTypeScriptで作成されたAPIサーバーに、WinstonとMorganを使用してロギング管理を実装します。
WinstonはNode.js向けの多機能ロギングライブラリ、MorganはExpress専用のHTTPリクエストロギングミドルウェアです。
ロガーを導入することで、デバッグのスピードが大きく向上します。構造化されたログにより、エラーの発生場所や原因を素早く特定でき、問題解決までの時間を短縮できます。
アプリケーションの運用、開発、保守においてロガーを導入することがおすすめです。
console.log
の違い
ロガーと-
console.log
では単純な出力のみですが、ロガーでは情報の重要度に応じて適切なログレベル(error、warn、info、debug等)を設定できます。 -
console.log
はコンソールにのみ出力されますが、ロガーは様々な出力先(ファイル、外部サービス、データベースなど)に柔軟に出力できます。 -
console.log
は単純なテキスト出力ですが、ロガーは構造化された形式(JSON等)でログを出力でき、後の検索が容易です。 - 開発環境と本番環境で異なるログ設定を適用できます。
-
console.log
は同期的な処理となりますが、ロガーは非同期処理やバッファリングが可能で、アプリのパフォーマンスへの影響を最小限に抑えられます。
前提条件
- Node.js と npm がインストールされていること
- Express + TypeScriptで作成されたプロジェクト
tl:dr;
- 必要なパッケージをインストールする
- Winstonの設定ファイルを作成
- Morganの設定ファイルを作成
- アプリへの統合
- ログの使用例
- 通常のログ出力
- 非同期処理でのログ出力
- ログローテーションの追加
1. 必要なパッケージをインストールする
npm install winston morgan
npm instsll -D @types/morgan
2. Winstonの設定ファイルを作成
src/config/logger.ts
にWinstonの設定を作成します。
src/config/logger.ts
import winston from 'winston'
// ログレベル
const levels = {
error: 0,
warn: 1,
info: 2,
http: 3,
debug: 4,
};
// ログカラー
const colors = {
error: 'red',
warn: 'yellow',
info: 'green',
http: 'magenta',
debug: 'white',
};
// ログフォーマットの定義
const logFormat = winston.format.combine(
winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }),
winston.format.errors({ stack: true }),
winston.format.splat(),
winston.format.json()
)
// ロガーの作成
const logger = winston.createLogger({
level: process.env.LOG_LEVEL || 'info',
format: logFormat,
transports: [
// コンソールログ
new winston.transports.Console(),
]
})
// 開発環境の場合はコンソールにも出力
if (process.env.NODE_ENV !== 'production') {
logger.add(new winston.transports.Console({
format: winston.format.combine(
winston.format.colorize(),
winston.format.simple()
)
}))
}
export default logger
2. Morganの設定
src/middleware/morgan.ts
にMorganの設定を作成します。
src/middleware/morgan.ts
import morgan from 'morgan'
import logger from '../config/logger'
// Morganのストリームを定義
const stream = {
write: (message: string) => {
logger.info(message.trim())
}
}
// カスタムフォーマットの定義
const format = ':remote-addr - :remote-user [:date[clf]] ":method :url HTTP/:http-version" :status :res[content-length] ":referrer" ":user-agent" - :response-time ms'
// Morganミドルウェアの作成
const morganMiddleware = morgan(format, { stream })
export default morganMiddleware
ログのフォーマットは要件に合わせてカスタマイズすることができます。
デフォルトでは以下のように出力されます。
morgan(':method :url :status :res[content-length] - :response-time ms')
定義したMorganのフォーマット文字列は、HTTPリクエストのログを以下のような形式で出力します:
192.168.1.1 - john [10/Oct/2023:13:55:36 +0000] "GET /api/users HTTP/1.1" 200 2890 "http://example.com" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36" - 50.3 ms
-
:remote-addr
→192.168.1.1
(クライアントのIPアドレス) -
:remote-user
→john
(認証されたユーザー名、ない場合は-
) -
:date[clf]
→10/Oct/2023:13:55:36 +0000
(リクエスト時刻) -
:method
→GET
(HTTPメソッド) -
:url
→/api/users
(リクエストURL) -
:http-version
→1.1
(HTTPバージョン) -
:status
→200
(HTTPステータスコード) -
:res[content-length]
→2890
(レスポンスのサイズ[バイト]) -
:referrer
→http://example.com
(リファラー) -
:user-agent
→Mozilla/5.0...
(ユーザーエージェント) -
:response-time
→50.3
(レスポンス時間[ミリ秒])
3. アプリケーションへの統合
src/app.ts
でミドルウェアを統合します。
import express from 'express'
import morganMiddleware from './middleware/morgan'
import logger from './config/logger'
const app = express()
// Morganミドルウェアの適用
app.use(morganMiddleware)
export default app
ログの使用例
1. 通常のログ出力
// 情報ログ
logger.info('User logged in', { userId: user.id })
// エラーログ
logger.error('Database connection failed', { error: err })
2. 非同期処理でのログ出力
async function fetchUserData(userId: string): Promise<User>{
try {
logger.info('Fetching user data', { userId })
const user = await User.findById(userId)
logger.info('User data retrieved successfully', { userId })
return user
} catch (error) {
logger.error('Failed to fetch user data', {
userId,
error: error.message
})
throw error
}
}
ログローテーションの追加
ログローテーションとはログファイルを一定の基準(サイズ、日付など)で分割・管理する仕組みです。
これにより、古いログの自動アーカイブ/削除が実現できます。
winston-daily-rotate-file
をインストールして、ロガーに Transport を追加します。
npm install winston-daily-rotate-file
src/config/logger.ts
import winston from 'winston'
+ import DailyRotateFile from 'winston-daily-rotate-file';
// ロガーの作成
const logger = winston.createLogger({
level: process.env.LOG_LEVEL || 'info',
format: logFormat,
transports: [
// コンソールログ
new winston.transports.Console(),
+ // エラーログ
+ new DailyRotateFile({
+ filename: 'error-%DATE%.log',
+ level: 'error',
+ ...rotateFileConfig,
+ }),
+
+ // 全ログ
+ new DailyRotateFile({
+ filename: 'combined-%DATE%.log',
+ ...rotateFileConfig,
+ }),
]
})
export default logger
主な設定オプション
-
filename
: ログファイルの名前パターン -
datePattern
: 日付フォーマット -
maxSize
: ファイルの最大サイズ -
maxFiles
: 保持する最大ファイル数/期間 -
zippedArchive
: 古いログの圧縮有無 -
auditFile
: ログファイルの管理情報を保存
APIを叩いてログがログファイルに出力されたことを確認します。
また、logs/
を.gitignore
に追加することも忘れないようにしましょう。
まとめ
ExpressアプリにWinstonとMorganを導入してロギング管理を実装してみました。
誰かの参考になれば嬉しいです。
Discussion