返回
Featured image of post NodeJS - log處理

NodeJS - log處理

winston 是一款熱門的log套件,非常好用,nanoid是一款加密小工具那他是來做什麼的呢?

什麼是Log?為什麼Log也要處理格式?

Log的重要程度佔了整個維運工作的其最重要的角色,有專門在處理Log的大型框架ELK,Log的用途甚廣,可以記錄使用者於其應用介面的任何操作,尤其蠻常見的就是與廠商介接掉單處理,查詢應用層的各項缺失,所以要將Log統一風格化處理,我的習慣是將Log輸出成Json格式。
也不是將所有不重要的資訊都通通倒垃圾般的導出Log,Log也是有分程度的,常見的分法有 error(錯誤)、warn(警告)、info(信息)、http、verbose(冗長)、debug(調試)、silly(愚蠢)
開發過程會有多個環境去處理,dev/qa/prod環境不同而提出不同的環境。

套件網址:

winston - 286 kB

npm i winston

特色

  • 可以分程度導出
  • 可自組輸出格式
  • 彈性輸出log資料

封裝自用

import { createLogger, format, transports } from 'winston';

export default createLogger({
    level: process.env.NODE_ENV == "development" ? 'info' : 'warn', // 輸出 Level
    format: format.combine(
        format.timestamp(),
        format.json(),
    ),
    transports: [
        new transports.Console(),
    ],
});

所以如果你要引用在其他Route使用就import package logger就可以了。

與 Express 框架使用

常見的紀錄時機有兩個時機,也是最常用的時機,就是 Request/Response 這兩個時機,可能使用者送進來的資料有問題,在查詢問題時會導出Log,或是我方錯誤資訊記錄起來。

middleware

這是一段 typescript,也不用特別緊張,重點是組 Log 可能要有什麼資訊。

import { NextFunction, Request, Response } from 'express';
import { ExpressMiddlewareInterface } from 'routing-controllers';
import { nanoid } from 'nanoid'
import logger from '../packages/logger';

export class ReqLoggerMiddleware implements ExpressMiddlewareInterface {
  use(req: Request, res: Response, next?: (err?: any) => NextFunction): any {
    let log = {
      // Request
      pid: nanoid(),
      method: req.method,                                            // Request 的 http method : 'GET' 'POST' 'PUT' 'PATCH' 'DELETE' ...
      url: req.protocol + '://' + req.get('host') + req.originalUrl, // Request 的 URL
      body: req.body,                                                // Request 的 body
      params: req.params,                                            // Request 的 params
      query: req.query,                                              // Request 的 query
      clientAuth: req.headers.Authorization,                         // Request 的 clientAuth
      clientIP: req.headers['x-forwarded-for'],                      // Request 的 clientIP
    }
    res.locals.pid = log.pid                                         // pass pid ,Express 提供的一個功能想傳遞就綁在 `res.locals` 上面 
    logger.info('Request Data', log)
    logger.info('Request Data', log)                                 // 如果你是 info 就是用 info() warn 就用 warn()
    // {"pid":"IGjI3iV_GLXXMq6sB_jqW","url":"http://127.0.0.1:30080/api/v1/route?rows=10&sort=sales&page=1&memberId=0","body":{},"params":{},"query":{"rows":"10","sort":"sales","page":"1","memberId":"0"},"level":"info","message":"Request Data","timestamp":"2021-08-27T03:47:13.893Z"}
    // 如果是 logger.info('message'),會有 pid 就是因為 我在製作package的時候有加入 defaultMeta 我把它稱作為 pid
    // {"pid":"IGjI3iV_GLXXMq6sB_jqW","level":"info","message":"Request Data","timestamp":"2021-08-27T03:47:13.893Z"}

    // Response 不建議每一筆都要 回傳 但如果你要的話 將回傳的資料都取出。 
    res.on('finish', function () { logger.info('Response Data', { ...res.locals }) });
    next();
  }
}

什麼是 pid ?

pid 又稱為 process id 進程ID,他是代表這一個執行緒所執行的進程ID,沒錯 NodeJS 預設也有一個 process.pid,你們可以使用看看,他是一個數字而且永遠不會增加。
查詢問題的時候可以用兩個依據去查詢一個是時間區間,一個就是pid,我們可以使用 uuid4 或著是向下方介紹的 nanoid 當作 你的 pid

nanoid - 59.5 kB

npm i nanoid

特色

  • 非常輕量
  • 短加密

用法簡單:

import { nanoid } from 'nanoid'
console.log(nanoid()) // zpSZymgimvr7jrTF0G3HR
Licensed under CC BY-NC-SA 4.0
comments powered by Disqus