node如何优雅地打印出全链路营销日志?

lxf2023-03-21 19:58:01

node如何优雅地打印出全链路营销日志?下边本文就要来给大家介绍一下在node中雅致打印出全链路营销日志的方式,希望能帮助到大家!

node如何优雅地打印出全链路营销日志?

当客户报难题:网上某一作用应用出错时,怎么才能清晰地精准定位?当某一请求接口回到数据信息迟缓时,怎样正确地跟踪提升?

一、原理和实践活动

大家都知道,当一个要求来临时,大约会出现下列日志造成:

1、AceesLog:用户访问日志

2、Exception:编码出现异常日志

3、SQL:sql查看日志

4、ThirdParty:第三方服务日志

该如何跟踪一条要求所产生的全部日志?

一般做法就是使用一个requestId做唯一标识,

随后写一个消息中间件,把requestId注入到context前后文中,当要打日志时,然后从context中取出打印出,

在第三方服务和SQL日志中,还要把requestId传到到对应的函数公式里边打印出,那样逐层传送,确实太麻烦了,编码介入性比较强。

我们希望减少编码介入性,一次引入,自动跟踪。

通过调查,async_hooks能够跟踪多线程个人行为的生命周期,在每一个多线程网络资源(每一个要求都是一个多线程网络资源)中,它都是有2个ID,

各是asyncId(多线程网络资源现阶段生命期ID),trigerAsyncId(父级多线程网络资源ID)。

async_hooks带来了下列生命期勾子来监视多线程网络资源:

asyncHook = async_hook.createHook({
  // 监视多线程资源建立
  init(asyncId,type,triggerAsyncId,resource){},
  // 多线程网络资源调用函数开始执行以前
  before(asyncId){},
  // 多线程网络资源调用函数开始执行后
  after(asyncId){},
  // 监视多线程资源消毁
  destroy(asyncId){}
})

那么如果其实做一个投射,每一个asyncId投射一个storage,storage里边再存放相对应的requestId,那requestId就能非常容易获得了。

恰好cls-hooked这一库早已根据async_hooks都做好了封装形式,在同一个一份多线程网络资源维护保养一份数据信息,以健值正确的方式存放。(留意:async_hooked必须在大版本号node>=8.2.1应用)自然社区中还有其他完成,例如cls-session,node-continuation-local-storage等。

下边讲讲我将cls-hooked应用从我项目中的案例

/session.js 建立取名内存空间

const createNamespace = require('cls-hooked').createNamespace 
const session = createNamespace('requestId-store') 
module.exports = session

/logger.js 打印出日志

const session = require('./session') 
module.exports = { 
info: (message) => 
{ 
const requestId = session.get('requestId')
console.log(`requestId:${requestId}`, message) 
}, 
error: (message) => 
{ 
const requestId = session.get('requestId') 
console.error(`requestId:${requestId}`, message) 
} 
}

/sequelize.js sql启用logger打印出日志

const logger = require("./logger") 
new Sequelize( 
logging: function (sql, costtime) { 
logger.error( `sql exe : ${sql} | costtime ${costtime} ms` ); 
} )

/app.js 设定requestId、设定requestId回到响应头、打印出浏览日志

const session = require('./session') 
const logger = require('./logger') 
async function accessHandler(ctx, next) 
{ 
const requestId = ctx.header['x-request-id'] || uuid()
const params = ctx.request.body ? JSON.stringify(ctx.request.body) : JSON.stringify(ctx.request.query)
// 设定requestId session.run(() => { session.set('requestId', requestId)
logger.info(`url:${ctx.request.path};params:${params}`) next()
// 设定回到响应头
ctx.res.setHeader('X-Request-Id',requestId)
}) }

大家看看当一条要求途径是/home?a=1来临时的日志:

浏览日志:
requestId:79f422a6-6151-4bfd-93ca-3c6f892fb9ac url:/home;params:{"a":"1"}

Sql日志:
requestId:79f422a6-6151-4bfd-93ca-3c6f892fb9ac sql exe :
Executed (default): SELECT `id` FROM t_user

能够看见同一条要求全部链接的日志requestId是一样的。假如后面还有报警发至报警服务平台,那我们依据requestId就能找到这一条要求实施的全部链接了。

细心地同学们可能观查到你在接口返回的响应头里也设置权限requestId,目的就是为了后面一旦发现某条请求响应迟缓或是有什么问题,那直接在电脑浏览器就能知道requestId,就能做阐述了。

二、特性花销

我当地进行了一下压测,

这也是运行内存的占有比照:

node如何优雅地打印出全链路营销日志?

比没有使用async_hook得多约10%。

其实对于我们qps是千级其他系统软件还行,但如果是分布式系统服务,估计要深思熟虑下。

ps:有误热烈欢迎强调,别喷我

大量node基本知识,请访问:nodejs 实例教程!

以上就是关于教你如何在node中怎么雅致打印出全链路营销日志的具体内容,大量欢迎关注AdminJS其他类似文章!