为什么要用zap来写日志

原来是写PHP的,一直用的error_log,第一次写Go项目的时候,还真不知道该怎么写日志,后来就按照PHP的写法自己不成规范的捣鼓写。去了新公司之后,发现用的是zap。后来查询 了解了下zap,前同事反应他们很多大公司都在使用zap写日志,GitHub上star 高达7K多,足以说明它受欢迎的程度。

1.zap是Uber开源的日志库;

2.很多大的公司和小的公司都在使用;

3.跟seelog、logrus等类库相比,高性能是它最突出的优势;

我想以上几个原因就已经说明了它的广泛性、稳定性,就值得我们去尝试。

怎么使用zap

我们说下简单的使用案例

首相当然是下载

go get -u go.uber.org/zap

先贴一个我这边常用的zap的配置

  1. zap.Config{
  2. Level: zap.NewAtomicLevelAt(zap.DebugLevel),
  3. Development: true,
  4. Encoding: "json",
  5. EncoderConfig: zapcore.EncoderConfig{
  6. TimeKey: "t",
  7. LevelKey: "level",
  8. NameKey: "log",
  9. CallerKey: "caller",
  10. MessageKey: "msg",
  11. StacktraceKey: "trace",
  12. LineEnding: zapcore.DefaultLineEnding,
  13. EncodeLevel: zapcore.LowercaseLevelEncoder,
  14. EncodeTime: 时间格式函数,
  15. EncodeDuration: zapcore.SecondsDurationEncoder,
  16. EncodeCaller: zapcore.ShortCallerEncoder,
  17. },
  18. OutputPaths: []string{"/tmp/zap.log"},
  19. ErrorOutputPaths: []string{"/tmp/zap.log"},
  20. InitialFields: map[string]interface{}{
  21. "app": "test",
  22. },
  23. }

基本配置的说明

Level:日志级别,跟其他语言是一样的。只不过它需要的类型是AtomicLevel。所以需要使用zap.NewAtomicLevelAt做下如下的转化。

  1. zap.NewAtomicLevelAt(zap.DebugLevel)
  2. zap.DebugLevel
  3. zap.InfoLevel
  4. zap.WarnLevel
  5. zap.ErrorLevel

Development:bool 是否是开发环境。如果是开发模式,对DPanicLevel进行堆栈跟踪

DisableCaller:bool 禁止使用调用函数的文件名和行号来注释日志。默认进行注释日志

DisableStacktrace:bool 是否禁用堆栈跟踪捕获。默认对Warn级别以上和生产error级别以上的进行堆栈跟踪。

Encoding:编码类型,目前两种json 和 console【按照空格隔开】,常用json

EncoderConfig:生成格式的一些配置--TODO 后面我们详细看下EncoderConfig配置各个说明

OutputPaths:[]string 日志写入文件的地址

ErrorOutputPaths:[]string 将系统内的error记录到文件的地址

InitialFields:map[string]interface{} 加入一些初始的字段数据,比如项目名

当然了,如果想控制台输出,OutputPaths和ErrorOutputPaths不能配置为文件地址,而应该改为stdout。

关于config的配置,具体的可以参考文件里面的注释

go.uber.org/zap/config.go

type Config struct

EncoderConfig配置说明

MessageKey:输入信息的key名

LevelKey:输出日志级别的key名

TimeKey:输出时间的key名

NameKey CallerKey StacktraceKey跟以上类似,看名字就知道

LineEnding:每行的分隔符。基本zapcore.DefaultLineEnding 即"\n"

EncodeLevel:基本zapcore.LowercaseLevelEncoder。将日志级别字符串转化为小写

EncodeTime:输出的时间格式

EncodeDuration:一般zapcore.SecondsDurationEncoder,执行消耗的时间转化成浮点型的秒

EncodeCaller:一般zapcore.ShortCallerEncoder,以包/文件:行号 格式化调用堆栈

EncodeName:可选值。

具体EncoderConfig的说明,可以参考文件里面的注释

go.uber.org/zapcore/encoder.go

type EncoderConfig struct

举个栗子

