英文:
How to disable a log.Logger
问题
我有一些使用log
包的代码,其中有很多仪器化的部分。现在是关闭日志记录的时候了,但我无法确定如何关闭标准日志记录器。
我有遗漏了什么吗?在进行日志调用之前,我应该检查一个标志,还是在生产环境中将它们注释掉?
英文:
I have some heavily instrumented code that makes use of the log
package. Now it's come time to turn off the logging, and I can't determine how to turn off the standard logger.
Have I missed something? Should I be checking a flag before making log calls, or commenting them out in production?
答案1
得分: 129
没有理由为常见的io.Writer创建自己的类型,因为在io/ioutil包中已经存在一个。
import (
"log"
"io/ioutil"
)
func init() {
log.SetOutput(ioutil.Discard)
}
从Go 1.16开始,只需使用io.Discard
> package ioutil // import "io/ioutil"
>
> var Discard io.Writer = io.Discard
> Discard是一个io.Writer,所有的写入调用都会成功,而不做任何操作。
>
> 已弃用:从Go 1.16开始,这个值只是io.Discard。
log.SetOutput(io.Discard)
英文:
No reason to create your own type for a common io.Writer when one exists in the io/ioutil package.
import (
"log"
"io/ioutil"
)
func init() {
log.SetOutput(ioutil.Discard)
}
From Go 1.16, just use io.Discard
> package ioutil // import "io/ioutil"
>
> var Discard io.Writer = io.Discard
> Discard is an io.Writer on which all Write calls succeed without doing
> anything.
>
> Deprecated: As of Go 1.16, this value is simply io.Discard.
log.SetOutput(io.Discard)
答案2
得分: 41
要完全禁用日志,最好调用log.SetFlags(0)
并将输出设置为一个无操作的io.Writer
(即log.SetOutput(ioutil.Discard)
)。
但即使这样,操作仍会在[500-600 ns/op][2a]之间空闲<sup>1</sup>。
通过使用自定义的Logger
实现,并将所有函数实现为无操作,可以将其缩短到约100 ns/op,如此处所示(仅为了简洁起见,只覆盖Println
)。
所有这些的替代方法是使用具有级别的自定义日志框架,并将其设置为完全关闭。
请注意,其中一个常用的日志库([logrus][3])存在[性能问题][4],在[基准测试][6]中,它的性能为_3K+ ns/op_。
偏见观点:从基准测试中可以看出,当将Level
设置为-1
时,库[go-logging][5]的性能与自定义的Logger
实现相当,无论后端和格式如何
(基准测试源代码可以在[这里][6]找到)
基准测试的输出如下:
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
<sup>#1:YMMV,在i7-4500U CPU @ 1.80GHz上进行了测试</sup>
[1]:https://stackoverflow.com/questions/10571182/go-disable-a-log-logger#comment43485550_10688098
[2a]:https://gist.github.com/Avinash-Bhat/48c4f06b0cc840d9fd6c#file-log_test-go "YMMV, tested on i7-4500U CPU @ 1.80GHz"
[2b]:https://gist.github.com/Avinash-Bhat/48c4f06b0cc840d9fd6c#file-log_test-go "benchmark for package log"
[3]:https://github.com/Sirupsen/logrus
[4]:https://github.com/Sirupsen/logrus/issues/125 "Issue #125"
[5]:https://github.com/op/go-logging
[6]:https://gist.github.com/Avinash-Bhat/48c4f06b0cc840d9fd6c "Gist"
英文:
For completely disabling logs, it's actually better to call log.SetFlags(0)
<sup>[Joril][1]</sup> and set the output to a no-op io.Writer
(i.e., log.SetOutput(ioutil.Discard)
)
But even after this, the operations will idle around [500-600 ns/op][2a]<sup>1</sup>
This can still be cut short (to around 100 ns/op) by using a custom Logger
implementation, and implementing all the functions to be no-op -- as demonstrated [here][2b] (only overriding Println
for bervity).
The alternative to all these is to use a custom logging framework with levels and set it to complete OFF.
Note though, one of the commonly used library for logging ([logrus][3]) has [performance implications][4] -- the same can be found in the [benchmarks][6] where it perform with 3K+ ns/op, regardless.
Biased opinion: from the benchmarks, the library [go-logging][5] performs in par with the custom Logger
implementation when setting the Level
to -1
, regardless of the backend and formatting
(the benchmark source can be found [here][6])
the output of the benchmark is as follows:
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
<sup>#1: YMMV, tested on i7-4500U CPU @ 1.80GHz</sup>
[1]:https://stackoverflow.com/questions/10571182/go-disable-a-log-logger#comment43485550_10688098
[2a]:https://gist.github.com/Avinash-Bhat/48c4f06b0cc840d9fd6c#file-log_test-go "YMMV, tested on i7-4500U CPU @ 1.80GHz"
[2b]:https://gist.github.com/Avinash-Bhat/48c4f06b0cc840d9fd6c#file-log_test-go "benchmark for package log"
[3]:https://github.com/Sirupsen/logrus
[4]:https://github.com/Sirupsen/logrus/issues/125 "Issue #125"
[5]:https://github.com/op/go-logging
[6]:https://gist.github.com/Avinash-Bhat/48c4f06b0cc840d9fd6c "Gist"
答案3
得分: 6
type NullWriter int
func (NullWriter) Write([]byte) (int, error) { return 0, nil }
// ...
log.SetOutput(new(NullWriter))
英文:
type NullWriter int
func (NullWriter) Write([]byte) (int, error) { return 0, nil }
// ...
log.SetOutput(new(NullWriter))
答案4
得分: 3
这种方法允许您在运行时打开和关闭日志记录:
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
}
<sub>其中some.Constant
可以是在编译之前设置的常量(生成一个“生产”二进制文件),或者是在运行程序时通过命令行标志设置的变量(类似于myprogram --enable-logging=true
)</sub>
使用这两种方法,您几乎可以完全不改动您当前的代码。
英文:
This approach allows you to turn logging on and off at runtime:
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
}
And this approach enables or disables logging for the entire runtime:
type LogWriter struct{}
func (l *LogWriter) Write([]byte) (int, error) {
if some.Constant {
//...
}
return 0, nil
}
<sub>Where some.Constant
would be either a constant that you set before compiling (producing a "production" binary) or a variable that is set only once when running the program via command-line flags (something like myprogram --enable-logging=true
)</sub>
With both approaches you can leave your current code almost entirely untouched.
答案5
得分: 2
由于SetOutput()
仅适用于全局记录器,对于其他记录器来说,自定义的写入器仍然很方便。编写一个简短的写入器的方法如下:
type LogWriter struct{ io.Writer }
func (w *LogWriter) Enable() { w.Writer = os.Stdout }
func (w *LogWriter) Disable() { w.Writer = ioutil.Discard }
英文:
Since SetOutput()
is only defined for the global logger, a custom writer is still handy for other loggers. A short way of writing one is like this:
type LogWriter struct{ io.Writer }
func (w *LogWriter) Enable() { w.Writer = os.Stdout }
func (w *LogWriter) Disable() { w.Writer = ioutil.Discard }
答案6
得分: 0
一个给其他人的提示,如果你来到这里寻找日志记录和其他日志设施的话:可以看一下log4go包,它涵盖了关闭日志记录、设置日志级别、日志轮转、重定向到文件等功能,可能会很有用。
请参阅文档:http://godoc.org/code.google.com/p/log4go
英文:
A note for others coming here looking for this and other logging facilities: have a look at the log4go package as that covers turning off logging, setting log levels, log rotation, redirection to a file etc which might be useful.
See the doc at http://godoc.org/code.google.com/p/log4go
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论