zaplogfmt

package module
v1.6.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 9, 2023 License: MIT Imports: 14 Imported by: 0

README

Logfmt Encoder

GoDoc GitHub Actions CI

This package provides a logfmt encoder for zap.

Usage

The encoder is easy to configure. Simply create a new core with an instance of the logfmt encoder and use it with your preferred logging interface.

package main

import (
    "os"

    "github.com/allir/zap-logfmt"
    "go.uber.org/zap"
    "go.uber.org/zap/zapcore"
)

func main() {
    config := zap.NewProductionEncoderConfig()
    logger := zap.New(zapcore.NewCore(
        zaplogfmt.NewEncoder(config),
        zapcore.Lock(os.Stdout),
        zapcore.DebugLevel,
    ))
    defer logger.Sync()

    logger.Info("Hello World")
}

An alternative way to set up the logger by registering the encoder and using it with the config builder. Also setting the time encoding to RFC3339.

package main

import (
    zaplogfmt "github.com/allir/zap-logfmt"
    "go.uber.org/zap"
    "go.uber.org/zap/zapcore"
)

func main() {
    zaplogfmt.Register()
    zapConfig := zap.NewProductionConfig()
    zapConfig.EncoderConfig = zap.NewProductionEncoderConfig()
    zapConfig.EncoderConfig.EncodeTime = zapcore.RFC3339TimeEncoder
    zapConfig.Encoding = "logfmt"

    logger, err := zapConfig.Build()
    if err != nil {
        panic(err)
    }
    defer logger.Sync()

    logger.Info("Hello World")
}

Arrays, Objects, and Reflected Fields

While it's best to avoid complex data types in log fields, there are times when they sneak in. When complex fields are included in log records, they will be encoded, but they won't be very pretty.

Arrays

Arrays are encoded as a comma separated list of values within square brackets. This format is very similar to JSON encoding. Arrays of simple scalars remain quite readable but including elements that require quoting will result in very ugly records.

Objects

Objects are encoded as a space separated list of key=value pairs. Because this format includes an equals sign, the encoded object will require quoting. If any value in the object requires quoting, the required escapes will make the encoded field pretty difficult for humans to read.

Channels and Functions

Channels and functions are encoded as their type and their address. Therearen't many meaningful ways to log channels and functions...

Maps and Structs

Maps and structs are encoded as strings that contain the result of fmt.Sprint.

Namespaces

Namespaces are supported. If a namespace is opened, all of the keys will be prepended with the namespace name. For example, with the namespace foo and the key bar, you would get a key of foo.bar.

Attribution

This is a fork of the original encoder from github.com/jsternberg/zap-logfmt. And pulling in and combining additional fixes from other sources such as;

Documentation

Overview

Package zaplogfmt provides a logfmt encoder for zap (https://github.com/uber-go/zap)

Example (Array)
package main

import (
	"os"

	zaplogfmt "github.com/allir/zap-logfmt"
	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
)

func main() {
	config := zap.NewProductionEncoderConfig()
	config.TimeKey = ""

	logger := zap.New(zapcore.NewCore(
		zaplogfmt.NewEncoder(config),
		os.Stdout,
		zapcore.DebugLevel,
	))

	logger.Info("counting", zap.Ints("values", []int{0, 1, 2, 3}))

}
Output:

level=info msg=counting values=[0,1,2,3]
Example (NewEncoder)
package main

import (
	"os"

	zaplogfmt "github.com/allir/zap-logfmt"
	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
)

func main() {
	config := zap.NewProductionEncoderConfig()
	config.TimeKey = ""
	logger := zap.New(
		zapcore.NewCore(
			zaplogfmt.NewEncoder(config),
			zapcore.Lock(os.Stdout),
			zapcore.DebugLevel),
		zap.AddCaller(),
		zap.AddStacktrace(zapcore.ErrorLevel),
	).Named("main")
	defer logger.Sync()

	logger.Info("Hello World")

}
Output:

level=info logger=main caller=zap-logfmt/example_test.go:24 msg="Hello World"
Example (Object)
package main

import (
	"os"

	zaplogfmt "github.com/allir/zap-logfmt"
	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
)

type Person struct {
	First string
	Last  string
	Age   int
}

func (p Person) MarshalLogObject(enc zapcore.ObjectEncoder) error {
	enc.AddString("first", p.First)
	enc.AddString("last", p.Last)
	enc.AddInt("age", p.Age)
	return nil
}

func main() {
	config := zap.NewProductionEncoderConfig()
	config.TimeKey = ""

	logger := zap.New(zapcore.NewCore(
		zaplogfmt.NewEncoder(config),
		zapcore.Lock(os.Stdout),
		zapcore.DebugLevel,
	))
	defer logger.Sync()

	person := Person{First: "Arthur", Last: "Dent", Age: 42}
	logger.Warn("hitchhiker discovered", zap.Object("identity", person))

}
Output:

level=warn msg="hitchhiker discovered" identity="first=Arthur last=Dent age=42"
Example (Register)
package main

import (
	zaplogfmt "github.com/allir/zap-logfmt"
	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
)

func main() {
	zaplogfmt.Register()
	zapConfig := zap.NewProductionConfig()
	zapConfig.Encoding = "logfmt"
	zapConfig.OutputPaths = []string{"stdout"} // Need to log to stdout for the test

	zapConfig.EncoderConfig = zap.NewProductionEncoderConfig()
	zapConfig.EncoderConfig.TimeKey = ""
	zapConfig.EncoderConfig.EncodeTime = zapcore.RFC3339TimeEncoder

	logger, err := zapConfig.Build()
	if err != nil {
		panic(err)
	}
	defer logger.Sync()

	logger = logger.Named("reg")

	logger.Info("Hello World")

}
Output:

level=info logger=reg caller=zap-logfmt/example_test.go:47 msg="Hello World"

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func NewEncoder

func NewEncoder(cfg zapcore.EncoderConfig) zapcore.Encoder

NewEncoder creates an encoder interface for zap that writes logfmt formatted log entries.

func Register added in v1.5.0

func Register()

Register adds an encoder to zap named "logfmt" that can be used with zapcore.EncoderConfig.

Types

This section is empty.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL