V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
The Go Programming Language
http://golang.org/
Go Playground
Go Projects
Revel Web Framework
zwpaper
V2EX  ›  Go 编程语言

Golang 有没有什么方法能解决高并发时, log 的输出问题?

  •  
  •   zwpaper ·
    zwpaper · 2017-06-16 21:35:15 +08:00 · 2798 次点击
    这是一个创建于 2715 天前的主题,其中的信息可能已经有所发展或是发生改变。

    最近在写程序,自己调试的时候没什么问题,真正用的时候发现日志特别乱,才发现并发的时候,日志都打一起去了,虽然也是行输出的,但是就不好找运行的流程了。

    所以在想,能不能有什么办法,在并发的时候,能区分一下不同 goroutine 的日志

    第一个想到打 goroutine ID,但是这个被 Google 否决了,并不能拿到这个 ID。 尴尬点的方法,自己生成一个 ID,也是一种方案,但是太不优雅了

    找日志库,好像也没人讨论出这方面比较好的库

    不知道在座各位有没有什么好一点的解决方案?

    19 条回复    2017-06-17 11:47:29 +08:00
    wweir
        1
    wweir  
       2017-06-16 22:02:21 +08:00 via Android
    针对调用链(栈)区分上下文,把上下文作为 tag 打到日志里。

    context 包里加上全局唯一 ID 可以一定程度上解决分布式调用链追踪问题,不过这方法对你的问题而言,有点过重了
    est
        2
    est  
       2017-06-16 22:17:24 +08:00
    再开一个 goroutine 专门把数组转换成日志并且定时 flush。
    cxbig
        3
    cxbig  
       2017-06-16 22:28:43 +08:00   ❤️ 1
    现在比较流行 ELK 日志管理 https://www.elastic.co/
    找现成试用 有 https://logz.io/
    zwpaper
        4
    zwpaper  
    OP
       2017-06-16 23:17:21 +08:00
    @wweir #1 针对调用链这个不太理解,现在就是在并发的时候,各个 goroutine 都有自己的调用链,打到一起就乱了😳

    确实是想找一个能稍微简单一点的方案
    zwpaper
        5
    zwpaper  
    OP
       2017-06-16 23:18:30 +08:00
    @cxbig #3 ELK 就更重了,而且 ELK 首先也得在打印的时候能区分吧?
    zwpaper
        6
    zwpaper  
    OP
       2017-06-16 23:19:10 +08:00
    @est #2 这个方案写着写着,应该就是一个 log 库了吧。。。
    devops
        7
    devops  
       2017-06-16 23:37:01 +08:00
    蛤蛤,这个问题我搞过,overhead 最小的办法是修改 runtime 库,加上这个函数。

    func GoID() int64 {
    return getg().goid
    }
    zwpaper
        8
    zwpaper  
    OP
       2017-06-16 23:42:50 +08:00
    @devops #7 对了,这个也查到过,但是改人官方库,总感觉有点太 tricky 了。。。
    cxbig
        9
    cxbig  
       2017-06-16 23:43:51 +08:00
    @zwpaper ELK 可以方便的分析和归类日志
    至于区分的问题,每个进程生成一个随机 key 怎么就不优雅呢?
    mingyun
        10
    mingyun  
       2017-06-16 23:45:01 +08:00
    @cxbig nice
    zwpaper
        11
    zwpaper  
    OP
       2017-06-17 00:05:07 +08:00
    @cxbig #9 目前看来就这个方法最简单了
    zwpaper
        12
    zwpaper  
    OP
       2017-06-17 00:05:42 +08:00
    @cxbig #9 还想看看大家有没有一些不一样的思路
    cxbig
        13
    cxbig  
       2017-06-17 00:13:15 +08:00
    @zwpaper 你还可以直接用 stream 发出去,不写 FS。
    https://github.com/omc/dendrite

    并发量大的话可以用 Kafka 之类的中间件可以进一步稳定性能。
    herozem
        14
    herozem  
       2017-06-17 01:40:15 +08:00 via iPhone
    在 nginx 上加一个 requestID ?然后 elk 再归一下类
    wweir
        15
    wweir  
       2017-06-17 07:03:41 +08:00 via Android   ❤️ 1
    @zwpaper 最简单轻量的两种做法,
    通常是在函数的参数中(或者方法的结构体中),加个 context 保存 tag,打日志的时候带上这个 tag。
    另一个更轻量省事,引入一个第三方 errors 包,报错一层一层手动加调用栈。遇到 goruntine 加上其 id 或者方便识别的随机字符串

    PS:扯 elk 大数据之流纯属扯淡,日志乱到人都分辨,工具更是没法分辨
    TheCure
        16
    TheCure  
       2017-06-17 10:13:27 +08:00   ❤️ 2
    context 不就是干这个的么
    mengzhuo
        17
    mengzhuo  
       2017-06-17 10:37:57 +08:00 via iPhone   ❤️ 1
    思路问题
    1. 加上日志等级
    2. 不要输出没必要的调试日志
    3. UT 保证程序的正确性,而不是肉眼看日志
    zwpaper
        18
    zwpaper  
    OP
       2017-06-17 10:41:57 +08:00 via iPhone
    @mengzhuo
    1. 等级有,但是并不能解决并发日志问题
    2. 同一
    3. 单测做的再好,也无法避免有时候出错需要查日志吧?
    reus
        19
    reus  
       2017-06-17 11:47:29 +08:00
    一般只有 panic 日志,也就是,如果打出日志来,就说明需要我要干预
    不需要关心的都直接入库
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5558 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 03:10 · PVG 11:10 · LAX 19:10 · JFK 22:10
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.