Skip to content

logrus Transport ​

Go ReferenceVersionSourceChangelog

Wraps an existing *logrus.Logger. Metadata nests under a single configurable key.

sh
go get go.loglayer.dev/transports/logrus/v3
go get github.com/sirupsen/logrus

Basic Usage ​

go
import (
    "os"

    "github.com/sirupsen/logrus"

    "go.loglayer.dev/v3"
    lllogrus "go.loglayer.dev/transports/logrus/v3"
)

l := logrus.New()
l.Out = os.Stderr
l.Formatter = &logrus.JSONFormatter{}

log := loglayer.New(loglayer.Config{
    Transport: lllogrus.New(lllogrus.Config{Logger: l}),
})

log.Info("hello")
// {"level":"info","msg":"hello","time":"..."}

If you don't pass a Logger, the transport constructs one writing to Writer (default os.Stderr) at TraceLevel.

Config ​

go
type Config struct {
    transport.BaseConfig

    Logger *logrus.Logger // wrap an existing logger
    Writer io.Writer      // used only when Logger is nil
}

Fatal Behavior ​

logrus.Logger.Fatal and Logger.Log(FatalLevel, ...) call the logger's ExitFunc, which by default is os.Exit(1). To prevent logrus from exiting before the core's DisableFatalExit check can run, this transport always builds a fresh *logrus.Logger that copies the supplied logger's settings (Out, Hooks, Formatter, ReportCaller, Level, BufferPool) but with ExitFunc set to a no-op.

Two consequences:

  • The user's original *logrus.Logger is never mutated; its ExitFunc is preserved.
  • The wrapped copy returned by GetLoggerInstance is the no-op-ExitFunc version, not the original. For most operations this doesn't matter; configurations set on the original (formatter, hooks, etc.) are all preserved.

The core then decides whether os.Exit(1) is called after dispatch. See Fatal Exits the Process.

Metadata Handling ​

The core nests the entry's metadata under MetadataFieldName (default "metadata"; set Config.FlattenMetadata: true to restore per-transport v2 placement). This transport honors that key.

Metadata nests under the metadata key ​

go
log.WithMetadata(loglayer.Metadata{"requestId": "xyz", "n": 42}).Info("served")
// {"level":"info","msg":"served","metadata":{"requestId":"xyz","n":42},"time":"..."}

log.WithMetadata(User{ID: 7, Name: "Alice"}).Info("user")
// {"level":"info","metadata":{"id":7,"name":"Alice"},"msg":"user",...}

With Config.FlattenMetadata: true, map metadata instead becomes keys in a logrus.Fields bag passed to WithFields.

Change the nesting key on the core's config:

go
loglayer.New(loglayer.Config{
    Transport:         lllogrus.New(lllogrus.Config{Logger: l}),
    MetadataFieldName: "payload",
})

Reaching the Underlying Logger ​

GetLoggerInstance returns the wrapped (no-op-ExitFunc) *logrus.Logger:

go
l := log.GetLoggerInstance("logrus").(*logrus.Logger)
l.AddHook(myHook)

("logrus" is whatever you set as BaseConfig.ID; defaults to an auto-generated ID when unset.)

Level Mapping ​

LogLayer Levellogrus Level
LogLevelTraceTraceLevel
LogLevelDebugDebugLevel
LogLevelInfoInfoLevel
LogLevelWarnWarnLevel
LogLevelErrorErrorLevel
LogLevelFatalFatalLevel
LogLevelPanicPanicLevel