日志Logger结构体,以此调用打印日志内容,定义如下:
``` type Logger struct { core zapcore.Core
development bool name string errorOutput zapcore.WriteSyncer addCaller bool addStack zapcore.LevelEnabler callerSkip int
} ```
日志主体内容结构体,表示一条具体日志,定义如下:
type Entry struct {
Level Level
Time time.Time
LoggerName string
Message string
Caller EntryCaller
Stack string
}
经过检查之后的日志内容结构体,cores带有具体的打印方式,定义如下:
type CheckedEntry struct {
Entry
ErrorOutput WriteSyncer
dirty bool // best-effort detection of pool misuse
should CheckWriteAction
cores []Core
}
CheckedEntry嵌套了Entry,并保存core对象
CheckedEntry的Write方法:(ce *CheckedEntry) Write(fields ...Field)
Write方法中的fields是zap的Field对象参数,一起添加打印到结构化的日志中
Core定义了一个Logger实现日志具体要如何打印的一系列接口,其中的LevelEnabler也是一个接口,定义如下:
``` type Core interface { LevelEnabler
With([]Field) Core Check(Entry, *CheckedEntry) *CheckedEntry Write(Entry, []Field) error Sync() error
}
type LevelEnabler interface { Enabled(Level) bool } ```
LevelEnabler
接口提供用于判断给定的日志级别是否应该打印该条日志的逻辑判断方法With
方法添加结构化的Field内容到Encoder对象中Check
方法通过LevelEnabler
接口中的Enabled
方法和其他逻辑判断传入的Entry
日志对象否应该被打印,如果应该则添加Core对象到CheckedEntry
的cores
中,此时Entry变为带有Core对象的CheckedEntry并返回CheckedEntry
,调用方必须在调用Write
方法前使用Check
方法Write
方法将日志对象Entry
和Fileds
写到具体实现的目的位置,在通过CheckedEntry中的Write方法完成日志打印时,CheckedEntry的Write方法中会遍历调用其所有的Core对象的Write方法(即当前这里的Write方法)Sync
方法,如果需要刷新日志缓冲区,在这儿实现通过zapcore.NewCore
可以创建一个Core对象ioCore
,方法定义:func NewCore(enc Encoder, ws WriteSyncer, enab LevelEnabler) Core
,需要传入Encoder
和WriteSyncer
和LevelEnabler
三个对象。
在zapcore
中提供了NewTee(cores ...Core) Core
方法可以把多个Core对象合并为一个Core,即将传入的Core对象添加到slice中,在为该slice对象实现Core接口的方法,合并后的Core对象在执行接口方法时,会遍历所有core对象的对应方法调用。
zap.Hooks
对core对象注册回调函数,通过RegisterHooks(core Core, hooks ...func(Entry) error) Core
注册hook方法来生成新的带有hooks方法的hooked
Core对象并在其Check方法中先对原始的core进行Check,然后添加到CheckedEntry
的cores列表,再将自己添加cores列表中,日志写入时除了原始的core的Write方法调用外,还会对hooked core的Write
方法会调用所有传入的hooks
回调函数。
zap.WrapCore
方法可以对Core做一次包装,并替换成WrapCore传入的方法所生成的Core对象
zapcore提供了NewCore
方法来创建core对象,创建logger的时候大部分是通过该方法来生成core对象。zapcore实现了ioCore
这个core对象
NewCore定义: NewCore(enc Encoder, ws WriteSyncer, enab LevelEnabler) Core
结构体定义:
type ioCore struct {
LevelEnabler
enc Encoder
out WriteSyncer
}
它实现了Core接口的所有方法,自定义Core可以参考或者复用这里的实现,
Check
方法通过ioCore
中LevelEnabler
接口的Enabled
方法判断日志Entry的Level是否使用被打印,可以打印则使用ioCore
对象和Entry
日志对象构成CheckedEntry
。
Write
方法中使用ioCore
中的Encoder
对日志Entry和Fields先进行Encoder
的EncodeEntry
处理,再使用WriteSyncer
中的Write
方法将Encode之后的内容进行写入。
With
方法调用时,会调用addFields
将Fields
添加到Encoder,对传入的Fields进行遍历调用Field的AddTo
方法,将传入的Field全部添加到Encoder的buffer中。
zapcore.Field
定义
type Field struct {
Key string
Type FieldType
Integer int64
String string
Interface interface{}
}
addFields方法定义: addFields(enc ObjectEncoder, fields []Field)
Encoder是一个数据编码接口,定义如下:
``` type Encoder interface { ObjectEncoder
Clone() Encoder EncodeEntry(Entry, []Field) (*buffer.Buffer, error)
} ```
每一个具体的Encoder实现都实现了ObjectEncoder
接口中的一系列根据具体数据类型进行Add或者Append的方法,根据field的具体数据类型构造一个buffer储存对应的数据格式,例如json_encoder在EncodeEntry方法中构造出对应的json格式保存在buffer中返回出来
zap提供了console
和json
两种Encoder,可以通过RegisterEncoder(name string, constructor func(zapcore.EncoderConfig) (zapcore.Encoder, error)) error
方法注册自己的Encoder构造函数,该函数通过EncoderConfig
参数生成对应的Encoder
,
EncoderConfig
结构体定义:
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"`
StacktraceKey string `json:"stacktraceKey" yaml:"stacktraceKey"`
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"`
}
WriteSyncer是一个带有Sync
方法的io.Writer
,定义如下:
type WriteSyncer interface {
io.Writer
Sync() error
}
这里的Sink
是一个包含了io.Closer
和WriteSyncer
接口的接口,
即Sink
也是一种WriteSyncer
,它是一个包含了io.Writer
、io.Closer
和Sync
方法的接口,定义如下:
type Sink interface {
zapcore.WriteSyncer
io.Closer
}
通过Sink
对象的Write
方法进行日志的具体输出。
在通过Config
的Build
方法创建Logger的时候,Build
方法通过buildEncoder
使用Config中的Encoding
名称获取到对应Encoder的构造函数,然后通过构造函数和配置项生成具体的Encoder
。同时会通过openSinks
方法生成WriteSyncer
,其中根据配置对象中的OutputPaths
参数通过Open
方法根据给定的输出位置生成各种对应的Sink
对象,用于日志的输出实现。
Open
方法会遍历所有给定的输出路径,根据每个路径使用newSink
创建出对应的WriteSyncer
即sink对象,然后通过CombineWriteSyncers
方法将所有sink对象合并为一个sink对象,即全部添加到slice中,该slice实现了WriteSyncer接口,Write
方法遍历调用全部WriteSyncer的Write方法写入日志。
newSink
方法在处理输出路径时的规则是按URL来解析,将解析出的scheme
作为key(xxx://yyy
中xxx就是对应的scheme)从一个map对象中取出对应的sink对象的factory
方法,然后使用该工厂方法生成对应的sink。
如果输出路径没有解析出url的scheme,则表示file
类型的sink,file
类型的sink是zap默认实现的sink对象,其中为判断文件路径,如果是特定的stdout
和stderr
则直接输出到终端而非文本文件。
如果需要自定义sink,可以使用RegisterSink(scheme string, factory func(*url.URL) (Sink, error)) error
方法注册自己实现的sink工厂方法,就可以通过OutputPaths
中的特定scheme
来获取对应的sink然后将日志输出到对应的位置。
Logger结构中包含了zapcore的Core接口对象,打印日志就是通过实现了Core接口的该对象完成的。
zap通过创建Logger结构体来打印日志,创建新Logger提供了以下方法:
New(core zapcore.Core, options ...Option) *Logger
New方法通过传入的Core接口对象和Options构造LoggerNewNop() *Logger
NewNop返回一个不会真正打印日志的loggerNewProduction(options ...Option) (*Logger, error)
NewProduction返回一个日志级别为Info,以json形式输出日志到stderr的LoggerNewDevelopment(options ...Option) (*Logger, error)
NewDevelopment返回一个日志级别为Level,以json形式输出日志到stderr的LoggerNewExample(options ...Option) *Logger
NewExample返回用于测试的Logger,缺少了一些字段并且以debug级别输出到stdout(cfg Config) Build(opts ...Option) (*Logger, error)
通过配置信息结构体的Build方法生成Logger然后通过NewCore
方法使用Encoder和WriteSyncer生成Core对象构造具体Logger
按日志级别提供了以下打印日志的方法:
(log *Logger) Debug(msg string, fields ...Field)
log *Logger) Info(msg string, fields ...Field)
log *Logger) Warn(msg string, fields ...Field)
(log *Logger) Error(msg string, fields ...Field)
(log *Logger) DPanic(msg string, fields ...Field)
(log *Logger) Panic(msg string, fields ...Field)
(log *Logger) Fatal(msg string, fields ...Field)
每个打印方法都会调用logger.go
中的check
方法完成打印日志。
打印日志方法中的check方法:(log *Logger) check(lvl zapcore.Level, msg string)
打印日志执行流程:通过调用Logger具体的打印日志方法每打一条日志都会调用check方法,check方法通过传入的lvl
和msg
参数构造zapcore.Entry
结构体,Entry即为要打印的日志信息对象,
然后通过Core接口
对象的Check
方法对该Entry
进行判断是否应该打印这条日志并把Core对象添加到CheckedEntry
中并返回,
再通过返回的CheckedEntry的Write
方法遍历调用CheckedEntry中所有添加的Core对象的Write方法写入msg
和Fields
完成实际的日志输出。
而Core对象的Write方法实际是调用的WriteSyncer/Sink
对象中的Write
方法完成输出。
网友51.*.*.5[火星]2022-05-26 23:10
网友185.*.*.12[火星]2022-05-26 23:09
网友185.*.*.38[火星]2022-05-26 22:25
网友40.*.*.46[美国]2022-05-26 22:14
发表评论
亲~ 评论内容是必须的哟! o(∩_∩)o
昵称
邮箱
主页
评论