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

以上是我的在项目中的一次小的尝试,若有问题,还请指出,谢谢

相关文章
相关标签/搜索