在zap日志库中,zapcore给我们提供了2种CallEncoder, 即 zapcore.FullCallerEncoder 和 zapcore.ShortCallerEncoder 但是这2种都不符合我们的要求:
原有方式的不足
zapcore.FullCallerEncoder 将每个caller的完整路径都进行了记录,从而导致大量的重复的路径记录在日志中,主要是当前项目的完整路径。
而zapcore.ShortCallerEncoder这个方式都所有的caller都只记录简短的路径, 这样导致我们很多的路径无法进行快速定位。
要求:我们希望对于当前项目的caller, 我们只记录相对路径即可,其他记录完整路径。
对于这个需求,我们就只能通过自定义的方式来完成。 要自定义,我们需要首先了解一下这个 EncoderConfig配置信息。
EncoderConfig参考
// An EncoderConfig allows users to configure the concrete encoders supplied by
// zapcore.
type EncoderConfig struct {
// Set the keys used for each log entry. If any key is empty, that portion
// of the entry is omitted.
MessageKey string `json:"messageKey" yaml:"messageKey"`
LevelKey string `json:"levelKey" yaml:"levelKey"`
TimeKey string `json:"timeKey" yaml:"timeKey"`
NameKey string `json:"nameKey" yaml:"nameKey"`
CallerKey string `json:"callerKey" yaml:"callerKey"`
FunctionKey string `json:"functionKey" yaml:"functionKey"`
StacktraceKey string `json:"stacktraceKey" yaml:"stacktraceKey"`
SkipLineEnding bool `json:"skipLineEnding" yaml:"skipLineEnding"`
LineEnding string `json:"lineEnding" yaml:"lineEnding"`
// Configure the primitive representations of common complex types. For
// example, some users may want all time.Times serialized as floating-point
// seconds since epoch, while others may prefer ISO8601 strings.
EncodeLevel LevelEncoder `json:"levelEncoder" yaml:"levelEncoder"`
EncodeTime TimeEncoder `json:"timeEncoder" yaml:"timeEncoder"`
EncodeDuration DurationEncoder `json:"durationEncoder" yaml:"durationEncoder"`
EncodeCaller CallerEncoder `json:"callerEncoder" yaml:"callerEncoder"`
// Unlike the other primitive type encoders, EncodeName is optional. The
// zero value falls back to FullNameEncoder.
EncodeName NameEncoder `json:"nameEncoder" yaml:"nameEncoder"`
// Configure the encoder for interface{} type objects.
// If not provided, objects are encoded using json.Encoder
NewReflectedEncoder func(io.Writer) ReflectedEncoder `json:"-" yaml:"-"`
// Configures the field separator used by the console encoder. Defaults
// to tab.
ConsoleSeparator string `json:"consoleSeparator" yaml:"consoleSeparator"`
}
自定义EncodeCaller
从上面的配置中我们可以得知, 这个EncodeCaller他实际上是一个函数定义 type CallerEncoder func(EntryCaller, PrimitiveArrayEncoder) 如下图所示:
我们要自定义这个EncodeCaller实际上就是定义这样一个函数即可。
定义方式如下:
即在我们初始化配置对象的时候对这个EncodeCaller定义一个函数即可,这样每次在zap执行的时候就会调用我们定义的这个函数。 即,如下示例
EncodeCaller: func(caller zapcore.EntryCaller, enc zapcore.PrimitiveArrayEncoder) {
// 这里将路径的前缀即当前项目的路径去除 其他路径保持完整路径
ctrimPaht := TrimAppPath(caller.FullPath())
enc.AppendString(fmt.Sprintf("%v%v", c.Prefix, ctrimPaht))
},
在这个函数里面我们就可以对这个Encoder进行自定义的操作了。
获取当前项目路径函数 GetAppPath
// 获取当前app的运行路径 如: /opt/app/gotms
func GetAppPath() string {
var appPath string
if exeFile, err := os.Executable();err==nil {
appPath=filepath.Dir(exeFile)
}else{
appPath,_=os.Getwd()
}
return appPath
}
// 去除当前app的路径 如果包含, 否则原样返回
func TrimAppPath(inPath string) string {
if path, ok := strings.CutPrefix(inPath, GetAppPath()); ok {
return path
}
return inPath
}