你扯这么多配置说明,谁有时间看这玩意,写个常用的让大家照着用就好了嘛。

  1. package main
  2. import (
  3. "fmt"
  4. "go.uber.org/zap"
  5. "go.uber.org/zap/zapcore"
  6. "time"
  7. )
  8. var logger *zap.Logger
  9. func formatEncodeTime(t time.Time, enc zapcore.PrimitiveArrayEncoder) {
  10. enc.AppendString(fmt.Sprintf("%d%02d%02d_%02d%02d%02d", t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute(), t.Second()))
  11. }
  12. func FormateLog(args []interface{}) *zap.Logger {
  13. log := logger.With(ToJsonData(args))
  14. return log
  15. }
  16. func Debug(msg string, args ...interface{}) {
  17. FormateLog(args).Sugar().Debugf(msg)
  18. }
  19. func ToJsonData(args []interface{}) zap.Field {
  20. det := make([]string, 0)
  21. if len(args) > 0 {
  22. for _, v := range args {
  23. det = append(det, fmt.Sprintf("%+v", v))
  24. }
  25. }
  26. zap := zap.Any("detail", det)
  27. return zap
  28. }
  29. func InitZapLog() {
  30. cfg := zap.Config{
  31. Level: zap.NewAtomicLevelAt(zap.DebugLevel),
  32. Development: true,
  33. Encoding: "json",
  34. EncoderConfig: zapcore.EncoderConfig{
  35. TimeKey: "t",
  36. LevelKey: "level",
  37. NameKey: "logger",
  38. CallerKey: "caller",
  39. MessageKey: "msg",
  40. StacktraceKey: "trace",
  41. LineEnding: zapcore.DefaultLineEnding,
  42. EncodeLevel: zapcore.LowercaseLevelEncoder,
  43. EncodeTime: formatEncodeTime,
  44. EncodeDuration: zapcore.SecondsDurationEncoder,
  45. EncodeCaller: zapcore.ShortCallerEncoder,
  46. },
  47. OutputPaths: []string{"/tmp/zap.log"},
  48. ErrorOutputPaths: []string{"/tmp/zap.log"},
  49. InitialFields: map[string]interface{}{
  50. "app": "test",
  51. },
  52. }
  53. var err error
  54. logger, err = cfg.Build()
  55. if err != nil {
  56. panic("log init fail:" + err.Error())
  57. }
  58. }
  59. func main() {
  60. InitZapLog()
  61. defer logger.Sync()
  62. a := []string{"test","hello","world"}
  63. Debug("output",a)
  64. }

执行下,就会在日志文件上输入按照我们配置日志格式。

  1. tail -f /tmp/zap.log
  2. {"level":"debug","t":"20190630_044053","caller":"myproject/main.go:21","msg":"output","app":"test","detail":["[test hello world]"]}

然后我们试下控制台输出,修改三个console相关的配置代码

···

OutputPaths: []string{"stdout"},

ErrorOutputPaths: []string{"stdout"},

控制台窗口就会输出

{"level":"debug","t":"20190630_092533","caller":"myproject/main.go:21","msg":"output","app":"test","detail":["[test hello world]"]}

···

当然了,zap最想的使用和文档,看官网嘛

https://github.com/uber-go/zap

https://godoc.org/go.uber.org/zap

