Fully asynchronous, structured, pluggable logging for Go.

logr

GoDoc Report Card

Logr is a fully asynchronous, contextual logger for Go.

It is very much inspired by Logrus but addresses two issues:

  1. Logr is fully asynchronous, meaning that all formatting and writing is done in the background. Latency sensitive applications benefit from not waiting for logging to complete.

  2. Logr provides custom filters which provide more flexibility than Trace, Debug, Info... levels. If you need to temporarily increase verbosity of logging while tracking down a problem you can avoid the fire-hose that typically comes from Debug or Trace by using custom filters.

Concepts

entity description
Logr Engine instance typically instantiated once; used to configure logging.
lgr := &Logr{}
Logger Provides contextual logging via fields; lightweight, can be created once and accessed globally or create on demand.
logger := lgr.NewLogger()
logger2 := logger.WithField("user", "Sam")
Target A destination for log items such as console, file, database or just about anything that can be written to. Each target has its own filter/level and formatter, and any number of targets can be added to a Logr. Targets for syslog and any io.Writer are built-in and it is easy to create your own. You can also use any Logrus hooks via a simple adapter.
Filter Determines which logging calls get written versus filtered out. Also determines which logging calls generate a stack trace.
filter := &logr.StdFilter{Lvl: logr.Warn, Stacktrace: logr.Fatal}
Formatter Formats the output. Logr includes built-in formatters for JSON and plain text with delimiters. It is easy to create your own formatters or you can also use any Logrus formatters via a simple adapter.
formatter := &format.Plain{Delim: " | "}

Usage

// Create Logr instance.
lgr := &logr.Logr{}

// Create a filter and formatter. Both can be shared by multiple
// targets.
filter := &logr.StdFilter{Lvl: logr.Warn, Stacktrace: logr.Error}
formatter := &format.Plain{Delim: " | "}

// WriterTarget outputs to any io.Writer
t := target.NewWriterTarget(filter, formatter, os.StdOut, 1000)
lgr.AddTarget(t)

// One or more Loggers can be created, shared, used concurrently,
// or created on demand.
logger := lgr.NewLogger().WithField("user", "Sarah")

// Now we can log to the target(s).
logger.Debug("login attempt")
logger.Error("login failed")

// Ensure targets are drained before application exit.
lgr.Shutdown()

Fields

Fields allow for contextual logging, meaning information can be added to log statements without changing the statements themselves. Information can be shared across multiple logging statements thus allowing log analysis tools to group them.

Fields are added via Loggers:

lgr := &Logr{}
// ... add targets ...
logger := lgr.NewLogger().WithFields(logr.Fields{
  "user": user,
  "role": role})
logger.Info("login attempt")
// ... later ...
logger.Info("login successful")

Logger.WithFields can be used to create additional Loggers that add more fields.

Logr fields are inspired by and work the same as Logrus fields.

Filters

Logr supports the traditional seven log levels via logr.StdFilter: Panic, Fatal, Error, Warning, Info, Debug, and Trace.

// When added to a target, this filter will only allow
// log statements with level severity Warn or higher.
// It will also generate stack traces for Error or higher.
filter := &logr.StdFilter{Lvl: logr.Warn, Stacktrace: logr.Error}

Logr also supports custom filters (logr.CustomFilter) which allow fine grained inclusion of log items without turning on the fire-hose.

  // create custom levels; use IDs > 10.
  LoginLevel := logr.Level{ID: 100, Name: "login ", Stacktrace: false}
  LogoutLevel := logr.Level{ID: 101, Name: "logout", Stacktrace: false}

  lgr := &logr.Logr{}

  // create a custom filter with custom levels.
  filter := &logr.CustomFilter{}
  filter.Add(LoginLevel, LogoutLevel)

  formatter := &format.Plain{Delim: " | "}
  tgr := target.NewWriterTarget(filter, formatter, os.StdOut, 1000)
  lgr.AddTarget(tgr)
  logger := lgr.NewLogger().WithFields(logr.Fields{"user": "Bob", "role": "admin"})

  logger.Log(LoginLevel, "this item will get logged")
  logger.Debug("won't be logged since Debug wasn't added to custom filter")

Both filter types allow you to determine which levels require a stack trace to be output. Note that generating stack traces cannot happen fully asynchronously and thus add latency to the calling goroutine.

Targets

There are built-in targets for outputting to syslog, file, or any io.Writer. More will be added.

You can use any Logrus hooks via a simple adapter.

You can create your own target by implementing the Target interface.

An easier method is to use the logr.Basic type target and build your functionality on that. Basic handles all the queuing and other plumbing so you only need to implement two methods. Example target that outputs to io.Writer:

type Writer struct {
  logr.Basic
  out io.Writer
}

func NewWriterTarget(filter logr.Filter, formatter logr.Formatter, out io.Writer, maxQueue int) *Writer {
  w := &Writer{out: out}
  w.Basic.Start(w, w, filter, formatter, maxQueue)
  return w
}

