Skip to content

wojas/genericr

Repository files navigation

GoDoc

genericr

A generic logr implementation that makes it easy to write your own logging backend.

This package allows you to implement the logr interface by implementing a single callback function instead of the full interface.

Examples

Basic example

Basic example that directly writes to stderr:

log := genericr.New(func(e genericr.Entry) {
	fmt.Fprintln(os.Stderr, e.String())
})

log.WithName("some-component").WithValues("x", 123).V(1).Info("some event", "y", 42)

This outputs the default string representation which currently looks like this:

[1] some-component "some event" x=123 y=42

The genericr.Entry struct you receive in your handler contains the following fields that you can use to do your own formatting:

type Entry struct {
	Level     int           // level at which this was logged
	Name      string        // name parts joined with '.'
	NameParts []string      // individual name segments
	Message   string        // message as send to log call
	Error     error         // error if .Error() was called
	Fields    []interface{} // alternating key-value pairs

	// Caller information
	Caller      runtime.Frame // only available after .WithCaller(true)
	CallerDepth int           // caller depth from callback
}

Use e.FieldsMap() to retrieve the Fields as a map.

To enable caller information, use genericr.New(...).WithCaller(true).

To filter messages above a certain verbosity level, use genericr.New(...).WithVerbosity(1).

Usage in tests

This shows how you can redirect logs to the testing.T logger and keep a reference to the last log entry if you want to check that one:

func TestLogger_Table(t *testing.T) {
	var last genericr.Entry
	log := genericr.New(func(e genericr.Entry) {
		last = e
		t.Log(e.String())
	})
    // ...
}

Logrus example

More complicated example that implements a logrus adapter:

root := logrus.New()
root.SetLevel(logrus.TraceLevel)
root.SetFormatter(&logrus.TextFormatter{
	DisableColors:    true,
	DisableTimestamp: true,
})
root.Out = os.Stdout

var lf genericr.LogFunc = func(e genericr.Entry) {
	var l *logrus.Entry = root.WithField("component", e.Name)
	if e.Error != nil {
		l = l.WithError(e.Error)
	}
	if len(e.Fields) != 0 {
		l = l.WithFields(e.FieldsMap())
	}
	logrusLevel := logrus.Level(e.Level) + logrus.InfoLevel // 0 = info
	if logrusLevel < logrus.ErrorLevel {
		logrusLevel = logrus.ErrorLevel
	} else if logrusLevel > logrus.TraceLevel {
		logrusLevel = logrus.TraceLevel
	}
	l.Log(logrusLevel, e.Message)
}
log := genericr.New(lf)