I\xe2\x80\x99m 尝试构建一个自定义记录器,将日志消息保持在缓冲区中的错误级别以下,并仅在遇到错误后刷新缓冲区。
\n问题是我不\xe2\x80\x99不知道在遇到错误时如何触发将日志刷新到输出(同步方法)。
\n下面的代码是这样做的尝试:
\nfunc CustomLogger() {\n // First, define our level-handling logic.\n lowPriority := zap.LevelEnablerFunc(func(lvl zapcore.Level) bool {\n return lvl < activationLevel\n })\n //define the output of the logs\n customWriteSyncer := Buffer(os.Stdout)\n\n consoleEncoder := zapcore.NewConsoleEncoder(zap.NewDevelopmentEncoderConfig())\n zapcore.NewJSONEncoder(zap.NewProductionEncoderConfig())\n\n //creates a Core that writes logs to a WriteSyncer\n core := zapcore.NewCore(consoleEncoder, customWriteSyncer, lowPriority)\n\n logger := zap.New(core)\n\n defer logger.Sync()\n \n Logger = logger\n}\n\ntype BufferWriterSync struct {\n buf *bufio.Writer\n}\n\nfunc Buffer(ws zapcore.WriteSyncer) zapcore.WriteSyncer {\n bw := &BufferWriterSync{\n buf: bufio.NewWriter(ws),\n }\n ws = zapcore.Lock(bw)\n return ws\n}\n// Sync syncs data to output\nfunc (w BufferWriterSync) Sync() error {\n return w.buf.Flush()\n}\n// Write writes data to buffer\nfunc (w BufferWriterSync) Write(p []byte) (int, error) {\n return w.buf.Write(p)\n} \n\n
Run Code Online (Sandbox Code Playgroud)\n例如,执行时:
\nlogger.Info("some Info message")
该消息最终出现在 bufio.Writer 的缓冲区中,并且不显示 Info 消息
logger.Info("some Info message2")
该消息最终出现在 bufio.Writer 的缓冲区中,并且不显示 Info 消息
logger.Error("some Error message")
仅当遇到错误记录时,所有来自缓冲的累积日志都必须刷新到输出,根据上面的代码示例,它应该转到os.Stdout
预期输出:
\nsome Info message\nsome Info message2\nsome Error message\n
Run Code Online (Sandbox Code Playgroud)\n注意:\n我试图实现的功能类似于Php Symfony 框架中存在的Fingers_crossed功能。
\n总的来说,我认为这不是一个好主意。如果您的应用程序从未出现错误,理论上您的缓冲区可能会无限增长。这就是为什么 Zap 自己的刷新BufferedWriteSyncer
具有基于大小或基于计时器的刷新:您必须确定性地清除缓冲区。然而:
要仅打印特定级别的日志,您可以使用以下命令轻松创建自定义核心zap.NewAtomicLevelAt()
:
core := zapcore.NewCore(
zapcore.NewJSONEncoder(zap.NewProductionEncoderConfig()),
os.Stdout,
zap.LevelEnablerFunc(func(level zapcore.Level) bool {
return level == zapcore.ErrorLevel
}),
)
logger := zap.New(core)
logger.Info("bar") // not logged
logger.Error("baz") // logged
Run Code Online (Sandbox Code Playgroud)
当然,这对于其他日志级别也同样有效。
正如我上面所说,您应该支持确定性刷新逻辑。无论如何,如果您可以证明您的缓冲区最终会被清除,那么出于完整性考虑,以下是一个可行的解决方案。这有点尴尬,因为据我所知,没有(合理的)方法可以从zapcore.WriteSyncer
.
您必须创建一个自定义核心并实现缓冲。这个想法是将 a 嵌入zapcore.Encoder
到您的自定义结构中并Encoder.EncodeEntry
使用缓冲逻辑来实现。以下是一个演示程序(它并不意味着线程安全、内存高效等......):
// struct to "remember" buffered entries
type log struct {
entry zapcore.Entry
fields []zapcore.Field
}
// custom encoder
type bufferEncoder struct {
// embeds a zapcore encoder
zapcore.Encoder
// the entry buffer itself
buffer []*log
// the buffer pool, to return encoded entries
pool buffer.Pool
}
func (b *bufferEncoder) EncodeEntry(entry zapcore.Entry, fields []zapcore.Field) (*buffer.Buffer, error) {
// buffer entries
b.buffer = append(b.buffer, &log{entry, fields})
// return an empty buffer if the level is not error
if entry.Level != zap.ErrorLevel {
return b.pool.Get(), nil
}
// new buffer
buf := b.pool.Get()
for _, log := range b.buffer {
// encode buffered entries and append them to buf
encoded, err := b.Encoder.EncodeEntry(log.entry, log.fields)
if err != nil {
return nil, err
}
buf.AppendString(encoded.String())
}
// reset the buffer before returning
b.buffer = nil
return buf, nil
}
func main() {
enc := &bufferEncoder{
Encoder: zapcore.NewJSONEncoder(zap.NewProductionEncoderConfig()),
pool: buffer.NewPool(),
}
core := zapcore.NewCore(enc, os.Stdout, zap.NewAtomicLevelAt(zap.InfoLevel))
logger := zap.New(core)
logger.Info("info")
fmt.Println("buffered info")
time.Sleep(500 * time.Millisecond)
logger.Warn("warn")
fmt.Println("buffered warn")
time.Sleep(500 * time.Millisecond)
logger.Error("error")
fmt.Println("flushed")
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
5825 次 |
最近记录: |