SoFunction
Updated on 2025-03-03

Golang integrated log zap implementation example

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!