SoFunction
Updated on 2025-03-03

Detailed explanation of how to use Zap to manage logs in Go

Run the following command to install zap

go get -u /zap

Configure Zap Logger

Zap provides two types of loggers—Sugared LoggerandLogger. 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 comparesSugaredLoggerFaster 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)

inMethodXXXis a variadic parameter function, which can be Info/Error/Debug/Panic, etc. Each method accepts a message string and any number ofField parameters. EachIn 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 useSugaredLoggerbyprintfFormat record statement

The following is the use after modificationSugaredLoggerreplaceLoggerCode:

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—EncoderWriteSyncerLogLevel

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 modifyWriteSyncerCode. 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 canmainThe 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!