Permalink: 2015-05-15 16:15:04 by ning in golang

日志库考虑因素:

  • 级别: 最好是 always, err, warn, notice, info, debug, verbos 几个级别.

  • 性能: 如果设置级别低, 应该对程序性能没有任何影响.(不要先format)

  • 易用性:
    • 不需要显示初始化.

    • 打印代码行.

    • 可以动态设置日志级别

    • 如果支持rolling, rolling 需要提供小时级()
      • 不过自动rolling切日志都会降低性能.

因为标准库不支持日志级别, 所以造轮子的需求很强烈.

1   常见库

1.1   标准库

/usr/local/go/src/pkg/log/log.go

  • 没有级别:
  • 不需要初始化, 易用性ok

1.2   beego

~/go/src/github.com/astaxie/beego/logs
http://beego.me/docs/module/logs.md

遵守 RFC5424 log message levels:

const (
    LevelEmergency = iota
    LevelAlert
    LevelCritical
    LevelError
    LevelWarning
    LevelNotice
    LevelInformational
    LevelDebug
)

Numerical         Severity
 Code

  0       Emergency: system is unusable
  1       Alert: action must be taken immediately
  2       Critical: critical conditions
  3       Error: error conditions
  4       Warning: warning conditions
  5       Notice: normal but significant condition
  6       Informational: informational messages
  7       Debug: debug-level messages

问题:

  1. 必须初始化并持有一个句柄才能打印日志:

    log := NewLogger(10000)
    log.Trace("trace %s %s","param1","param2")
    
  2. 打日志先format再去判断级别, 性能差:

    // Log WARNING level message.
    func (bl *BeeLogger) Warning(format string, v ...interface{}) {
        msg := fmt.Sprintf("[W] "+format, v...)
        bl.writerMsg(LevelWarning, msg)
    }
    
    func (bl *BeeLogger) writerMsg(loglevel int, msg string) error {
        if loglevel > bl.level {
            return nil
        }
    
  3. 为了兼容老代码, 代码中冗余函数较多.

1.3   log4go

File logging with rotation (size, linecount, daily) and custom output formats
Console logging
Network logging via JSON and TCP/UDP

级别很奇怪:

const (
    FINEST level = iota
    FINE
    DEBUG
    TRACE
    INFO
    WARNING
    ERROR
    CRITICAL
)

和常见的顺序是反的.. 没有NOTICE.

使用上也需要初始化一个实例再调用实例的方法.

1.4   codis logging库

级别差不多, 问题不大:

const (
    LOG_FATAL   = LogType(0x1)
    LOG_ERROR   = LogType(0x2)
    LOG_WARNING = LogType(0x4)
    LOG_INFO    = LogType(0x8)
    LOG_DEBUG   = LogType(0x10)
)
  • 底层是基于Log.
  • 性能ok
  • 不需要初始化一个实例

2   性能

对几个库做了benchmark, (代码: https://github.com/idning/golog/blob/master/benchmark/log_benchmark.go)

结果如下:

go run benchmark/log_benchmark.go
qps of     dummy1: 2727908735
qps of     dummy2:  552468326
qps of   variadic:    6151799
qps of    logging:    4003802
qps of      golog:    5986678
qps of     beelog:    1170780       <beego 性能确实较差>

测试发现, 使用变参形式就会导致性能很差:

Debug("hello %s", "world")        // 1. 100w/s
Debug("hello world")              // 2. 1000w/s 性能好10倍.

对于变参写法, 通过profiling发现, 此时90%的时间都用于GC,

原因在于, 变参的这种写法, 每次要把参数转为 interface 构成的 slice, 产生了很多对象. 所以gc时间很重.

在benchmark里面我也加了 variadic测试, 对于一个空函数, 也只能达到600w/s 的性能.

3   小结

  1. beego性能较差.
  2. codis logging是目前所见较好的库(日志级别不习惯)
  3. 一旦使用了变参函数, 性能就很差.

Comments