Run the following command to install zap
go get -u /zap
Configure Zap Logger
Zap provides two types of loggers—Sugared Logger
andLogger
. In a context where performance is good but not very critical, useSugaredLogger
. It is 4-10 times faster than other structured logging packages and supports structured and printf-style logging. In the context where every microsecond and every memory allocation is important, useLogger
. It even comparesSugaredLogger
Faster and less memory allocation, but it only supports strongly typed structured logging.
Logger
- By calling
()
/()
or()
Create a Logger. - Each of the functions above will create a logger. The only difference is that the information it will record is different. For example, the production logger records the call function information, date and time by default.
- Call Info/Error, etc. through Logger.
- By default, logs are printed to the application's console interface.
package main import ( "/zap" "net/http" ) var logger * func main() { InitLogger() defer () simpleHttpGet("") simpleHttpGet("") } func InitLogger() { logger, _ = () } func simpleHttpGet(url string) { resp, err := (url) if err != nil { ( "Error fetching url..", ("url", url), (err)) } else { ("Success..", ("statusCode", ), ("url", url)) () } }
In the above code, we first create a Logger and then log the message using the Logger method such as Info/Error. The syntax of the logger method is as follows:
func (log *Logger) MethodXXX(msg string, fields ...Field)
inMethodXXX
is a variadic parameter function, which can be Info/Error/Debug/Panic, etc. Each method accepts a message string and any number ofField parameters. Each
In fact, it is a set of key-value pair parameters. We execute the above code and get the following output:
{"level":"error","ts":1585653856.0853302,"caller":"log_test/:21","msg":"Error fetching url..","url":"","error":"Get
: unsupported protocol scheme \"\"","stacktrace":"\n\tE:/DEV/Go/src//my_test/log_test/:21\nmai
\n\tE:/DEV/Go/src//my_test/log_test/:12\\n\tD:/software/Go/src/runtime/:203"}
{"level":"error","ts":1585653877.2866385,"caller":"log_test/:21","msg":"Error fetching url..","url":"","error":"Get
: dial tcp 31.13.84.1:80: connectex: A connection attempt failed because the connected party did not properly respond after
a period of time, or established connection failed because connected host has failed to respond.","stacktrace":"\n\tE:/DEV/Go
/src//my_test/log_test/:21\\n\tE:/DEV/Go/src//my_test/log_test/:13\\n\t
D:/software/Go/src/runtime/:203"}
Sugared Logger
Now let's use Sugared Logger to achieve the same functionality.
- Most implementations are basically the same.
- The only difference is that we call the main logger
. Sugar()
Method to get aSugaredLogger
。 - Then use
SugaredLogger
byprintf
Format record statement
The following is the use after modificationSugaredLogger
replaceLogger
Code:
package main import ( "/zap" "net/http" ) var sugarLogger * func main() { InitLogger() defer () simpleHttpGet("") simpleHttpGet("") } func InitLogger() { logger, _ := () sugarLogger = () } func simpleHttpGet(url string) { ("Trying to hit GET request for %s", url) resp, err := (url) if err != nil { ("Error fetching URL %s : Error = %s", url, err) } else { ("Success! statusCode = %s for URL %s", , url) () } }
When you execute the above code, you will get the following output:
{"level":"error","ts":1572159149.923002,"caller":"logic/:27","msg":"Error fetching URL : Error = Get : unsupported protocol scheme \"\"","stacktrace":"\n\t/Users/q1mi/zap_demo/logic/:27\\n\t/Users/q1mi/zap_demo/logic/:14\\n\t/usr/local/go/src/runtime/:203"}
{"level":"info","ts":1572159150.192585,"caller":"logic/:29","msg":"Success! statusCode = 200 OK for URL "}
You should notice that both loggers have printed out the JSON structure format so far.
Custom logger
Write logs to files instead of terminals
The first change we have to make is to write the logs to a file, rather than print them to the application console.
We will use(…)
Method to pass all configurations manually instead of using like()
Such a preset method to create a logger.
func New(core , options ...Option) *Logger
Three configurations are required—
Encoder
,WriteSyncer
,LogLevel
。
1、Encoder: Encoder (how to write to logs). We will use out of the boxNewJSONEncoder()
, and use pre-setProductionEncoderConfig()
。
(())
2、WriterSyncer: Specify where the log will be written. We use()
The function and pass the open file handle in.
func InitLogger() { writeSyncer := getLogWriter() encoder := getEncoder() core := (encoder, writeSyncer, ) logger := (core) sugarLogger = () } func getEncoder() { return (()) } func getLogWriter() { file, _ := ("./") return (file) }
3、Log Level: Which level of log will be written. We will modify the Logger code in the above section and rewrite itInitLogger()
method. The rest of the methods—main()
/SimpleHttpGet()
Stay unchanged.
func InitLogger() { writeSyncer := getLogWriter() encoder := getEncoder() core := (encoder, writeSyncer, ) logger := (core) sugarLogger = () } func getEncoder() { return (()) } func getLogWriter() { file, _ := ("./") return (file) }
When using these modified logger configurations, the above section is calledmain()
When the function is used, the following output will be printed in the file—middle.
{"level":"debug","ts":1572160754.994731,"msg":"Trying to hit GET request for "}
{"level":"error","ts":1572160754.994982,"msg":"Error fetching URL : Error = Get : unsupported protocol scheme \"\""}
{"level":"debug","ts":1572160754.994996,"msg":"Trying to hit GET request for "}
{"level":"info","ts":1572160757.3755069,"msg":"Success! statusCode = 200 OK for URL "}
Change JSON Encoder to normal Log Encoder
Now, we want to change the encoder from JSON Encoder to normal Encoder. To do this, we need toNewJSONEncoder()
Change toNewConsoleEncoder()
。
return (())
When using these modified logger configurations, the above section is calledmain()
When the function is used, the following output will be printed in the file—middle.
1.572161051846623e+09 debug Trying to hit GET request for
1.572161051846828e+09 error Error fetching URL : Error = Get : unsupported protocol scheme ""
1.5721610518468401e+09 debug Trying to hit GET request for
1.572161052068744e+09 info Success! statusCode = 200 OK for URL
Change the time encoding and add caller details
Given the changes we made to our configuration, there are two issues:
- Time is displayed in a non-human-readable way, for example 1.572161051846623e+09
- The details of the caller's function are not displayed in the log
The first thing we have to do is override the defaultProductionConfig()
, and make the following changes:
- Modify the time encoder
- Log levels using capital letters in log files
func getEncoder() { encoderConfig := () = zapcore.ISO8601TimeEncoder = return (encoderConfig) }
Next, we will modify the zap logger code to add the function to log the call function information into the log. To do this, we will(..)
Add one to the functionOption
。
logger := (core, ())
When using these modified logger configurations, the above section is calledmain()
When the function is used, the following output will be printed in the file—middle.
2019-10-27T15:33:29.855+0800 DEBUG logic/:47 Trying to hit GET request for
2019-10-27T15:33:29.855+0800 ERROR logic/:50 Error fetching URL : Error = Get : unsupported protocol scheme ""
2019-10-27T15:33:29.856+0800 DEBUG logic/:47 Trying to hit GET request for
2019-10-27T15:33:30.125+0800 INFO logic/:52 Success! statusCode = 200 OK for URL
Log Cutting Archives with Lumberjack
The only thing missing in this log program is the log cutting and archiving function.
Zap itself does not support cutting archive log files
To add log cutting archive function, we will use a third-party libraryLumberjackTo achieve it.
Install
Run the following command to install Lumberjack
go get -u /natefinch/lumberjack
Add Lumberjack to zap logger
To add Lumberjack support to zap, we need to modifyWriteSyncer
Code. We will modify it according to the following codegetLogWriter()
function:
func getLogWriter() { lumberJackLogger := &{ Filename: "./", MaxSize: 10, MaxBackups: 5, MaxAge: 30, Compress: false, } return (lumberJackLogger) }
Lumberjack Logger takes the following properties as input:
- Filename: The location of the log file
- MaxSize: Maximum size (in MB) of log file before cutting
- MaxBackups: The maximum number of old files preserved
- MaxAges: Maximum number of days to keep old files
- Compress: Whether to compress/archive old files
Test all functions
Finally, the complete sample code using the Zap/Lumberjack logger is as follows:
package main import ( "net/http" "/natefinch/lumberjack" "/zap" "/zap/zapcore" ) var sugarLogger * func main() { InitLogger() defer () simpleHttpGet("") simpleHttpGet("") } func InitLogger() { writeSyncer := getLogWriter() encoder := getEncoder() core := (encoder, writeSyncer, ) logger := (core, ()) sugarLogger = () } func getEncoder() { encoderConfig := () = zapcore.ISO8601TimeEncoder = return (encoderConfig) } func getLogWriter() { lumberJackLogger := &{ Filename: "./", MaxSize: 1, MaxBackups: 5, MaxAge: 30, Compress: false, } return (lumberJackLogger) } func simpleHttpGet(url string) { ("Trying to hit GET request for %s", url) resp, err := (url) if err != nil { ("Error fetching URL %s : Error = %s", url, err) } else { ("Success! statusCode = %s for URL %s", , url) () } }
Execute the above code and the following content will be output to the file.
2019-10-27T15:50:32.944+0800 DEBUG logic/:48 Trying to hit GET request for
2019-10-27T15:50:32.944+0800 ERROR logic/:51 Error fetching URL : Error = Get : unsupported protocol scheme ""
2019-10-27T15:50:32.944+0800 DEBUG logic/:48 Trying to hit GET request for
2019-10-27T15:50:33.165+0800 INFO logic/:53 Success! statusCode = 200 OK for URL
At the same time, you canmain
The logs are recorded loop in the function to test whether the log files will be cut and archived automatically (the log files will be cut every 1MB and a maximum of 5 backups are saved in the current directory).
This is the end of this article about how to use Zap to manage logs in Go. For more related content of Go Zap management logs, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!