我有一些使用该log
包的大量检测代码。现在是时候关闭日志记录了,我无法确定如何关闭标准记录器。
我错过了什么吗?我应该在进行日志调用之前检查标志,还是在生产中将它们注释掉?
当 io/ioutil 包中存在一个通用 io.Writer 时,没有理由为通用 io.Writer 创建自己的类型。
import (
"log"
"io/ioutil"
)
func init() {
log.SetOutput(ioutil.Discard)
}
对于完全禁用日志,实际上最好调用log.SetFlags(0)
Joril并将输出设置为无操作io.Writer
(即,log.SetOutput(ioutil.Discard)
)
但即使在此之后,操作也会在500-600 ns/op 1左右空闲
这仍然可以通过使用自定义实现来缩短(到100 ns/opLogger
左右) ,并将所有功能实现为无操作 - 如此处所示(仅为Println
bervity 覆盖)。
所有这些的替代方法是使用具有级别的自定义日志框架并将其设置为完全关闭。
但请注意,常用的日志记录库之一 ( logrus ) 具有性能影响——无论如何,在它使用3K+ ns/op执行的基准测试中都可以找到相同的内容。
有偏见的意见:从基准测试来看,无论后端和格式如何,库go-logging在设置toLogger
时的性能与自定义实现相当Level
-1
(基准源可以在这里找到)
基准的输出如下:
testing: warning: no tests to run
PASS
BenchmarkGoLogging-4 1000000 2068 ns/op
BenchmarkGoLoggingNullBackend-4 5000000 308 ns/op
BenchmarkGoLoggingNullBackendWithFancyFormatter-4 3000000 435 ns/op
BenchmarkGoLoggingOffLevel-4 20000000 109 ns/op
BenchmarkGoLoggingNullBackendAndOffLevel-4 20000000 108 ns/op
BenchmarkGoLoggingNullBackendWithFancyFormatterAndOffLevel-4 20000000 109 ns/op
BenchmarkLog15-4 200000 7359 ns/op
BenchmarkLog15WithDiscardHandler-4 2000000 922 ns/op
BenchmarkLog15WithDiscardHandlerAndOffLevel-4 2000000 926 ns/op
BenchmarkLog15WithNopLogger-4 20000000 108 ns/op
BenchmarkLog15WithNopLoggerDiscardHandlerA-4 20000000 112 ns/op
BenchmarkLog15WithNopLoggerAndDiscardHandlerAndOffLevel-4 20000000 112 ns/op
BenchmarkLog-4 1000000 1217 ns/op
BenchmarkLogIoDiscardWriter-4 2000000 724 ns/op
BenchmarkLogIoDiscardWriterWithoutFlags-4 3000000 543 ns/op
BenchmarkLogCustomNullWriter-4 2000000 731 ns/op
BenchmarkLogCustomNullWriterWithoutFlags-4 3000000 549 ns/op
BenchmarkNopLogger-4 20000000 113 ns/op
BenchmarkNopLoggerWithoutFlags-4 20000000 112 ns/op
BenchmarkLogrus-4 300000 3832 ns/op
BenchmarkLogrusWithDiscardWriter-4 500000 3032 ns/op
BenchmarkLogrusWithNullFormatter-4 500000 3814 ns/op
BenchmarkLogrusWithPanicLevel-4 500000 3872 ns/op
BenchmarkLogrusWithDiscardWriterAndPanicLevel-4 500000 3085 ns/op
BenchmarkLogrusWithDiscardWriterAndNullFormatterAndPanicLevel-4 500000 3064 ns/op
ok log-benchmarks 51.378s
go test -bench . 62.17s user 3.90s system 126% cpu 52.065 total
#1:YMMV,在 i7-4500U CPU @ 1.80GHz 上测试
type NullWriter int
func (NullWriter) Write([]byte) (int, error) { return 0, nil }
// ...
log.SetOutput(new(NullWriter))
这种方法允许您在运行时打开和关闭日志记录:
type LogWriter struct{
enabled bool
}
func (l *LogWriter) Enable() {
l.enabled = true
}
func (l *LogWriter) Disable() {
l.enabled = false
}
func (l *LogWriter) Write([]byte) (int, error) {
if l.enabled {
//...
}
return 0, nil
}
这种方法启用或禁用整个运行时的日志记录:
type LogWriter struct{}
func (l *LogWriter) Write([]byte) (int, error) {
if some.Constant {
//...
}
return 0, nil
}
wheresome.Constant
将是您在编译之前设置的常量(生成“生产”二进制文件)或在通过命令行标志运行程序时仅设置一次的变量(类似于myprogram --enable-logging=true
)
使用这两种方法,您可以几乎完全保持当前代码不变。
由于SetOutput()
仅为全局记录器定义,自定义编写器对于其他记录器仍然很方便。一个简短的写法是这样的:
type LogWriter struct{ io.Writer }
func (w *LogWriter) Enable() { w.Writer = os.Stdout }
func (w *LogWriter) Disable() { w.Writer = ioutil.Discard }
其他人来这里寻找这个和其他日志记录工具的注意事项:看看 log4go 包,因为它包括关闭日志记录、设置日志级别、日志轮换、重定向到文件等可能有用。