winston 日誌模組
在使用 nodejs winston 模組中,加上相關的兩個模組,事倍功半。
- express-winston
- winston-daily-rotate-file
express-winston
是 express-winston 的 winston 的增加版, 是作為 express 的中介軟體來列印日誌,不僅有請求頭資訊,並且有響應時間。
作為中介軟體, 為什麼會有響應時間呢? 因為 express-winston 改寫了 express 的 res.end 辦法, 是請求結束後再打的日誌。
程式碼片段
var end = res.end;
res.end = function(chunk, encoding) {
res.responseTime = (new Date) - req._startTime;
res.end = end;
res.end(chunk, encoding);
...
}
express-winston 沒有修改或者擴充套件 winston 的transport, 而 winston-daily-rotate-file 正是增強了 winston 的transport 辦法
winston-daily-rotate-file
winston-daily-rotate-file 是 winston 擴充套件, 增加了 transport 的辦法,使 winston 有滾動日誌的能力。
結合使用
我們來一個需求: 如何讓 express-winston 列印日誌的時候,也列印出介面 /api 的請求引數和響應資料?
- 該日誌中介軟體應該在呼叫鏈 api 後面, api/* 業務處理之前。 like: app.use(`/api`, apiRequestLogger, apiHandler)
- 要獲取到響應資料, 就要在業務處理完後 send 出來後才能捕獲到,express 所有的請求響應最後都是走 res.send 我們可以從這裡入手捕獲響應資料
程式碼如下
import winston from `winston`
import expressWinston from `express-winston`
import `winston-daily-rotate-file`
import path from `path`
export let DailyRotateFileTransport = (fileName) => {
return new (winston.transports.DailyRotateFile)({
filename: path.join(process.env.LOGPATH, `${fileName}-%DATE%.log`),
datePattern: `YYYY-MM-DD-HH`,
// maxSize: `20m`,
maxFiles: `7d`,
timestamp: () => new Date().format(`yyyy-MM-dd hh:mm:ss.S`)
})
}
export let pageRequestLogger = expressWinston.logger({
transports: [
DailyRotateFileTransport(`page-request`)
],
meta: true, // optional: control whether you want to log the meta data about the request (default to true)
msg: `HTTP {{req.method}} {{req.url}}`, // optional: customize the default logging message. E.g. "{{res.statusCode}} {{req.method}} {{res.responseTime}}ms {{req.url}}"
expressFormat: true, // Use the default Express/morgan request formatting. Enabling this will override any msg if true. Will only output colors with colorize set to true
colorize: false, // Color the text and status code, using the Express/morgan color palette (text: gray, status: default green, 3XX cyan, 4XX yellow, 5XX red).
ignoreRoute: function (req, res) {
// 只列印頁面請求資訊
let notPageRequest = false
let ignoreArr = [`/api`, `.js`, `.css`, `.png`, `.jpg`, `.gif`]
ignoreArr.forEach(item => {
if (req.url.indexOf(item) > -1) notPageRequest = true
})
return notPageRequest
} // optional: allows to skip some log messages based on request and/or response
})
export let apiRequestLogger = (req, res, next) => {
let send = res.send
let content = ``
let query = req.query || {}
let body = req.body || {}
res.send = function () {
content = arguments[0]
send.apply(res, arguments)
}
expressWinston.logger({
transports: [
DailyRotateFileTransport(`api-request`)
],
meta: true, // optional: control whether you want to log the meta data about the request (default to true)
msg () {
return `HTTP ${req.method} ${req.url} query ${JSON.stringify(query)} body ${JSON.stringify(body)} resData ${content} `
},
colorize: true, // Color the text and status code, using the Express/morgan color palette (text: gray, status: default green, 3XX cyan, 4XX yellow, 5XX red).
ignoreRoute: function (req, res) {
if (req.headers.self) return true
return false
} // optional: allows to skip some log messages based on request and/or response
})(req, res, next)
}