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\n",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\n\t/Users/bobby96333/go/pkg/mod/github.com/lingdor/midlog2zap@v1.13.0/zapWriter.go:37\ngithub.com/lingdor/midlog.(*midlogT).tryWriteLog\n\t/Users/bobby96333/go/pkg/mod/github.com/lingdor/midlog@v1.0.0/logWriter.go:19\ngithub.com/lingdor/midlog.(*midlogT).logWithCaller3\n\t/Users/bobby96333/go/pkg/mod/github.com/lingdor/midlog@v1.0.0/midlog.go:122\ngithub.com/lingdor/midlog.(*midlogT).Error1\n\t/Users/bobby96333/go/pkg/mod/github.com/lingdor/midlog@v1.0.0/midlog.go:69\nmain.main\n\t/Users/bobby96333/go/midlog-examples/useZap/main.go:13\nruntime.main\n\t/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

Golang 异常/日志处理的更多相关文章

  1. Log4Net异常日志记录在asp.net mvc3.0的应用

    前言 log4net是.Net下一个非常优秀的开源日志记录组件.log4net记录日志的功能非常强大.它可以将日志分不同的等级,以不同的格式,输出到不同的媒介.本文主要是简单的介绍如何在Visual ...

  2. ASP.NET全局错误处理和异常日志记录以及IIS配置自定义错误页面

    应用场景和使用目的 很多时候,我们在访问页面的时候,由于程序异常.系统崩溃会导致出现黄页.在通常的情况下,黄页对于我们来说,帮助是极大的,因为它可以帮助我们知道问题根源,甚至是哪一行代码出现了错误.但 ...

  3. angular代码分析之异常日志设计

    angular代码分析之异常日志设计 错误异常是面向对象开发中的记录提示程序执行问题的一种重要机制,在程序执行发生问题的条件下,异常会在中断程序执行,同时会沿着代码的执行路径一步一步的向上抛出异常,最 ...

  4. ExceptionLess异常日志收集框架-1

    哈哈,中秋和代码更配哦,不知不觉一年过半了,祝园友们中秋快乐 前一阵子在博客园看到了一篇博文 http://www.cnblogs.com/savorboard/p/exceptionless.htm ...

  5. IOS异常日志记录与展现功能

    在平常的APP开发过程中经常碰到程序遇到异常闪退的问题,通过日志可以把相关的详细错误信息进行记录,本实例要记录不管在哪个页面出错都要进行记录,这边使用到的日志记录插件CocoaLumberjack,以 ...

  6. Log4Net异常日志记录在asp.net mvc3.0的应用(转载)

    这篇博客写的很好:http://www.cnblogs.com/qianlifeng/archive/2011/04/22/2024856.html 前言 log4net是.Net下一个非常优秀的开源 ...

  7. iOS应用日志:开始编写日志组件与异常日志

    应用日志(一):开始编写日志组件 对于那些做后端开发的工程师来说,看 LOG解Bug应该是理所当然的事,但我接触到的移动应用开发的工程师里面,很多人并没有这个意识,查Bug时总是一遍一遍的试图重现,试 ...

  8. 在 C# 控制台中记录异常日志并输出

    最近做了一个小程序,要求在控制台中记录程序运行的异常并输出到指定的文件夹中,以下是我的具体的程序代码: public static void ErrorLog(Exception ex) { stri ...

  9. 将Error异常日志从普通日志中剥离

    开发过程中经常需要调试和线上环境查看异常日志的需求,但普通消息与异常消息混在一起实在是非常难得找,上则NM的文档够你头痛,所以就将Error级别的日志抽离出来. 本示例采用log4net来配置: 1. ...

随机推荐

  1. 开发第一个maven示例

    mavenDemo目录如下: 在webapp下新建index.jsp文件 浏览器访问:http://localhost:8080/mavenDemo/index.jsp

  2. Mybatis延迟加载, 一级缓存、二级缓存

    延迟加载 概念:MyBatis中的延迟加载,也称为懒加载,是指在进行关联查询时,按照设置延迟规则推迟对关联对象的select查询.延迟加载可以有效的减少数据库压力. (注意:MyBatis的延迟加载只 ...

  3. 064_将 Linux 系统中 UID 大于等于 1000 的普通用户都删除

    #!/bin/bash#先用 awk 提取所有 uid 大于等于 1000 的普通用户名称#再使用 for 循环逐个将每个用户删除即可 user=$(awk -F: '$3>=1000{prin ...

  4. VsCode安装Go的相关插件

    今天在学习Go的时候,安装Go的相关插件,显示安装不上,但是右下角也一直会提示让你安装,当然你可以设置成忽略,为了开发效率,我选择了安装.然后出现了问题,一直Failed.在网上看到了很多的文章,不是 ...

  5. 搭建自己的博客(十七):添加每日阅读量并使用highcharts通过图表显示

    之前写了单篇博客的阅读量统计,今天添加了博客总阅读量统计,并且使用highcharts图表显示. 1.变化的部分

  6. QoS in RoCE

    QoS in RoCE 首页分类标签留言关于订阅2018-03-22 | 分类 Network  | 标签 RDMA  RoCE  ECN  PFC Overview TCP/IP协议栈满足不了现代I ...

  7. 《论文翻译》 GIOU

    目录 广义交并比-GIOU(回归检测的一种指标和Loss) 注释 1. 摘要 2. 介绍 3. 相关工作 4. 广义交并比 5. GIOU作为目标检测的LOSS 6. 实验结果 7. 个人理解 单词汇 ...

  8. 【原创】go语言学习(七)数组

    目录 数组定义 二维数组 数组拷贝.传参 数组定义 1. 数组是同一类型的元素集合. var a [3]int //定义一个数组 //Go中数组下标从0开始,因此⻓长度为n的数组下标范围:[0,n-1 ...

  9. meshing-simple_block

    原视频下载地址:https://yunpan.cn/cqjeSzP7s93Pc  访问密码 aaff

  10. RK3288 查看ddr信息

    转载请注明出处:https://www.cnblogs.com/lialong1st/p/10910949.html CPU:RK3288 系统:Android 5.1 1.查看ddr驱动版本号.容量 ...