[uber-zap/part2] custom recorder

Posted by pbase on Mon, 06 May 2019 17:40:03 +0200

Explain

  • A previous translation of a tutorial (without backing up the original address, the ladder was sealed). Add the original address after finding it

text

Using the default recorder saves time, but if you decide to adjust the recorder, you need to explore ways to customize the recorder

Using zap configuration structure to create recorders

You can use configuration zap.Config to create a recorder, which is a structure that can be filled with the required values, and then call the. Build() method of the structure to get the recorder.

cfg := zap.Config{...}
logger, err := cfg.Build()

Note that the structure of zap.Config does not have default values, providing values for at least three settings required by zap

  • Encoder: Just add an Encoding:"XXX" and use JSON to create a JSON encoder with another value of console
  • You can use the structure zapcore.EncoderConfig to customize the encoder (almost certainly, because the default is not very useful)
  • level enabler: This is an interface type that allows zap to determine whether a particular level of message should be displayed. In the zap configuration structure, you can use the Atomic Level wrapper in the Level field to provide this type.
  • sink: The output target of the log, which can specify multiple output paths using the Output Paths field, is sent to all these files. Like stderr and stdout are also possible

Customized encoder

It is not enough to set the type of encoder in the configuration structure. By default, json only outputs the fields specifically provided in the log message.
Here's the minimum configuration that won't throw errors when calling the. Build() method

    logger, _ := zap.Config{
        Encoding:    "json",
        Level:       zap.NewAtomicLevelAt(zap.DebugLevel),
        OutputPaths: []string{"stdout"},
    }.Build()

    logger.Info("This is an INFO message with fileds", zap.String("region", "us-west"), zap.Int("id", 2))

output

{"region":"us-west","id":2}

As you can see, the log information is not printed out!
To add information to json encoder, you need to specify the json key that will have this value in the output

    logger, _ := zap.Config{
        Encoding:    "json",
        Level:       zap.NewAtomicLevelAt(zap.DebugLevel),
        OutputPaths: []string{"stdout"},
        EncoderConfig: zapcore.EncoderConfig{
            MessageKey: "message", // <---
        },
    }.Build()

    logger.Info("This is an INFO message with fileds", zap.String("region", "us-west"), zap.Int("id", 2))

output

{"message":"This is an INFO message with fileds","region":"us-west","id":2}

zap can add more metadata like message, such as level name, timestamp, caller, stacktrace and so on. Unless the JSON key corresponding to the metadata is explicitly indicated, no will be displayed.
Note: These metadata names must match the encoder, or zap will make a mistake

Example:

    cfg := zap.Config{
        Encoding:         "json",
        Level:            zap.NewAtomicLevelAt(zap.DebugLevel),
        OutputPaths:      []string{"stdout"},
        ErrorOutputPaths: []string{"stderr"},
        EncoderConfig: zapcore.EncoderConfig{
            MessageKey: "message", // <---

            LevelKey:    "level",
            EncodeLevel: zapcore.CapitalLevelEncoder,

            TimeKey:    "time",
            EncodeTime: zapcore.ISO8601TimeEncoder,

            CallerKey:    "caller",
            EncodeCaller: zapcore.ShortCallerEncoder,
        },
    }
    logger, _ := cfg.Build()

    logger.Info("This is an INFO message with fileds", zap.String("region", "us-west"), zap.Int("id", 2))

output

{"level":"INFO","time":"2018-10-31T14:59:45.238+0800","caller":"zap_config/main.go:29","message":"This is an INFO message with fileds","region":"us-west","id":2}

Other options for encoder metadata fields

Each encoder can be customized as needed. Here are the different implementations provided by zap

  • timestamp can be ISO8601 Format output, which can be seconds,milliseconds Even to the extent that nanoseconds Format output
  • level: It can be capital or lowercase, and they even have colored Options. It is important to note that color options are not meaningful in JSON encoders
  • caller: Can be in relative format short And absolute format full display

Dynamic Change of Recorder Behavior

You can clone recorders from existing recorders and make some modifications to their behavior

  • logger.AddCaller() Add caller
  • logger.AddStacktrace() adds stack traces to messages at a given level and above
  • logger.Fields() adds the specified field to all messages output by the new logger. This approach reduces memory allocation and speeds up logging compared to specifying fields during actual log calls
  • logger.WrapCore() allows you to modify or even completely replace the encoder, level, and sink contained in the recorder. Here's an example
fmt.Printf("\n*** Using a JSON encoder, at debug level, sending output tu stuout, all possible keys specified\n\n")

    cfg := zap.Config{
        Encoding:         "json",
        Level:            zap.NewAtomicLevelAt(zapcore.DebugLevel),
        OutputPaths:      []string{"stderr"},
        ErrorOutputPaths: []string{"stderr"},
        EncoderConfig: zapcore.EncoderConfig{
            MessageKey: "message",

            LevelKey:    "level",
            EncodeLevel: zapcore.CapitalLevelEncoder,

            TimeKey:    "time",
            EncodeTime: zapcore.ISO8601TimeEncoder,

            CallerKey:    "caller",
            EncodeCaller: zapcore.ShortCallerEncoder,
        },
    }

    logger, _ := cfg.Build()

    logger.Info("This is an INFO message")

    fmt.Printf("\n*** Same logger with console loggin enable instead\n\n")

    logger.WithOptions(
        zap.WrapCore(
            func(zapcore.Core) zapcore.Core {
                return zapcore.NewCore(zapcore.NewConsoleEncoder(cfg.EncoderConfig), zapcore.AddSync(os.Stderr), zapcore.DebugLevel)
            })).Info("This is an INFO message")

output

*** Using a JSON encoder, at debug level, sending output tu stuout, all possible keys specified

{"level":"INFO","time":"2018-11-01T08:59:12.984+0800","caller":"wrap_core/main.go:35","message":"This is an INFO message"}

*** Same logger with console loggin enable instead

2018-11-01T08:59:12.984+0800    INFO    wrap_core/main.go:43    This is an INFO message

Topics: Go JSON encoding