// Write will always be called by a single goroutine, so no locking needed.
// Just convert a log record to a []byte using the formatter and output the
// bytes to your sink.
func (w *Writer) Write(rec *logr.LogRec) error {
  _, stacktrace := w.IsLevelEnabled(rec.Level())

  // take a buffer from the pool to avoid allocations or just allocate a new one.
  buf := rec.Logger().Logr().BorrowBuffer()
  defer rec.Logger().Logr().ReleaseBuffer(buf)

  buf, err := w.Formatter().Format(rec, stacktrace, buf)
  if err != nil {
    return err
  }
  _, err = w.out.Write(buf.Bytes())
  return err
}

Formatters

Logr has two built-in formatters, one for JSON and the other plain, delimited text.

You can use any Logrus formatters via a simple adapter.

You can create your own formatter by implementing the Formatter interface:

Format(rec *LogRec, stacktrace bool, buf *bytes.Buffer) (*bytes.Buffer, error)

Handlers

When creating the Logr instance, you can add several handlers that get called when exceptional events occur:

Logr.OnLoggerError(err error)

Called any time an internal logging error occurs. For example, this can happen when a target cannot connect to its data sink.

It may be tempting to log this error, however there is a danger that logging this will simply generate another error and so on. If you must log it, use a target and custom level specifically for this event and ensure it cannot generate more errors.

Logr.OnQueueFull func(rec *LogRec, maxQueueSize int) bool

Called on an attempt to add a log record to a full Logr queue. This generally means the Logr maximum queue size is too small, or at least one target is very slow. Logr maximum queue size can be changed before adding any targets via:

lgr := logr.Logr{MaxQueueSize: 10000}

Returning true will drop the log record. False will block until the log record can be added, which creates a natural throttle at the expense of latency for the calling goroutine. The default is to block.

Logr.OnTargetQueueFull func(target Target, rec *LogRec, maxQueueSize int) bool

Called on an attempt to add a log record to a full target queue. This generally means your target's max queue size is too small, or the target is very slow to output.

As with the Logr queue, returning true will drop the log record. False will block until the log record can be added, which creates a natural throttle at the expense of latency for the calling goroutine. The default is to block.

Logr.OnExit func(code int) and Logr.OnPanic func(err interface{})

OnExit and OnPanic are called when the Logger.FatalXXX and Logger.PanicXXX functions are called respectively.

In both cases the default behavior is to shut down gracefully, draining all targets, and calling os.Exit or panic respectively.

When adding your own handlers, be sure to call Logr.Shutdown before exiting the application to avoid losing log records.

Owner
Mattermost
All team communication in one place, searchable and accessible anywhere.
Mattermost
Comments
  • Fixed plugin log attributes

    Fixed plugin log attributes

    Summary

    Unless I am mistaken, this should fix field names for structured logs (...keyValuePair). I noticed it because the plugin logs appeared broken.

    Ticket Link

    https://mattermost.atlassian.net/browse/MM-38342

  • Add support for color output

    Add support for color output

    Summary

    This PR adds color output for formatters that support it, i.e. the Plain text formatter.

    Draft until https://github.com/mattermost/logr/pull/12 is merged.

    Ticket Link

    https://focalboard-community.octo.mattermost.com/workspace/qgsck6cts3fwpqwyjiupjm5cde?id=47aa9bb4-6967-4a96-83c7-11bd6b20f1eb&v=ca1a5441-4c1c-4d0e-856e-88cc744576c8&c=29350874-945a-412b-8056-10de8909e516

  • MM-27316 Add metrics to Mattermost Logr

    MM-27316 Add metrics to Mattermost Logr

    Summary

    This PR adds metrics gathering to Logr. Metrics include queue sizes, queue capacities, logged records counts, and error counts. Metrics are provided by a new API: (*Logr).GetMetrics

    Ticket Link

    https://mattermost.atlassian.net/browse/MM-27316

  • Use params.Host over params.IP for syslog config

    Use params.Host over params.IP for syslog config

    Summary

    A bug was reported where the params.Host config setting was ignored and only the deprecated params.IP was used. This PR ensures params.Host takes priority over IP.

    Ticket Link

    NONE

  • export cfg factories

    export cfg factories

    Summary

    The fields within config.Factories were not exported, making it impossible to create custom targets outside the Logr package. This PR exports those two fields.

    Ticket Link

    NONE

  • fix metrics shutdown

    fix metrics shutdown

    Summary

    This PR fixes an issue with metrics collector shutdown where unit test can cause the shutdown to happen more than once, causing a close of a closed channel.

    Ticket Link

    NONE

  • Allow SetMetricsCollector to be called after init

    Allow SetMetricsCollector to be called after init

    Summary

    Normally the metrics collector is provided via options when a Logr is instantiated. Sometimes the host application is not ready to create a metrics collector until later in the app start up. This PR allows the collector to be safely added after instantiation.

    Ticket Link

    In support of https://mattermost.atlassian.net/browse/MM-36764

  • Handle nil stringer field type

    Handle nil stringer field type

    Summary

    When a logger field of type Stringer was used with a nil value it caused an error to be output. This PR fixes that output an empty string instead. Also added unit test to check this case.

    Ticket Link

    https://github.com/mattermost/focalboard/issues/775

  • Add support for Caller field

    Add support for Caller field

    Summary

    This PR adds support for an optional Caller field output to logs. This is required for FocalBoard and Chat logging.

    e.g.: "caller":"test/load.go:54"

    Ticket Link

    NONE

  • Fix build constraint

    Fix build constraint

    Summary

    Fixes the build contraint (+build at top of file) due to the comma separated platforms causing the the platforms to be AND'ed, thus breaking the build for Windows.

    Tiny change - no reviewers needed.

    Ticket Link

    https://github.com/mattermost/focalboard/issues/519

  • Windows build failing due to Logr syslog dependency

    Windows build failing due to Logr syslog dependency

    Summary

    Windows build was failing due to Logr syslog dependency since syslog is not supported on Windows. This PR fixes the issue by conditionally importing the syslog package for platforms that support it, and using a stub for unsupported platforms.

    Ticket Link

    https://github.com/mattermost/focalboard/issues/519

