背景
ECサイトなどを運用する場合、ログにユーザの識別IDが付与されていると調査時に行動を把握することが容易なため便利です。
そこで今回はNode.js(Express)で実現してみたいとおもいます。
実装
userId保持用の箱を準備
ログを出力する際、userIdを参照できるようにシングルトンなクラスを作成しておきます。
requestContext.js
class RequestContext {
init(userId) {
this.userId = userId
}
getUserId() {
return this.userId
}
}
export default new RequestContext()
Expressサーバ
下記の記述を、他のルーティングの上部に配置します。
express/app.js
import requestContext from 'path/to/requestContext'
app.use((req, res, next) => {
if (!req.session.userId) {
// sessionにuesrIdがない場合は、uuidを設定
req.session.userId = uuid.v4()
}
// 事前に作成したrequestContextに、userIdを設定
requestContext.init(req.session.userId)
next()
})
※ session管理には、express-session
を使っています。
※ next()
では、下部に処理を委ねます。
winston
今回loggerにはwinstonを用います。
例ではtimestampとログレベルも出力してます。
logger.js
import path from 'path'
import { createLogger, format, transports } from 'winston'
import config from 'config'
import requestContext from './requestContext'
const { combine, timestamp, printf } = format
const logDir = path.resolve('log')
const logFormatter = printf(
({ level, message, timestamp }) =>
`[${timestamp}] [${level.toUpperCase()}] [${requestContext.getUid()}] ${message}`
)
export const logger = createLogger({
level: config.get('logger.level.default') || 'info',
format: combine(timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }), logFormatter),
transports: [
new transports.Console(),
new transports.File({
filename: `${logDir}/application.log`
})
]
})
export const apiLogger = createLogger({
level: config.get('logger.level.api') || 'info',
format: combine(timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }), logFormatter),
transports: [
new transports.Console(),
new transports.File({
filename: `${logDir}/api.log`
})
]
})
検証
logger呼び出し例
import logger from 'path/to/logger'
logger.error('test!!')
出力例
application.log
[2019-10-30 11:08:18] [ERROR] [6ffd3f48-c967-43ac-88e3-d6886c82d3a5] test!!