EggJS實現一個簡易的鏈路日誌,集成到kibana中

項目背景

公司部署的kibana目前是從容器中的標準輸入輸出中採集日誌,目前還不支持指定文件或者目錄,egg自己的日誌是基於文件的,因此是沒發在kibana中查看egg自己打印的日誌node

標準輸入輸出

linux shell下經常使用輸入輸出操做符是:linux

1.  標準輸入   (stdin) :代碼爲 0 ,使用 < 或 << ; /dev/stdin -> /proc/self/fd/0   0表明:/dev/stdin 
2.  標準輸出   (stdout):代碼爲 1 ,使用 > 或 >> ; /dev/stdout -> /proc/self/fd/1  1表明:/dev/stdout
3.  標準錯誤輸出(stderr):代碼爲 2 ,使用 2> 或 2>> ; /dev/stderr -> /proc/self/fd/2 2表明:/dev/stderr
複製代碼

node中console.log會輸出到stdout、console.error輸出到stderr,因此要想收集到日誌,那就要用console方式輸出,shell

可是node中console是一個同步操做,因此頻繁的執行console輸出到終端,會阻塞進程,影響性能,因此日誌輸出須要有一個合併操做,因此我須要本身寫一個個性化日誌輸出插件,我最早想到的就是利用egg提供的拓展去作這件事

Egg 拓展

Egg 框架提供了多種擴展點擴展自身的功能:bash

Application
Context
Request
Response
Helper
在開發中,咱們既可使用已有的擴展 API 來方便開發,也能夠對以上對象進行自定義擴展,進一步增強框架的功能。
複製代碼

我選擇基於Context進行拓展,給他增長一個自定義Log方法,代碼以下,能夠根據本身的業務需求自行修改,文件路徑爲app/extend/context.jsapp

module.exports = {
  logs: [],
  LogStart (text) {
    const time = new Date()
    this.logs = [{
      time,
      text: 'start print log'
    }]
  },
  Log (text) {
    const time = new Date()
    this.logs.push({
      time,
      text
    })
  },
  LogEnd (type) {
    const tranceId = new Date().getTime()
    const url = this.request.url
    const userId = this.request.header['user-id']
    let logObj = {
      tranceId,
      userId,
      url,
      steps: {}
    }
    this.logs.map((item, index) => {
      let timeStr = item.time.toLocaleString() + ' ' + item.time.getMilliseconds() + 'ms'
      logObj.steps[index] = `< ${timeStr} > - ${item.text}`
    })
    const useTime = new Date().getTime() - new Date(this.logs[0].time).getTime()
    logObj.useTime = `${useTime} ms`
    if (type === 'error') {
      console.error('System Error:' + JSON.stringify(logObj))
    } else {
      console.log(JSON.stringify(logObj))
    }
  }
} 
複製代碼

egg日誌打印策略

一般 Web 訪問是高頻訪問,每次打印日誌都寫磁盤會形成頻繁磁盤 IO,爲了提升性能,咱們採用的文件日誌寫入策略是: 日誌同步寫入內存,異步每隔一段時間(默認 1 秒)刷盤框架

因此我在日誌調用結束會將日誌的完整鏈路一次所有打出,防止頻繁調用,只輸出一條記錄,在kibana中方便查看異步

這樣咱們在中間件中就能夠這樣調用async

module.exports = function (options) {
    return async function proxy(ctx, next) {
        await next()
        ctx.LogStart()
        ctx.Log('你要打印的日誌!')
        ctx.Log('執行A操做!')
        ctx.Log('執行B操做!')
        ctx.LogEnd()
    };
};
複製代碼

最後在kibana能夠看到下面這樣 性能

kibana
整個鏈路的日誌都能統一輸出
kibana

以上是我的在項目中的一次小的嘗試,若有問題,還請指出,謝謝

相關文章
相關標籤/搜索