zoukankan      html  css  js  c++  java
  • Golang 异常/日志处理

    1、xerrors 异常

    xerrors 包是一个非常棒的设计,不同于往常语言如java/php,因为go的errors只是一个string类型的映射,所以内存占用空间很少。这在golang的核心库和golang大多数开源模块中使用,简单,高效,稳定!比如:

    var myErr:=errors.New("error msg")
    func act1()err{
         return myErr
    }
    

            以上代非常高效,如果你经常做go的开发时。这种解决时经常会存在一个很头疼的问题,就是异常触发点很难定位,因为你很难去定位到异常发生的代码文件及行数和调用的堆栈,但出现问题时非常必要知道是什么情况处罚的这个异常,只是一个message不足以让开发人员去解决问题。

            在最新的xerrors包中,引入了一个caller堆地址,通过使用Format接口可以格式化出调用第一行的堆,但这往往很多时候不足以解决去定位问题。这时可以考虑使用第三方包,请继续往下看:)

    2、堆栈异常处理

    go.mod

    require github.com/pkg/errors latest
    
    go mod download
    
    package main
    
    import(
        "fmt"
        "github.com/pkg/errors"
    ) 
    
    func act1()error{
        return errors.New("hello world!")
    }
    
    func main(){
    fmt.Printf("%+v
    ",act1())
    }
    

    Output:

    Hello world!

    main.act1

    /tmp/aa/main.go:9

    main.main

    /tmp/aa/main.go:13

    runtime.main

    /usr/local/Cellar/go/1.13.4/libexec/src/runtime/proc.go:203

    runtime.goexit

    /usr/local/Cellar/go/1.13.4/libexec/src/runtime/asm_amd64.s:1357

    以上代码中,首先引用pkg/errrors堆异常包,然后通过使用%+v格式化error,将堆栈数据打印到屏幕中,通过这种方式,通过调用堆栈你可以快速定位异常的代码位置,从而快速解决问题。

    3、go原生日志框架

          glog是Golang log的缩写,开源于golang核心库,所以应用比较广泛实现如下:

    package main
    
    import "log"
    
    func main(){
    log.Println("Info","hello world")
    }
    

    output:

    2019/11/29 17:44:56 Info hello world

    因为功能过于简单,导致在golang中的日志很难实现日志的来源和日志级别实现日志的过滤功能。在很多模块集成后,导致日志繁杂错乱很难阅读,甚至到致不同模块包括的日志格式不同以及日志的级别也不一致,导致日志的分析带来了不少挑战!

    4、midlog 日志框架

    midlog类似于java的slf4j框架,定义了通用的日志级别、日志来源锁定、日志重定向框架,并且提供日志的重定义组件,可以将所有日志汇总处理,非常方便! 

    midlog 日志框架示 

    4.1、midlog 包接取

    go.mod

         require github.com/lingdor/midlog

    or

        go get github.com/lingdor/midlog

    4.2、midlog通用日志函数

     创建日志对象

    var Logger Midlog = New("your module name")
    

     建议这个Logger声明为外部可访问的,这样如果想实现日志的分流时,可以通过这个Logger对象判断日志的来源模块是哪来的,然后分流不同的日志记录。

    Logger.Trace("hello")
    
    Logger.Info("hello")
    
    Logger.Warn("hello")
    
    Logger.Debug("hello")
    
    Logger.Error1("hello")
    
    Logger.Error2("hello")
    
    Logger.Error3("hello")
    
    Logger.Log(LevelTrace, "hello")
    
     
    
    Logger.Infof("hello %s","world!")
    
    Logger.Tracef("hello %s","world!")
    
    Logger.Warnf("hello %s","world!")
    
    Logger.Debugf("hello %s","world!")
    
    Logger.Error1f("hello %s","world!")
    
    Logger.Error2f("hello %s","world!")
    
    Logger.Error3f("hello %s","world!")
    
    Logger.Logf(LevelTrace, "hello %s","world!")
    

    可以按照不同的日志级别,选择不同的函数,实现日志的记录!

    4.3、对接go原生日志框架

    go.mod 增加依赖

    require github.com/lingdor/midlog v1.0.0
    require github.com/lingdor/glog2midlog v1.0.0
    package main
    
     import (
    
    _ "github.com/lingdor/glog2midlog"
    
    "github.com/lingdor/midlog-examples/library1"
    
    "log"
    
    )
    
    func main() {
    
    log.Println("info", "hello world!")
    
    }

    output:

    2019-11-29 18:15:51 GLOG INFO  hello world!

    4.4 对接logrus

    go.mod

    require github.com/lingdor/midlog v1.0.0
    require github.com/lingdor/midlog2logrus v1.4.3

    main.go

    package main 
    
    import (
    "fmt"
    "github.com/lingdor/midlog"
    _ "github.com/lingdor/midlog2logrus"
    )
    
    var Logger = midlog.New("useLogrus")
    
    func main() {
    Logger.Info("hello world!")
    Logger.Error1("logger errror log")
    Logger.Ext(midlog.ExtMap{"123": "456"}).Error1("ext log")
    fmt.Println("done")
    }

    output:

    INFO[0000] hello world!                                 

    ERRO[0000] logger errror log                            

    ERRO[0000] ext log                                       123=456

    done 

    4.5 对接zap

    go.mod

    require github.com/lingdor/midlog v1.0.0
    require github.com/lingdor/midlog2zap v1.13.0
    

     main.go

    package main
    
    import (
    "fmt"
    "github.com/lingdor/midlog"
    _ "github.com/lingdor/midlog2zap"
    )
    
    var Logger = midlog.New("useLogrus")
    
    func main() {
    Logger.Info("hello world!")
    Logger.Error1("logger errror log")
    Logger.Ext(midlog.ExtMap{"123": "456"}).Info("ext log")
    fmt.Println("done")
    }
    

     output:

    {"level":"info","ts":1575022710.237491,"caller":"midlog2zap@v1.13.0/zapWriter.go:36","msg":"hello world!"}

    {"level":"error","ts":1575022710.23755,"caller":"midlog2zap@v1.13.0/zapWriter.go:37","msg":"logger errror log","stacktrace":"github.com/lingdor/midlog2zap.ZapWriter.Write /Users/bobby96333/go/pkg/mod/github.com/lingdor/midlog2zap@v1.13.0/zapWriter.go:37 github.com/lingdor/midlog.(*midlogT).tryWriteLog /Users/bobby96333/go/pkg/mod/github.com/lingdor/midlog@v1.0.0/logWriter.go:19 github.com/lingdor/midlog.(*midlogT).logWithCaller3 /Users/bobby96333/go/pkg/mod/github.com/lingdor/midlog@v1.0.0/midlog.go:122 github.com/lingdor/midlog.(*midlogT).Error1 /Users/bobby96333/go/pkg/mod/github.com/lingdor/midlog@v1.0.0/midlog.go:69 main.main /Users/bobby96333/go/midlog-examples/useZap/main.go:13 runtime.main /usr/local/Cellar/go/1.13.4/libexec/src/runtime/proc.go:203"}

    {"level":"info","ts":1575022710.237587,"caller":"midlog2zap@v1.13.0/zapWriter.go:36","msg":"ext log","123":"456"}

    done

    5、总结 

         实际上midlog只是一个日志接口层,并没有实现日志的滚动写入、异步等日志实际操作,但通过这个中间层,可以灵活对接自己选择的日志框架,和分流功能。然后通过zap/logrus/seelog/zerolog等模块组合实现日志的存储.

        不管是go的原生error还是log,都是一个非常棒的设计,很多时候可以解决最基础的需求,这避免了很多时候因为不需要而避免的额外性能消耗。而还有一部份场景,只是简单往往不足以解决问题,这导致简单和复杂的冲突哲学层面的取舍。我们在选择时,应该清楚了解自己的需求是什么,按照自己的需要去选择合适的模块,即可!

    6、参考资料

    midlog源码

    midlog-example源码

    zap源码

    logrus源码

    zap高性能日志

    谢谢

    来源: https://blog.csdn.net/obobby1/article/details/103316359

  • 相关阅读:
    Android执行时ART载入OAT文件的过程分析
    Oracle GoldenGate 支持 从SAP HANA database抽取或者复制数据到SAP HANA database 吗?
    【机房收费系统C#版】——导出Excel
    【STL容器学习】-关联容器与map的用法
    IOS
    使用Android Studio 1.3 版本号进行NDK开发
    4443: [Scoi2015]小秃玩矩阵|二分答案|匈牙利
    多版本号并发控制(MVCC)在实际项目中的应用
    memcached远程 telnet 无法连接,解决方案
    Memcached 服务器端命令
  • 原文地址:https://www.cnblogs.com/a-xu/p/11959537.html
Copyright © 2011-2022 走看看