In many Go language projects, we need a good logger that provides the following functions:
- Ability to log events into files instead of the application console;
- Log cutting - Ability to cut log files according to file size, time or interval, etc.;
- Supports different log levels. For example, INFO, DEBUG, ERROR, etc.;
- Able to print basic information, such as call file/function name and line number, log time, etc.;
- Log rating: Debug, Info, Warn, Error, DPanic, Panic, Fatal, etc.
- Log record structure: log content records are structured, such as json format output
- Custom format: Users can customize the output log format
- Custom public fields: Users can customize public fields, and the log content output by everyone shares these fields together
- Debugging: You can print file name, function name, line number, log time, etc., which is convenient for debugging programs.
- Custom call stack level: Its call stack information can be output according to the log level
- Namespace: Log namespace. After defining the namespace, all log contents are in this namespace. The namespace is equivalent to a folder
- Support hook operation
Install
go get -u /zap
Basic use
package main import "/zap" var logger * func main() { logger, _ = () // Use the production environment // logger, _ := () // Use the development environment defer () // Refresh the cache suger := () // Turn on log syntax sugar ("I'm a Debug-level log") ("I'm a Debug-level log", "key1", "value1", "key2", "value2") ("I'm a log %s at the Debug level", "value") ("I'm a Warn level log") ("I'm a Warn level log", "key1", "value1", "key2", "value2") ("I'm a Warn level log %s", "value") ("I'm an Info-level log") ("I'm an Info-level log", "key1", "value1", "key2", "value2") ("I'm an Info-level log %s", "info") ("I'm an Error level log") ("I'm an Error level log", "key1", "value1", "key2", "value2") ("I'm an Error level log %s", "value") ("I'm a Panic level log") ("I'm a Panic level log", "key1", "value1", "key2", "value2") ("I'm a Panic level log %s", "value") // Use logs without syntax sugar ("I'm a Debug-level log", ("key", "value"), ("num", 10)) ("I'm a Warn level log", ("key", "value"), ("num", 10)) ("I'm an Info-level log", ("key", "value"), ("num", 10)) ("I'm an Error level log", ("key", "value"), ("num", 10)) ("I'm a Panic level log", ("key", "value"), ("num", 10)) }
NewExample/NewDevelopment/NewProduction
zap provides us with three ways to quickly create loggers:()
,()
,()
Example is generally used in test code, Development is used in development environment, Production is used in generation environment
NewExample() use
NewExample builds a logger specifically for testing examples in zap. It outputs DebugLevel and above logs in JSON format standard output, but it omits timestamps and calls functions to keep the example output short and deterministic
Because in this method, zap has defined the default value of the log configuration item
// /uber-go/zap/blob/v1.24.0/#L127 func NewExample(options ...Option) *Logger { encoderCfg := { MessageKey: "msg", // Log content key:val, the previous key is set to msg LevelKey: "level", // Set the log level key to level NameKey: "logger", // Log name EncodeLevel: , //Log level, default lowercase EncodeTime: zapcore.ISO8601TimeEncoder, // Log time EncodeDuration: , } core := ((encoderCfg), , DebugLevel) return New(core).WithOptions(options...) }
Use Example
package main import ( "/zap" ) func main() { logger := () ("this is debug message") }
NewDevelopment() use
NewDevelopment() builds a development logger
Use Example
package main import ( "time" "/zap" ) func main() { logger, _ := () defer () ("failed to fetch url", // Strongly typed fields ("url", ""), ("attempt", 3), ("duration", ), ) ( // Strongly typed fields ("url", ""), ("attempt", 4), ("duration", *5), ).Info("[With] failed to fetch url") }
NewProduction() use
NewProduction() builds a reasonable Prouction logger that writes info and above log content into standard errors in JSON format
Use Example
package main import ( "time" "/zap" ) func main() { logger, _ := () defer () url := "" sugar := () ("failed to fetch URL", "url", url, "attempt", 3, "time", , ) ("Failed to fetch URL: %s", url) // Or more concise Sugar() // sugar := ().Sugar() // defer () }
Incoming configuration items
Among these 3 functions, some configuration items can be passed in.
func NewExample(options …Option) *Logger
package main import ( "os" "/zap" "/zap/zapcore" ) func main() { encoder := (()) file, _ := ("./", os.O_CREATE|os.O_APPEND|os.O_RDWR, ) syncFile := (file) syncConsole := () sync := (syncConsole, syncFile) core := (encoder, sync, ) logger := (core) ("info log", ("line", 1)) }
() Add callback function
The Hook (hook function) callback function provides a simple method for users to run this callback function after each log content is recorded to perform the operations required by the user. That is to say, after recording the log, you can call this function
package main import ( "fmt" "/zap" "/zap/zapcore" ) func main() { logger := ((func(entry ) error { ("[]test Hooks") return nil })) defer () ("test output") ("warn info") }
Custom configuration items
The easiest way to quickly build a logger logger is to predefined the configuration using zap:NewExample(), NewProduction()
andNewDevelopment()
These 3 methods can build a logger with a single function call, or can be configured simply
Config configuration item source code
// zap v1.24.0 type Config struct { // Dynamically change the log level, you can safely change the log level at runtime Level AtomicLevel `json:"level" yaml:"level"` // Set the logger to development mode, logs at WarnLevel and above levels will contain stack trace information Development bool `json:"development" yaml:"development"` // Stop calling the function in the log DisableCaller bool `json:"disableCaller" yaml:"disableCaller"` // Automatic stack trace is completely prohibited. By default, in development, the log levels of warnlevel and above will automatically capture stack trace information. // In production, ErrorLevel and above will also automatically capture stack information DisableStacktrace bool `json:"disableStacktrace" yaml:"disableStacktrace"` // Set the sampling policy. No SamplingConfing will prohibit sampling Sampling *SamplingConfig `json:"sampling" yaml:"sampling"` // Set log encoding. Can be set to console and json. You can also set the third-party encoding format through RegisterEncoder Encoding string `json:"encoding" yaml:"encoding"` // Set options for encoder encoder. Detailed settings information is EncoderConfig `json:"encoderConfig" yaml:"encoderConfig"` // The log output address can be one URLs address or file path, and multiple OutputPaths []string `json:"outputPaths" yaml:"outputPaths"` // Error log output address. The default output standard error message ErrorOutputPaths []string `json:"errorOutputPaths" yaml:"errorOutputPaths"` // You can add custom field information to the root logger. That is, each log will carry these field information, public fields InitialFields map[string]interface{} `json:"initialFields" yaml:"initialFields"` }
EncoderConfig structure source code, it also has many configuration options
// [email protected] type EncoderConfig struct { // Set key for log entry. If the key is empty, this part of the information in the log will also be omitted MessageKey string `json:"messageKey" yaml:"messageKey"`//The healthy name of the log information is msg by default LevelKey string `json:"levelKey" yaml:"levelKey"`//The log-level healthy name is level by default TimeKey string `json:"timeKey" yaml:"timeKey"`//The healthy name for recording log time, default is time 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"` // Some settings for log encoding 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 other encoders, this encoder is optional EncodeName NameEncoder `json:"nameEncoder" yaml:"nameEncoder"` // Configure the interface{} type encoder. If not set, it will be encoded with NewReflectedEncoder func() ReflectedEncoder `json:"-" yaml:"-"` // Configure the field separator in console. Use tab by default ConsoleSeparator string `json:"consoleSeparator" yaml:"consoleSeparator"` } type Entry struct { Level Level Time LoggerName string Message string Caller EntryCaller Stack string }zap Provided 2 Logger:`SugaredLogger` and `Logger`
SugaredLogger Log
When performance is required but not very important, using SugaredLogger is more appropriate. It is 4-10 times faster than other structured log packages, including structured logs and printf-style APIs
Use: suger.[log level]x
w Support key-value pairing to pass into logs
f supports %s interpolation
suger := () // Turn on log syntax sugar ("I'm a Debug-level log") ("I'm a Debug-level log", "key1", "value1", "key2", "value2") ("I'm a log %s at the Debug level", "value") ("I'm a Warn level log") ("I'm a Warn level log", "key1", "value1", "key2", "value2") ("I'm a Warn level log %s", "value") ("I'm an Info-level log") ("I'm an Info-level log", "key1", "value1", "key2", "value2") ("I'm an Info-level log %s", "info") ("I'm an Error level log") ("I'm an Error level log", "key1", "value1", "key2", "value2") ("I'm an Error level log %s", "value") ("I'm a Panic level log") ("I'm a Panic level log", "key1", "value1", "key2", "value2") ("I'm a Panic level log %s", "value")
logger log
Use Logger when performance and type safety are important. It is faster than SugaredLogger and allocates fewer resources, but it only supports structured logs and strongly typed fields
The first parameter prints the log name, and the variable parameters are passed in the following. … type
("key", "value") indicates the map with the key as a string value as a string
("I'm a Debug-level log", ("key", "value"), ("num", 10)) ("I'm a Warn level log", ("key", "value"), ("num", 10)) ("I'm an Info-level log", ("key", "value"), ("num", 10)) ("I'm an Error level log", ("key", "value"), ("num", 10)) ("I'm a Panic level log", ("key", "value"), ("num", 10))
Output log to file
cfg := () = []string{ "./", "stderr", "stdout", } logger, _ = () ("Print log to file")
Log Cutting Archive
lumberjackThis library cuts log files according to the log size.
go get -u /natefinch/lumberjack@v2
(&{ Filename: "/var/log/myapp/", // File location MaxSize: 500, // megabytes, M is the unit. After reaching this setting, log cutting is performed MaxBackups: 3, // Keep the maximum number of old files MaxAge: 28, //days, the maximum number of days for old files to be saved Compress: true, // disabled by default, whether to compress log archives, default not to compress})
Refer to its documentation and combine the above custom configuration
package main import ( "fmt" "/zap" "/zap/zapcore" "/natefinch/lumberjack.v2" ) func main() { lumberjacklogger := &{ Filename: "./", MaxSize: 1, // megabytes MaxBackups: 3, MaxAge: 28, //days Compress: true, // disabled by default } defer () config := () = zapcore.ISO8601TimeEncoder // Set time format fileEncoder := (config) core := ( fileEncoder, //Encoding settings (lumberjacklogger), //Output to file , //Log level ) logger := (core) defer () // Test segmentation log for i := 0; i < 8000; i++ { ( ("url", ("%", i)), ("name", "jimmmyr"), ("age", 23), ("agradege", "no111-000222"), ).Info("test info ") } }
Global logger
zap provides 2 types of global loggers, one is to call () to get;
Another one is to call () to get
If you call () or () directly to record the log, it will not record any log information. The ReplaceGlobals() function needs to be called to set it to the global Logger.
ReplaceGlobals replaces global Logger and SugaredLogger and returns a function to restore the original value
Simple use examples
package main import ( "/zap" ) func main() { // Direct calls will not record log information, so the following log information will not be output ().Info("no log info") ().Info("no log info [sugared]") logger := () defer () (logger) // Global logger, () and () need to call the ReplaceGlobals function to record log information ().Info("log info") ().Info("log info [sugared]") }
This is the end of this article about the implementation example of golang integrated log zap. For more related golang integrated log zap content, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!