Structured, pluggable logging for Go.
Structured, pluggable logging for Go.

Logrus Logrus is a structured logger for Go (golang), completely API compatible with the standard library logger. Logrus is in maintenance-mode. We wi

Jan 9, 2023
Logrus is a structured, pluggable logging for Go.
Logrus is a structured, pluggable logging for Go.

Logrus is a structured logger for Go (golang), completely API compatible with the standard library logger.

May 25, 2021
Gomol is a library for structured, multiple-output logging for Go with extensible logging outputs

gomol Gomol (Go Multi-Output Logger) is an MIT-licensed structured logging library for Go. Gomol grew from a desire to have a structured logging libra

Sep 26, 2022
A Go (golang) package providing high-performance asynchronous logging, message filtering by severity and category, and multiple message targets.

ozzo-log Other languages 简体中文 Русский Description ozzo-log is a Go package providing enhanced logging support for Go programs. It has the following fe

Dec 17, 2022
Seelog is a native Go logging library that provides flexible asynchronous dispatching, filtering, and formatting.

Seelog Seelog is a powerful and easy-to-learn logging framework that provides functionality for flexible dispatching, filtering, and formatting log me

Jan 3, 2023
Structured logging package for Go.
Structured logging package for Go.

Package log implements a simple structured logging API inspired by Logrus, designed with centralization in mind. Read more on Medium. Handlers apexlog

Dec 24, 2022
Simple, configurable and scalable Structured Logging for Go.

log Log is a simple, highly configurable, Structured Logging library Why another logging library? There's allot of great stuff out there, but also tho

Sep 26, 2022
Structured, composable logging for Go
Structured, composable logging for Go

log15 Package log15 provides an opinionated, simple toolkit for best-practice logging in Go (golang) that is both human and machine readable. It is mo

Dec 18, 2022
Structured Logging Made Easy
Structured Logging Made Easy

Structured Logging Made Easy Features Dependency Free Simple and Clean Interface Consistent Writer IOWriter, io.Writer wrapper FileWriter, rotating &

Jan 3, 2023
Blazing fast, structured, leveled logging in Go.

⚡ zap Blazing fast, structured, leveled logging in Go. Installation go get -u go.uber.org/zap Note that zap only supports the two most recent minor ve

Jan 7, 2023
Hierarchical, leveled, and structured logging library for Go

spacelog Please see http://godoc.org/github.com/spacemonkeygo/spacelog for info License Copyright (C) 2014 Space Monkey, Inc. Licensed under the Apach

Apr 27, 2021
Minimal structured logging library for Go
Minimal structured logging library for Go

slog slog is a minimal structured logging library for Go. Install go get cdr.dev/slog Features Minimal API First class context.Context support First c

Dec 29, 2022
structured logging helper

Logart Logart is a structured logging tool that aims to simplify logging to a database It is not yet in stable state, but is used in production and ac

Apr 24, 2021
Go-metalog - Standard API for structured logging

Metalog is a standard API for structured logging and adapters for its implementa

Jan 20, 2022
A simple logging module for go, with a rotating file feature and console logging.

A simple logging module for go, with a rotating file feature and console logging. Installation go get github.com/jbrodriguez/mlog Usage Sample usage W

Dec 14, 2022
FactorLog is a logging infrastructure for Go that provides numerous logging functions for whatever your style may be
FactorLog is a logging infrastructure for Go that provides numerous logging functions for whatever your style may be

FactorLog FactorLog is a fast logging infrastructure for Go that provides numerous logging functions for whatever your style may be. It could easily b

Aug 3, 2022
Package logging implements a logging infrastructure for Go
Package logging implements a logging infrastructure for Go

Golang logging library Package logging implements a logging infrastructure for Go. Its output format is customizable and supports different logging ba

Nov 10, 2021
Logger - Go language is interface-oriented to implement an asynchronous log writing program

logger日志库 1、安装 go get github.com/staryjie/logger@latest 2、使用 示例: package main import ( "github.com/staryjie/logger" "time" ) func initLogger(name,

Jan 4, 2022
Structured log interface

Structured log interface Package log provides the separation of the logging interface from its implementation and decouples the logger backend from yo

Sep 26, 2022