Uber Zap Logger:如何在每个日志条目前加上一个字符串
Uber Zap Logger: how to prepend every log entry with a string
我正在将我的应用程序用作 SystemD 服务,并且需要在每条消息前加上 JournalD 的入口级别 <LEVEL>
,例如:
<6> this is info
<7> this is debug
<4> this is warning
否则,JournalD 会将所有条目视为同一级别,我想使用其高级功能来仅显示特定级别的日志。
如何使用 uber-zap 库在每个日志条目前加上正确的级别标签(例如 Info 它将是 <6>
)?
编辑:这是我的记录器配置的相关部分:
var config zap.Config
if production {
config = zap.NewProductionConfig()
config.Encoding = `console`
config.EncoderConfig.TimeKey = "" // no time as SystemD adds timestamp
} else {
config = zap.NewDevelopmentConfig()
}
config.DisableStacktrace = true
config.EncoderConfig.EncodeLevel = zapcore.CapitalColorLevelEncoder // colors
config.OutputPaths = []string{"stdout"}
您可以使用嵌入 zapcore.Encoder
.
的自定义编码器
嵌入编码器使您可以使用与现在相同的配置“免费”实现所有方法。然后你可以只实现 EncodeEntry
和你需要的额外逻辑。
注意: 如果您打算使用结构化日志记录,您仍然需要实施 Clone()
,例如logger.With()
。更多信息:
回到你的主要问题,这是一个有效的例子;请参阅代码中的注释以获取更多解释:
type prependEncoder struct {
// embed a zapcore encoder
// this makes prependEncoder implement the interface without extra work
zapcore.Encoder
// zap buffer pool
pool buffer.Pool
}
// implementing only EncodeEntry
func (e *prependEncoder) EncodeEntry(entry zapcore.Entry, fields []zapcore.Field) (*buffer.Buffer, error) {
// new log buffer
buf := e.pool.Get()
// prepend the JournalD prefix based on the entry level
buf.AppendString(e.toJournaldPrefix(entry.Level))
buf.AppendString(" ")
// calling the embedded encoder's EncodeEntry to keep the original encoding format
consolebuf, err := e.Encoder.EncodeEntry(entry, fields)
if err != nil {
return nil, err
}
// just write the output into your own buffer
_, err = buf.Write(consolebuf.Bytes())
if err != nil {
return nil, err
}
return buf, nil
}
// some mapper function
func (e *prependEncoder) toJournaldPrefix(lvl zapcore.Level) string {
switch lvl {
case zapcore.DebugLevel:
return "<7>"
case zapcore.InfoLevel:
return "<6>"
case zapcore.WarnLevel:
return "<4>"
}
return ""
}
稍后您将构建一个带有自定义核心的记录器,该核心使用自定义编码器。您使用您现在使用的相同编码器初始化嵌入字段。您在下面看到的选项模仿您当前拥有的选项。
package main
import (
"go.uber.org/zap"
"go.uber.org/zap/buffer"
"go.uber.org/zap/zapcore"
"os"
)
func getConfig() zap.Config {
// your current config options
return config
}
func main() {
cfg := getConfig()
// constructing our prependEncoder with a ConsoleEncoder using your original configs
enc := &prependEncoder{
Encoder: zapcore.NewConsoleEncoder(cfg.EncoderConfig),
pool: buffer.NewPool(),
}
logger := zap.New(
zapcore.NewCore(
enc,
os.Stdout,
zapcore.DebugLevel,
),
// this mimics the behavior of NewProductionConfig.Build
zap.ErrorOutput(os.Stderr),
)
logger.Info("this is info")
logger.Debug("this is debug")
logger.Warn("this is warn")
}
测试 运行 输出(根据您的 zapcore.CapitalColorLevelEncoder
,INFO 以蓝色打印,DEBUG 以粉红色打印,WARN 以黄色打印):
<6> INFO this is info
<7> DEBUG this is debug
<4> WARN this is warn
我正在将我的应用程序用作 SystemD 服务,并且需要在每条消息前加上 JournalD 的入口级别 <LEVEL>
,例如:
<6> this is info
<7> this is debug
<4> this is warning
否则,JournalD 会将所有条目视为同一级别,我想使用其高级功能来仅显示特定级别的日志。
如何使用 uber-zap 库在每个日志条目前加上正确的级别标签(例如 Info 它将是 <6>
)?
编辑:这是我的记录器配置的相关部分:
var config zap.Config
if production {
config = zap.NewProductionConfig()
config.Encoding = `console`
config.EncoderConfig.TimeKey = "" // no time as SystemD adds timestamp
} else {
config = zap.NewDevelopmentConfig()
}
config.DisableStacktrace = true
config.EncoderConfig.EncodeLevel = zapcore.CapitalColorLevelEncoder // colors
config.OutputPaths = []string{"stdout"}
您可以使用嵌入 zapcore.Encoder
.
嵌入编码器使您可以使用与现在相同的配置“免费”实现所有方法。然后你可以只实现 EncodeEntry
和你需要的额外逻辑。
注意: 如果您打算使用结构化日志记录,您仍然需要实施 Clone()
,例如logger.With()
。更多信息:
回到你的主要问题,这是一个有效的例子;请参阅代码中的注释以获取更多解释:
type prependEncoder struct {
// embed a zapcore encoder
// this makes prependEncoder implement the interface without extra work
zapcore.Encoder
// zap buffer pool
pool buffer.Pool
}
// implementing only EncodeEntry
func (e *prependEncoder) EncodeEntry(entry zapcore.Entry, fields []zapcore.Field) (*buffer.Buffer, error) {
// new log buffer
buf := e.pool.Get()
// prepend the JournalD prefix based on the entry level
buf.AppendString(e.toJournaldPrefix(entry.Level))
buf.AppendString(" ")
// calling the embedded encoder's EncodeEntry to keep the original encoding format
consolebuf, err := e.Encoder.EncodeEntry(entry, fields)
if err != nil {
return nil, err
}
// just write the output into your own buffer
_, err = buf.Write(consolebuf.Bytes())
if err != nil {
return nil, err
}
return buf, nil
}
// some mapper function
func (e *prependEncoder) toJournaldPrefix(lvl zapcore.Level) string {
switch lvl {
case zapcore.DebugLevel:
return "<7>"
case zapcore.InfoLevel:
return "<6>"
case zapcore.WarnLevel:
return "<4>"
}
return ""
}
稍后您将构建一个带有自定义核心的记录器,该核心使用自定义编码器。您使用您现在使用的相同编码器初始化嵌入字段。您在下面看到的选项模仿您当前拥有的选项。
package main
import (
"go.uber.org/zap"
"go.uber.org/zap/buffer"
"go.uber.org/zap/zapcore"
"os"
)
func getConfig() zap.Config {
// your current config options
return config
}
func main() {
cfg := getConfig()
// constructing our prependEncoder with a ConsoleEncoder using your original configs
enc := &prependEncoder{
Encoder: zapcore.NewConsoleEncoder(cfg.EncoderConfig),
pool: buffer.NewPool(),
}
logger := zap.New(
zapcore.NewCore(
enc,
os.Stdout,
zapcore.DebugLevel,
),
// this mimics the behavior of NewProductionConfig.Build
zap.ErrorOutput(os.Stderr),
)
logger.Info("this is info")
logger.Debug("this is debug")
logger.Warn("this is warn")
}
测试 运行 输出(根据您的 zapcore.CapitalColorLevelEncoder
,INFO 以蓝色打印,DEBUG 以粉红色打印,WARN 以黄色打印):
<6> INFO this is info
<7> DEBUG this is debug
<4> WARN this is warn