golang开发:类库篇(一) Zap高性能日志类库的使用的更多相关文章

  1. golang开发:环境篇(五)实时加载工具gin的使用

    gin 工具是golang开发中非常有用且有效的工具,有效的提高了开发调试go程序的效率. 为什么要使用gin 我们知道golang是编译型语言,这就表示go程序的每次改动,如果需要查看改动结果都必须 ...

  2. zap高性能日志

    摘要 日志在整个工程实践中的重要性不言而喻,在选择日志组件的时候也有多方面的考量.详细.正确和及时的反馈是必不可少的,但是整个性能表现是否也是必要考虑的点呢?在长期的实践中发现有的日志组件对于计算资源 ...

  3. 【PHP调试篇】PHP高性能日志组件SeasLog

    简述 什么是SeasLog SeasLog是一个C语言编写的PHP扩展,提供一组规范标准的功能函数,在PHP项目中方便.规范.高效地写日志,以及快速地读取和查询日志. 为什么使用SeasLog 无论在 ...

  4. mysql 开发进阶篇系列 41 mysql日志之慢查询日志

    一.概述 慢查询日志记录了所有的超过sql语句( 超时参数long_query_time单位 秒),获得表锁定的时间不算作执行时间.慢日志默认写入到参数datadir(数据目录)指定的路径下.默认文件 ...

  5. mysql 开发进阶篇系列 39 mysql日志之二进制日志(binlog)

    一.概述 二进制日志(binlog)记录了所有的DDL(数据定义语言)语句和DML(数据操纵语言)语句,但是不包括数据查询语句, 语句以"事件"的形式保存,它描述了数据的更改过程, ...

  6. mysql 开发进阶篇系列 38 mysql日志之错误日志log-error

    一.mysql日志概述 在mysql中,有4种不同的日志,分别是错误日志,二进制日志(binlog日志),查询日志,慢查询日志.这此日志记录着数据库在不同方面的踪迹(区别sql server里只有er ...

  7. golang开发:环境篇(六) Go运行监控Supervisord的使用

    为什么要使用Supervisord 17年第一次写Go项目的时候,用Go开发项目倒没没费多大劲,很快就开发完成了.到了在测试环境部署的时候,由于不知道有 Supervisord 这个软件,着实花了些功 ...

  8. golang开发:环境篇(四)包管理器 glide的使用

    glide 是golang项目开发中是特别重要的软件,没有它,golang的项目可能都无法发布. 为什么要使用glide 平时我们开发Go项目的时候,使用第三方的包的时候都直接使用go get 去获取 ...

  9. mysql 开发进阶篇系列 40 mysql日志之二进制日志下以及查询日志

    一.binlog 二进制其它选项 在二进制日志记录了数据的变化过程,对于数据的完整性和安全性起着非常重要作用.在mysql中还提供了一些其它参数选项,来进行更小粒度的管理. 1.1 binlog-do ...

随机推荐

  1. Android 光标位置设置

    EditText edit =(EditText) findViewById(R.id.etTest); 1.设置光标在EditText中的指定位置 edit.setSelection(1); 需要注 ...

  2. PHP中遍历关联数组的方法

    下面介绍PHP中遍历关联数组的三种方法:foreach <?php $sports = array( 'football' => 'good', 'swimming' => 'ver ...

  3. qt的应用层主要是大型3d,vr,管理软件和器械嵌入软件(有上千个下一代软件黑科技项目是qt的,美国宇航局,欧洲宇航局,超级战舰DDG1000)

    作者:Nebula.Trek链接:https://www.zhihu.com/question/24316868/answer/118944490来源:知乎著作权归作者所有.商业转载请联系作者获得授权 ...

  4. 简明Python3教程 15.异常

    简介 当程序发生意外情况时则产生异常. 例如你需要读一个文件而这个文件并不存在会咋样?又或者是程序运行时你把它误删除了呢? 上述情形通过异常进行处理. 类似的,如果你的程序存在一些非法语句会发生什么呢 ...

  5. broadAnywhere:Broadcast组件权限绕过漏洞(Bug: 17356824)

    原创内容,转载请注明出处 http://retme.net/index.php/2014/11/14/broadAnywhere-bug-17356824.html Lolipop源代码已经放出有些日 ...

  6. Cocos2d-x layout (两)

    相对于对照布局 Size widgetSize = Director::getInstance()->getWinSize(); Text* alert = Text::create(" ...

  7. C++:怎样把一个int转成4个字节?

    大家都知道,一个int 或 unsigned int是由4个字节组成的,(<C/C++学习指南>,第3章,第3.2.3节:变量的内存视图) 比如, int   n  =  sizeof( ...

  8. 基于Linux C的socketEthereal程序和Package分析 (一个)

     执行测试平台:CentOS 6.5发行版,内核版本号3.11 1. Linux抓包源程序 在OSI七层模型中.网卡工作在物理层和数据链路层的MAC子层. 进行网络通信时.源主机通过socket( ...

  9. C++异常机制的实现方式和开销分析 (大图,编译器会为每个函数增加EHDL结构,组成一个单向链表,非常著名的“内存访问违例”出错对话框就是该机制的一种体现)

    白杨 http://baiy.cn 在我几年前开始写<C++编码规范与指导>一文时,就已经规划着要加入这样一篇讨论 C++ 异常机制的文章了.没想到时隔几年以后才有机会把这个尾巴补完 :- ...

  10. DataGrid数据绑定

    后台数据绑定 用户场景是生成报表,展示公司各员工每个月的绩效 数据结构 包括报表和单个员工绩效两个实体 public class Report { /// <summary> /// 统计 ...