前言

(import “log”) 

当前也有一些比较重量级的log模块,比如logrus,可以实现比较复杂的功能。这里介绍一个轻量级的log模块——log4go

最近又看了一些golang的日志包和相关的文章,仔细阅读了go 1.9.2系统提供的log和go-log,产生了对log4go的日志输出进行优化的想法。

结构化与multiwriter

log使用multiwriter支持多个日志输出,用 Mutex 加锁解决多线程日志输出的冲突。log4go 则采用结构化编程用 channel 传递 LogRecord 日志记录。

原来以为 channel 的效率比较高……其实这是一个伪命题。channel 是一个全局加锁的队列,可以用来加锁,但效率比较低。因为它多了传递数据、协调顺序处理、timout等功能,并不仅仅是加锁。跟Mutex不是一回事儿。

Close() 

log直接将格式化日志信息输出到屏幕,简单多了。

试着兼顾两者,在 log4go 中增加了 writer,直接输出到屏幕。拟将FileLog,SocketLog作为backend,仍然放在结构里。这样,调试小程序和生产程序可以使用同一个日志库。实测效率略有降低。不知道 windows 下的 ColorLog 如何,以后再说。

SetOutput(nil) out = nil 

Determine caller func - it's expensive

runtime.Caller(skip int)log.SetSkip(-1) log.SetSkip(log.GetSkip()+1) 

format优化

其实,这才是文章的主题。

日志输出避免不了打印日期和时间,linux 环境下还要打印微秒,说不定还要打印时区。log4go的pattlog.go就是完成这些工作的。

  • 有一个1秒更新一次的cache机制。很漂亮。
  • 大量使用字符串格式化函数——fmt.Sprintf。
  • 返回字符串。而writer一般支持的是[]byte。多做一次转换。
  • 每次都bytes.Splite讲format字符串以%字符分解成[][]byte。

在log里边自备了一个cheap的itoa函数。

用这个函数替换日期和时间的字符串格式化函数。用[]byte代替string。

优化前,log4go 的 benchmark。

优化后:

格式化日期时间所花的时间是原来的1/3。

打印无格式化信息所花的时间是原来的1/2。

runtime.Caller

字符串格式化——比较昂贵。

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对脚本之家的支持。