V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
zzh2036
V2EX  ›  Node.js

nestjs 日志问题 traceId

  •  
  •   zzh2036 · 2023-08-11 17:26:10 +08:00 · 2418 次点击
    这是一个创建于 495 天前的主题,其中的信息可能已经有所发展或是发生改变。

    nestjs(express)做了一个简单的服务
    目前用 winston替换了 nestjs的默认日志及 typeorm的日志
    有时候需要查看日志定位问题,所以想在日志中添加 traceId用于追踪一次 request的完整链路,最好是无代码侵入的
    有查到使用 Async hooks进行 request上下文保存的
    大家有没有已实现的方案?

    23 条回复    2023-08-22 13:55:33 +08:00
    lzgshsj
        1
    lzgshsj  
       2023-08-11 17:50:43 +08:00
    没用 winston ,用的 pino ,自带了 genReqId 的方法
    NessajCN
        2
    NessajCN  
       2023-08-11 17:51:15 +08:00
    既然是你自己做的服务那你就在 logger.log()的时候把你要的 traceId 加进去呗....
    没怎么看懂你有什么进一步需求
    zzh2036
        3
    zzh2036  
    OP
       2023-08-11 17:57:59 +08:00
    @NessajCN 需要调用其他函数的时候,traceId 要当做参数继续传递下去吗?因为之前没有做过 traceId 这些,所以想知道一些详细的方案。traceId 的生成能和 jwt 中的 userId 做一些关联吗?
    zzh2036
        4
    zzh2036  
    OP
       2023-08-11 18:00:20 +08:00
    @lzgshsj 你是用了 fastify 还是 express 配合 pino 使用的?
    NessajCN
        5
    NessajCN  
       2023-08-11 18:05:02 +08:00
    @zzh2036 哦所以你问的是 tracerId 的生成问题而不是怎么在日志里加 id 的问题是吧?
    这个讲道理没有什么固定规则呀当然你怎么看得顺眼怎么来。要我的话函数名加个时间戳么差不多了...最多再加个 api 名
    thynson
        6
    thynson  
       2023-08-11 18:05:40 +08:00
    nestjs 是不太好做的,所以我自己实现了一个类似的框架 sensejs
    进一步了解: https://sensejs.io 或者 https://github.com/sensejs/sensejs
    thynson
        7
    thynson  
       2023-08-11 18:07:05 +08:00
    zzh2036
        8
    zzh2036  
    OP
       2023-08-11 18:10:34 +08:00
    @NessajCN 有如何在日志中加 id 的疑问,刚才说的 logger.log()直接加 traceId ,那如果调用其它函数,traceId 要当做参数继续往下传递是吧?
    thynson
        9
    thynson  
       2023-08-11 18:14:30 +08:00
    @zzh2036 NestJS 印象中我是这么做的,在依赖注入框架下,然后在每个类初始化的时候用,可以把 requestId 注入进来,并关联到 Logger 上,requestId 的产生需要定义一个 provider 。当然这种做法还是有一定的侵入性
    NessajCN
        10
    NessajCN  
       2023-08-11 18:16:07 +08:00 via Android
    @zzh2036 这个都是你自己决定的…你想接着用这个 id 就往下传,想用个新的就再生成一个呗
    zzh2036
        11
    zzh2036  
    OP
       2023-08-11 18:19:22 +08:00
    @thynson 感谢大佬,我去试试
    zzh2036
        12
    zzh2036  
    OP
       2023-08-11 18:19:47 +08:00
    @NessajCN 感谢大佬,大概了解一些了
    victimsss
        13
    victimsss  
       2023-08-11 18:19:54 +08:00
    @NessajCN 大概是在中间件使用 continuation-local-storage 或者 cls-hooked 记录 jwt 的 id 或者 生产的 reqId 然后供上下文使用,然后 logger 记录的时候不需要显式传参。
    crysislinux
        14
    crysislinux  
       2023-08-11 18:27:11 +08:00 via Android
    async hooks 不是 100%可靠的。这点比较坑,打日志可以用,但是不要做业务,比如存储 tenant id 之类的
    zzh2036
        15
    zzh2036  
    OP
       2023-08-11 18:27:29 +08:00
    @victimsss 总结的太棒了😀
    Helios0
        16
    Helios0  
       2023-08-11 21:20:13 +08:00
    nestjs-cls https://papooch.github.io/nestjs-cls/
    或者自己实现一个中间件也是一样的
    zurmokeeper
        17
    zurmokeeper  
       2023-08-11 21:32:06 +08:00
    个人暂时还是比较笨的方法实现,把 logger 对象挂在 req 上,请求的开头自己生成一个 traceid,挂上去,后续这个 req ,在 nestjs 的生命周期里都是能拿到的,然后用类似 req.logger.debug() 这种方式打印,整个生命周期就都是用 traceid 关联的了。如果还有其他服务,也可以把这个 traceid 放到请求头或者其他地方,一路传下去,也可以实现多个服务被一个 traceid 串起来的功能
    owen800q
        18
    owen800q  
       2023-08-12 00:25:39 +08:00 via iPhone
    @z
    @zurmokeeper 把 logger 放到 req 是個不錯的想法,反正 req 都要一直往下傳的
    zzh2036
        19
    zzh2036  
    OP
       2023-08-14 10:09:29 +08:00
    @Helios0 感谢大佬,这个 nestjs-cls 中 requestID 的 case ,比较符合我想要的效果
    zzh2036
        20
    zzh2036  
    OP
       2023-08-14 10:13:26 +08:00
    @zurmokeeper 很实用的想法,我之前想到在请求拦截中生成 traceId ,挂在 req 对象上,controller 里解出来,后续一直在 service 中做传递。但觉得应该有更优雅的实现
    guiling
        21
    guiling  
       2023-08-22 10:59:54 +08:00
    当初网上确实找不到成熟方案,所以自己实现的,核心就是利用 AsyncLocalStorage
    1 使用 express-request-id 作为日志的 traceid
    2 基于 AsyncLocalStorage 自己写一个中间件,获取请求头里的 traceid 并赋值到 AsyncLocalStorage 的实例中,这个是最核心的,代码不多,node 版本好想要 14 以上,网上有相关教程
    3 重写 console 的 log 合 error 方法,日志就用这两个,没用第三方 logger ,这样所有请求默认的日志就会带 traceid
    4 关于定时任务因为不走请求所以没有 traceid ,需要自己随机生成一个然后在最外层包进去(我是机器时间+任务名)

    最终效果大概这样
    https://s2.loli.net/2023/08/22/9EOeUzQD5XvAqWj.png
    定时任务的
    https://s2.loli.net/2023/08/22/x4dHy8wcLiM5mP3.png

    理论上最终可以做成想 java 那样的把模块方法名也打印出来
    zzh2036
        22
    zzh2036  
    OP
       2023-08-22 12:21:36 +08:00
    @guiling 不错的实现方式。我目前直接引用了 nestjs-cls 这个包,全局注册时自定义了 traceid 生成规则,在 winston logger 的 printf 方法中通过 cls 取出 traceid 进行打印。
    guiling
        23
    guiling  
       2023-08-22 13:55:33 +08:00
    @zzh2036 看了下原理一样的,也是基于 AsyncLocalStorage ,可惜当初做的时候这包还没出来,不然就省事了
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5992 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 02:16 · PVG 10:16 · LAX 18:16 · JFK 21:16
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.