logging

package module
v2.3.1 Latest Latest
Warning

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

Go to latest
Published: Mar 11, 2022 License: NCSA Imports: 9 Imported by: 7

README

logging: A slightly more advanced logging apparatus for Go

go/logging provides basic compatibility with the standard library log package insofar as its public API, with missing methods provided via a wrapper. However, go/logging also provides most "standard" (depending on whose standard you consult) logging levels available in logging utilities oft-used in other environments.

go/logging goes a step further than the stdlib log package--and a handful of other Golang logging libraries--in that it allows greater control over the log format by exposing an API to override output, per level, as it is logged (see AddFormatOveride). go/logging also provides a few other conveniences such as: Individual backends per logging level, hierarchical logging, and chained loggers. Some of these features are shared with competing libraries.

Why go/logging and not ${personal_preference}?

Because the plethora of other logging choices were not available when I first started writing go/logging and the ones that were out there I didn't like. Seriously.

In fact, at that time, the choices were essentially large logging libraries that did too much, libraries that attempted to foist a substantial paradigm shift outside what most users actually want (simpler is better), and the stdlib takes that latter bit too far (you can be too simple).

Thus I wrote go/logging. Consequently, I also still maintain it. If you don't like the idea of this library, you are absolutely welcome to not use it.

Changes in v2.x+

go/logging v2.x and greater introduce changes incompatible with prio versions and thereby require adapting existing code to the new API. In particular:

  • Exported APIs have changed and new interfaces have been added. In particular, ImmutableLogger and PkgLogger now join StdLogger. ImmutableLogger is used in go/logging where logger options should not be changed by client code.
  • go/logging always has a root logger present. To obtain it, simply call logging.Logger().
  • Optionally, you may create your own root loggers as needed. There are two ways to do this: First, with Get(), which will register all loggers created via this method with go/logging; subsequent calls to Get() will return previously registered loggers. Second, using New(), an unregistered logger may be obtained.
  • A new function Register() has been introduced to register top-level loggers which will then be accessible via Get(). There are some use cases where it may be desirable to register a logger sometime after creation; perhaps you wish to configure the logger first, or modify it in some form, but don't wish for the actual logger to be ready for use until this happens. Calling Register() will overwrite any previously existing logger with the specified name. (Note: Register() operates on the Log.Name() value rather than a user-supplied logger name.)
  • Load() has also been added as a top-level function to return previously Register()'d root loggers or root loggers that were created via Get(). Load() returns a tuple containing the named logger and a boolean value indicating whether or not the logger exists.
  • Must* constructor functions have been removed.
  • The default formatter has been changed from the formatter returned via NewDefaultFormatter and replaced with the one assembled by NewFastFormatter. On average, this has improved log processing latency between 30 to 40% and up to 60% for some workloads (e.g. log chaining). This formatter has been backported to the v1.x branch.
  • v2.x now requires Go v1.16 or greater.

Notes about v1

go/logging v1.x will likely no longer see further updates with the introduction of the v2 branch. However, there are some changes or additions that are far too important to allow v1.x to languish.

As an example, with the introduction of v2, a new format handler was introduced early in its development cycle that substantially reduced processing time for generated log messages. This change was deemed far too important to skip the v1.x branch and thus was backported. Both branches now enjoy similar speed ups.

If you're comfortable enough using v1.x, I would strongly suggest that you continue using it. If you're authoring new code, I would suggest using v2.x instead. Both branches will be maintained at least into the near term; however, if a v3 branch ever surfaces, v1.x will likely be deprecated.

Quick Start

This README is only intended as a quick start guide. For more detailed usage documentation, please refer to the docs/ directory in this repository (or in your local copy!).

This version of the quick start guide covers the v2.x branch. For documentation referencing v1.x, please see the appropriate branch.

Prerequisites

Obtain go/logging (v2 API):

go get git.destrealm.org/go/logging/v2

Or grab the v1 API (see the appropriate documentation elsewhere):

go get git.destrealm.org/go/logging

Getting Started

To create and use a logger:

import "logging"

func main() {
    // Returns the default root logger.
    logger := logging.Logger()

    // Do something.

    logger.Error("an error occurred!")
}

To change the default logging level (logging.Warning):


logger := logging.Logger()

// Set the log level to info.
logger.SetLevel(logging.Info)

Defined Levels

go/logging defines the following levels: Fatal, Error, Warning, Notice, Info, and Debug. For each of these levels there is an exported log function with the suffix f (e.g. Error and Errorf) for logging C-style formatted strings and their arguments.

Additionally, go/logging also aliases common abbreviations; e.g., Warning() and Warn() are identical as are Information() and Info(). For compatibility with the standard library log, go/logging also defines Panic and Fatal functions.

Output Control

Backends

go/logging supports any backend that exposes an io.Writer interface. By default, go/logging will output entries to io.Stdout. To change this, call SetBackend() on any already-created Log instance.

Note: SetBackend() always wraps io.Writer instances with a synchronous wrapper to reduce the likelihood that output from multiple sources will be interleaved. If this is not desirable for whatever reason, SetRawBackend() will apply the specified backend without wrapping it in synchronization primitives.

It is also possible to configure Log instances with different backends depending on level. Here, we discuss examples of common use cases.

Change Backend

To change the backend to a file:


fp, _ := os.OpenFile("filename", os.O_WRONLY|os.O_TRUNC, os.FileMode(0644))
logger.SetBackend(fp)

To change the backend for certain levels:


fp, _ := os.OpenFile("filename", os.O_WRONLY|os.O_TRUNC, os.FileMode(0644))
logger.SetBackendForLevel(logging.Error)
logger.SetBackendForLevel(logging.Warning)

Note: This will only change the backend for the specified level.

Clear Backend

Sometimes it may be necessary to clear the backend associated with a specific level. This will force the logger for that level to revert to the default backend:

logger.ClearBackend(logging.Error)
Wrapper Support

As with SetBackend(), SetBackendForLevel() also includes an option to bypass the io.Writer synchronization by calling SetRawBackendForLevel().

All wrapped writers are of type *logging.SyncWriter and implement the Wrapper interface. If SetBackend() receives a backend that already implements logging.Wrapper the writer will not be re-wrapped.

Chaining

go/logging provides an API for chaining multiple loggers together. This is mostly useful if you intend to direct output to different io.Writers depending on the configured logging level. For example, it's possible to output Info logs to STDOUT, Error logs to a specific error file, and everything to its own file for later analysis (although the recommended way to accomplish this is to use SetBackendForLevel()).

Chained loggers must start with the most specific log and complete the chain with the least restrictive. In our example, above, we might construct the logger chain as:

applog := logging.Logger()
applog.SetBackendForLevel(logging.Info, os.Stdout)
applog.SetBackendForLevel(logging.Error, errorLog) // errorLog is a file pointer

everything := logging.Logger()
everything.SetBackend(everythingLog) // everythignLog is a file pointer

appLog.Chain(everything)

Chaining is intended primarily for use cases where a logger cascade is needed such that all loggers in the chain receive the same input. For v2 go/logging, chaining is a means of tying together otherwise unconnected root loggers.

Inheritance

go/logging supports creating a logger hierarchy where a child logger inherits all attributes (including backend configuration) from its parent. Inheritance is a different concept from chaining; whereas chain logs can be completely unrelated and comprise different root loggers, inheritance affects direct descendants of a particular log. For example, if a parent logger has its level set to logging.WARN, all descendants of that log will inherit the parent level until the child logger's log level is changed.

Creating an inheritance chain can be done in one of two ways. The first, by a method on the logger instead itself:

logger := logging.Logger()
webLogger := logger.Inherit("web")
requestLogger := webLogger.Inherit("request")

And the second via a naive retrieval method:

logger := logging.Logger()
requestLogger := logger.GetLogger("web.request")

// ...or...

requestLogger := logger.Inherit("web.request")

As such, inherited loggers can more easily be obtained via dot notation or via the individual loggers themselves:

logger := logging.Logger()

// As above.
requestLogger := logger.GetLogger("web.request")

// Or...
webLogger := logger.GetLogger("web")
requstLogger := webLogger.GetLogger("request")

Intermediate loggers are always created as needed. This is a notable departure from the v1 API!

Iteration and Inheritance

It's possible to iterate through a list of loggers using inheritance and iteration. Each logger has Iterate() and IterateAll() methods that accept a function consuming a single *Log parameter that will apply this function to each child logger.

Iterate() and IterateAll() differ in their intent: In the former, Iterate(), all direct descendants of a *Log will be traversed and is a fast way to apply changes to multiple children of a given logger; in the latter, IterateAll(), the entire inheritance tree (children, children of children, ad nauseum) is traversed.

For example:

// Iterate() usage.
logger := logging.Logger()
logger.Iterate(func(lg *logging.Log) {
    // Discard all output for child loggers.
    lg.SetBackend(logging.Discard)
})

If iteration over all descendants is required, use IterateAll() instead as Iterate() only applies itself to the immediate descendants of the current logger:

// IterateAll() usage:
logger := logging.Logger()
logger.IterateAll(func(lg *logging.Log) {
    // Discard all output for child loggers.
    lg.SetBackend(logging.Discard)
})

Advanced Topics

This section covers the less common use cases of go/logging that may be handy for specific edge cases or for implementers who require more control over the loggers' behavior.

Formatters

go/logging exposes some primitives for crafting custom formatters. These formatters are simple functions accepting an io.Writer, a logging.ImmutableLog, and a *logging.Message. Formatters can be used to transform log messages before they are written to their final location or, in a particularly creative use case, could be used to intercept log messages to manipulate them before writing (the passed-in io.Writer need not be used). Currently, three formatters are provided: The "default" formatter, which provides simple text template replacement; the template formatter, which uses Golang's text/template to format output; and the "fast" formatter which uses a function stack derived from an output template to cache intermediate logging output and is, on average, 30-50% faster than the default formatter. Future versions will likely remove the current default formatter entirely.

To create a formatter, it is necessary to register a function that matches the logging.FormatterFunc signature with a logger's SetFormatter() function. Formatters then receive the arguments: An io.Writer instance, a reference to the current logger instance of type logging.Log, and a *logging.Message pointer.

logging.Message contains all of the metadata associated with a log entry: The timestamp, the error level, and its message.

When constructing a new formatter, it's important to keep in mind a few things:

  • The io.Writer instance is the output channel that interfaces directly with the backend; this may be a file, STDOUT, or anything else implementing the io.Writer interface. This writer may or may not be buffered, so you will need to buffer your output internally if you plan on making several small writes per log entry. Doing so will improve throughput in most circumstances.
  • The io.Writer formatter functions receive will be encapsulated, by default, within a logging.SyncWriter which satisfies the logging.Wrapper interface except in cases where the client code has configured the backend via SetRawBackend() or SetRawBackendForLevel(). If you are uncertain if the io.Writer you have received is wrapped, you will need to manually check the writer's interface.
  • If you need to do initialization of an object, do so within a factory function that creates an instance of your formatter and return the logging.FormatterFunc from that. Be aware that your formatter will be invoked for every call to each logging method.
  • You can use the formatter if you need to translate for a specific backend, such as when targeting syslog or systemd-journald. Though, bear in mind that you may be better off using chaining combined with a custom backend. Future versions of go/logging will contain a sub-repository for custom backends.
  • logging.Log contains an internal options map (*Log.Options) that isn't used for anything go/logging-specific. Instead, it is intended as a metadata store for custom formatters. If you need to persist something per-logger, you should add it to the Options map and then access this from within your formatter. Be aware that this map is not protected by any synchronization primitives.

Metadata Logging

go/logging supports logging additional information besides simply writing strings to a particular backend. As of v2.1+, go/logging now includes support for printing metadata and file/line number information alongside the log message. This feature is opt-in per logger (it's slow; do not use it in high traffic code paths), returns a logging.Log copy, and will print the contents of a given string-keyed map after the log message. To use this feature, call either WithMeta or WithMetaOpts (the latter reserved, presently, for toggling line numbers):

logger := logging.Get("example")
meta := map[string]interface{}{
  "path": "/tmp/failed.txt",
  "code": 42,
}

mlog := logger.WithMeta(meta)
mlog.Error("failed to open file")

// Prints:
//
// [ERRO] - 2021-11-30 02:33:42 MST - failed to open file - [<path=/tmp/failed.txt> <code=42>]

Or substitute WithMeta with WithMetaOpts:

mlog := logger.WithMetaOpts(meta, logging.MetaOptions{LineNo: true})
mlog.Error("failed to open file")
// Prints:
//
// [ERRO] - 2021-11-30 02:33:42 MST - failed to open file - [<path=/tmp/failed.txt> <code=42>] - main.go:483

At present, the logging.MetaOptions struct allows for toggling callers' line numbers on or off and for shifting line number calculation to the previous caller (by setting MetaOptions.Caller to logging.PreviousCaller). At present there is no means of controlling the template used to generate the formatted output for processing metadata. Moreover, metadata cannot be changed without additional calls to WithMeta* or in the event the original map is changed.

Template Loggers

It may be necessary, on occasion, to configure a default state for all subsequently created root loggers. As of v2.3.0 this is now possible via the logging.SetTemplate() global function which will configure the specified logger as a "template" logger from which all other loggers derive their default settings.

To set the package template to the default root logger:

logging.SetTemplate(logging.Logger())

To set the package template to a custom logger:

logger := logging.Get("application")
logger.SetLevel(logging.Info)
logging.SetTemplate(logger)

// All loggers will now have a level of logging.Info:

lg := logging.Get("another-application")

To clear the template logger, simply call logging.ClearTemplate():

// Set the template logger to the default root logger.
logging.SetTemplate(logging.Logger())

// Do some things and then reset the template to nil:

logging.ClearTemplate()

Once ClearTemplate is called, the template logger is reset and all loggers created will use the package defaults.

A word of warning: Because all loggers will inherit their defaults from the global template, care should be taken to ensure that only those attributes that make sense to be inherited are changed. This could provoke unexpected behaviors; use wisely!

Panic() and Exit()

With the introduction of v2.0, the package mechanisms that allowed for overriding the behavior of Panic() and Exit() when calling any of the Panic* and Fatal* logger methods were inadvertently removed and never re-added. As of v2.3+, these have now made a reaappearance and can be overridden at the package level:

// Set Panic() to a no-op to disable panics when logged:
logging.Panic = func(string){}

// Set Exit() to panic instead:
logging.Exit = func(s string){
  panic(s)
}

Similarly, Panic* and Fatal* can be overridden per-logger rather than at the package level (this is preferred):

logger := logging.Get("panic-and-exit-example")

// Set Panic* to a noop.
logger.SetOnPanic(func(string){})

// Set Fatal* to exit instead.
logger.SetOnExit(func(s string){ panic(s) })

LICENSE

go/logging is licensed under the fairly liberal and highly permissive NCSA license. We prefer this license as it combines the best of BSD and MIT licenses while providing coverage for associated documentation and other works that are not strictly considered original source code. Consequently, all go/logging documentation is likewise covered under the same license as the codebase itself.

As with BSD-like licenses attribution is required.

Copyright (c) 2015-2021.

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (

	// Black escape sequence (normal font type).
	Black = []byte{0x33, '[', '3', '0', 'm'}

	// Red escape sequence (normal font type).
	Red = []byte{0x33, '[', '3', '1', 'm'}

	// Green escape sequence (normal font type).
	Green = []byte{0x33, '[', '3', '2', 'm'}

	// Yellow escape sequence (normal font type).
	Yellow = []byte{0x33, '[', '3', '3', 'm'}

	// Blue escape sequence (normal font type).
	Blue = []byte{0x33, '[', '3', '4', 'm'}

	// Magenta escape sequence (normal font type).
	Magenta = []byte{0x33, '[', '3', '5', 'm'}

	// Cyan escape sequence (normal font type).
	Cyan = []byte{0x33, '[', '3', '6', 'm'}

	// White escape sequence (normal font type).
	White = []byte{0x33, '[', '3', '7', 'm'}

	// Reset escape sequence.
	Reset = []byte{0x33, '[', '0', 'm'}
)
View Source
var Exit func(string) = _exit

Exit defines a function that is triggered, by default, for all Fatal* *Log calls. This can be overridden here by changing the value for the package as a whole, maintaining compatibility with earlier versions of go/logging.

Preferrably, this should be modified on the individual loggers via SetOnExit().

View Source
var Levels = []string{
	"INHERIT",
	"FATAL",
	"ERROR",
	"WARNING",
	"NOTICE",
	"INFO",
	"DEBUG",
}

Levels defines the supported RFC 5424 logging levels in this package.

View Source
var Panic func(string) = _panic

Panic defines a function that is triggered, by default, for all Panic* *Log calls. This can be overridden here by changing the value for the package as a while, maintaining compatibility with earlier versions of go/logging.

Preferrably, this should be modified on the individual loggers via SetOnPanic().

Stdout is the standard output writer, used globally by all writers by default to reduce risk of interleaving.

Functions

func ClearTemplate added in v2.3.0

func ClearTemplate()

ClearTemplate resets the template logger. All generated loggers will be unique, will share no attributes, and will be configured using package defaults once this is called.

func IsTTY added in v2.0.2

func IsTTY(writer io.Writer) bool

func Register

func Register(log *Log)

Register the specified logger as a root logger.

N.B.: While this does not necessarily have to be a root logger and can, in fact, be any logger in particular, convention dictates that loggers registered here should not be the inheritors of any other logger.

One particularly helpful use case for registering root loggers in this manner is to avoid the implicit inheritance hierarchy: go/logging, when used with individual loggers, will interpret names containing dots as a tree of available loggers. For instance, "main.web.request" will be perceived by a logger as containing "main" at the top level, followed by "web," and then by "request." For that matter, "www.example.com" would likewise be split into individual parts ("www," "example," and "com"). As this is not desirable, registering separate top-level loggers allows both shunting logger handling into go/logging as well as avoiding the inheritance problem.

func SetTemplate added in v2.3.0

func SetTemplate(log *Log)

SetTemplate configures the template logger to the specified log. When set, all new loggers, except for the default root logger, will use this to initialize their state. All attributes will therefore be copied from this logger (meaning that per-level backends will be shared, among other attributes).

This is global state that will modify the behavior of this package. Use sparingly. Examples include overriding all generated loggers such that they use the same backend, level, etc., unless otherwise specified.

func WrapWriter

func WrapWriter(w io.Writer) io.Writer

WrapWriter accepts an io.Writer and returns it, guarded by a SyncWriter. This is the recommended entry point for implementations to utilize SyncWriters. If the provided writer is already wrapped, it will be returned instead.

Types

type ErrorCallback added in v2.0.2

type ErrorCallback func(*Message, error, Level, *Log)

type FormatterFunc

type FormatterFunc func(io.Writer, ImmutableLogger, *Message) error

FormatterFunc defines the type of a formatter function that can be used to override the use of Go templates. This function must accept the logger instance as its first argument followed by a single formatter (containing the message data) and return a string.

func NewDefaultFormatter

func NewDefaultFormatter(format string) FormatterFunc

NewDefaultFormatter returns the defaultFormatter used by logging for inline variable string replacement.

This implementation is exceedingly basic, simple, and fairly performant. It is approximately 3 times faster than the Golang text template formatter and should be used except in rare circumstances where conditional manipulation of logging entries is required.

func NewFastFormatter

func NewFastFormatter(format string) FormatterFunc

func NewTemplateFormatter

func NewTemplateFormatter(tpl string, funcs map[string]interface{}) FormatterFunc

NewTemplateFormatter returns a formatter backed by Golang's text templates for line-by-line templating support.

templateFormatters support context-sensitive template functions via the `funcs` argument here and can be used to conditionally manipulate logging output.

Be aware that the templateFormatter is approximately 3 times slower than the default formatter.

type ImmutableLogger

type ImmutableLogger interface {
	Name() string
	FullPath() string
	DateFormat() string
	Level() Level
	Newline() bool
	Error(...interface{})
	Errorf(string, ...interface{})
	Warn(...interface{})
	Warnf(string, ...interface{})
	Warning(...interface{})
	Warningf(string, ...interface{})
	Notice(...interface{})
	Noticef(string, ...interface{})
	Info(...interface{})
	Infof(string, ...interface{})
	Information(...interface{})
	Informationf(string, ...interface{})
	Debug(...interface{})
	Debugf(string, ...interface{})
	Print(...interface{})
	Printf(string, ...interface{})
	Println(...interface{})
	Fatal(...interface{})
	Fatalf(string, ...interface{})
	Fatalln(...interface{})
	Panic(...interface{})
	Panicf(string, ...interface{})
	Panicln(...interface{})
}

type Level

type Level int

Level defines a type for use internally for identifying logging levels.

const (
	Inherit Level = iota
	Fatal
	Error
	Warning
	Notice
	Info
	Debug
)

RFC 5424 levels (borrowed from syslog message facilities).

func LevelFromString

func LevelFromString(l string) Level

LevelFromString returns a Level value (internally an integer) given a matching string. This serves as a simple map between string -> integer values of error levels.

Some levels have aliases. INFO and WARN can be given as "information" or "warning," respectively.

The case of input values is ignored.

func (Level) Short

func (l Level) Short() string

Short string implementation.

func (Level) String

func (l Level) String() string

String implementation.

type Log

type Log struct {

	// This mutex covers the backends, log chain, options metadata, and child
	// loggers.
	sync.Mutex

	// Metadata options. Typically this map will be empty and isn't used
	// internally by the logger. However, it is provided for formatterOverrides
	// that may need additional metadata for configuration (such as enabling or
	// disabling colorized output, among other things).
	Options map[string]interface{}
	// contains filtered or unexported fields
}

Log container.

func Get

func Get(name string) *Log

Get returns a new or existing root logger. Loggers created through this mechanism are registered with the global logger directory. To create a new unregistered logger, use New().

Root loggers are top level loggers from which all other loggers inherit. By default, go/logging possesses only a single root logger (the default). This function creates additional ones.

func Load

func Load(name string) (*Log, bool)

Load returns a previously Register()'d logger or a logger previously created via GetLogger(). If the specified logger doesn't exist, the returned tuple will contain (nil, false).

func Logger

func Logger() *Log

Logger returns the default root logger.

func New

func New(name string) *Log

New returns a new, unregistered logger. This logger, if destroyed, cannot be re-obtained unless it is first Register()'d.

func (*Log) AddErrorCallback added in v2.0.2

func (l *Log) AddErrorCallback(fn ErrorCallback) *Log

func (*Log) AddFormatOverride

func (l *Log) AddFormatOverride(level Level, f FormatterFunc) *Log

AddFormatOverride injects an override function for the level specified.

func (*Log) Attach

func (l *Log) Attach(name string, logger *Log) *Log

Attaches the specified logger to the current (parent) logger.

func (*Log) Chain

func (l *Log) Chain(logger *Log) *Log

Chain another Log instance with the current logger. When a logger is configured to chain to another logger, any logging messages will be repeatedly dispatched down the chain until no more logger instances are found. In this way, it's possible to isolate multiple logger behaviors by error level.

For example, if you wish to create two loggers, one that logs only error messages (and nothing else) and another that logs everything (including error messages), such as might be necessary for applications that must write error messages to a file as well as to STDOUT, you can do the following:

errorsOnly := &bytes.Buffer{}

// Error logger.
errorLog := MustGetLogger("errors")
errorLog.SetBackend(nil)

// Clear the main backend.
errorLog.SetBackendForLevel(Error, errorLog)

// Everything else (remember, the default is to log to os.Stdout)...
everythingLog := MustGetLogger("everything")

// Chain the loggers starting with the most restrictive.
errorLog.Chain(everything)

// Now, when we call errorLog.*, it will always log to everythingLog.
errorLog.Error("This is an error. It is written to both.")
errorLog.Debug("This is a debug notice. It is written only to
    everythingLog.")

func (*Log) ClearBackend

func (l *Log) ClearBackend(level Level) io.Writer

ClearBackend removes the backend for the specified level.

Returns the removed writer. If no such writer was set this value will be nil.

func (*Log) DateFormat

func (l *Log) DateFormat() string

func (*Log) Debug

func (l *Log) Debug(v ...interface{})

Debug logs debugging messages.

func (*Log) Debugf

func (l *Log) Debugf(format string, v ...interface{})

Debugf logs debugging messages with formatted input.

func (*Log) Destroy

func (l *Log) Destroy(name string) *Log

Destroy destroys the child logger identified by `name` alongside any of its children.

func (*Log) Error

func (l *Log) Error(v ...interface{})

Error logs an error condition.

func (*Log) Errorf

func (l *Log) Errorf(format string, v ...interface{})

Errorf logs an error condition with formatting.

func (*Log) Fatal

func (l *Log) Fatal(v ...interface{})

Fatal works similarly to the Go standard library log.Fatal. Like Fatalf, it's treated as as an error condition and exits the application. It additionally logs the message as Fatal.

func (*Log) Fatalf

func (l *Log) Fatalf(format string, v ...interface{})

Fatalf works identically to the Go standard library log.Fatalf, returning an error status and exiting the application. It additionally logs the message as Fatal.

func (*Log) Fatalln

func (l *Log) Fatalln(v ...interface{})

Fatalln works similarly to the Go standard library log.Fatalln. Like Fatalf and Fatal, it's treated as an error condition and exits the application. It additionally logs the message as Fatal.

func (*Log) FullPath

func (l *Log) FullPath() string

FullPath returns the fully qualified name for the current logger.

func (*Log) Get

func (l *Log) Get(name string) *Log

Get returns the child logger associated with this parent by its name `name`. If no such logger is configured it will be created.

func (*Log) Info

func (l *Log) Info(v ...interface{})

Info logs an informational message.

func (*Log) Infof

func (l *Log) Infof(format string, v ...interface{})

Infof logs an informational message with formatting.

func (*Log) Information

func (l *Log) Information(v ...interface{})

Information is an alias for Info.

func (*Log) Informationf

func (l *Log) Informationf(format string, v ...interface{})

Informationf is an alias for Infof.

func (*Log) Inherit

func (l *Log) Inherit(name string) *Log

Inherit constructs a new logger from the parent instance and returns it. Inherited loggers retain all of their parent properties until they are manually changed and are configured with the special level value Inherit. Inherited loggers are registered globally with the parent's name as a dot-separated prefix (e.g. parent.child) and may be accessed via MustGet or by the parent logger via parent.Get.

Inherit will *always* overwrite an existing logger by the same name.

If a logger inheritance hierarchy declaration (e.g. a dot-separated name) is passed to this method, the last component will be used as the inherited logger name.

func (*Log) Iterate

func (l *Log) Iterate(fn func(*Log)) *Log

Iterate over the current logger's children, applying the function fn(). Callback functions receive the current logger as their sole argument.

Useful for modifying an entire logging tree.

func (*Log) IterateAll

func (l *Log) IterateAll(fn func(*Log)) *Log

IterateAll attempts to iterate over *all* of the current logger's descendants.

func (*Log) Level

func (l *Log) Level() Level

GetLevel returns the level for the current logger or, if the level is set to the value Inherit, will return the level associated with the parent logger (if available).

If no suitable level is found, this will return Warning.

func (*Log) Name

func (l *Log) Name() string

Name returns the current logger's configured name.

func (*Log) Newline

func (l *Log) Newline() bool

Newline returns true if the logger appends a newline to the output, false otherwise.

This is used by formatters to decide whether they should attach a newline or not.

func (*Log) Notice

func (l *Log) Notice(v ...interface{})

Notice logs a notice containing pertinent information. This does not indicate an error condition.

func (*Log) Noticef

func (l *Log) Noticef(format string, v ...interface{})

Noticef logs a notice containing pertinent information with formatting. This does not indicate an error condition.

func (*Log) Panic

func (l *Log) Panic(v ...interface{})

Panic works similarly to the Go standard library log.Panic. Like Panicf, it's treated as as an error condition and panics. It additionally logs the message as fatal.

func (*Log) Panicf

func (l *Log) Panicf(format string, v ...interface{})

Panicf works identically to the Go standard library log.Panicf, printing the error and returning a panic. As with Fatalf, this logs the message as fatal.

This method will log the message twice if the output backend is STDOUT or STDERR and should typically be used only if it is expected that writing to the backend may fail (e.g. to a file or other output device; thus ensuring that whatever is connected to STDOUT or STDERR will still render the error message visible).

func (*Log) Panicln

func (l *Log) Panicln(v ...interface{})

Panicln works similarly to the Go standard library log.Panicln. Like Panicf and Panic, it's treated as a fatal error and returns a panic.

func (*Log) Print

func (l *Log) Print(v ...interface{})

Print works similarly to the Go standard library log.Print. Like Printf, it's treated as an informational message.

func (*Log) Printf

func (l *Log) Printf(format string, v ...interface{})

Printf works similarly to the Go standard library log.Printf with the exception that it's treated as an informational message.

func (*Log) Println

func (l *Log) Println(v ...interface{})

Println works similarly to the Go standard library log.Println. Like Printf and Print, it's treated as an informational message.

func (*Log) SetBackend

func (l *Log) SetBackend(backend io.Writer) *Log

SetBackend changes the default backend. This backend will be written to whenever any of the logging facility methods (Error, Critical, etc.) are called.

If you wish to override this backend for a specific logging level, use SetBackendForLevel.

Setting a backend with this function will wrap the given writer in a SyncWriter if it isn't already.

func (*Log) SetBackendForLevel

func (l *Log) SetBackendForLevel(level Level, backend io.Writer) *Log

SetBackendForLevel changes the backend to use for a specific level. Configuring this value will override the default backend for the specified level only.

For instance, creating the following:

buf := &bytes.Buffer{}
logger := MustGetLogger("example")
logger.SetBackendForLevel(Error, buf)

Will cause:

logger.Error("some error")

to save logging data to `buf`, while

logger.Warn("warning!")
logger.Debug("some debugging information")

will both write to the default backend (os.Stdout).

To clear the backend for the specified level, reverting it back to using the default backend, call ClearBackend(level).

Setting a backend with this function will wrap the given writer in a SyncWriter if it isn't already.

func (*Log) SetDateFormat

func (l *Log) SetDateFormat(format string) *Log

SetDateFormat changes the default date format for the current logger.

func (*Log) SetFormat

func (l *Log) SetFormat(format string) *Log

SetFormat sets the logger format. Logger formats are typically formatter-specific and depend on the formatter that has been configured for a given logger. By default this is usually the "fast" formatter (NewFastFormatter). Be aware that configuring this value for the wrong formatter will produce unexpected output.

For built in templates, values are delinated by keys encapsulated in "{{" and "}}" and are comprised of the following values:

time       - Timestamp.
error      - Error level text (one of FATAL, ERROR, WARN, NOTICE, INFO,
             DEBUG, INHERIT).
ErrorLevel - Error level as represented by a positive integer.
Message    - Log message.
ShortError - Truncated error level text containing exactly 4 characters
             (one of FATL, ERRO, WARN, NOTE, INFO, DEBUG, INHT).

For Golang-based templates the following fields are available:

.Time       - Timestamp
.Error      - Error level text (one of FATAL, ERROR, WARN, NOTICE, INFO,
              DEBUG, INHERIT).
.ErrorLevel - Error level (as a number between 0-7).
.Message    - Log message.
.ShortError - Shortened error level text (one of FATL, ERRO, WARN, NOTE,
              INFO, DEBUG, INHT)

(The logging level "INHERIT" should ordinarily not be end-user visible and indicates that a logger inherits its parent's state. Visibility of this mode should be considered a bug and may be reported as such.)

The default format at configuration time is:

"[{{err}}] {{time}} - {{message}}"

(newlines are added automatically unless SetNewline is passed false.)

Most colorization libraries should be usable by setting the format string.

This will also update the internal formatter state and is analogous to calling SetFormatter(FormatterFactory("template")), e.g.:

logger.SetFormat("{{message}}")

is equivalent to:

logger.SetFormatter(logging.NewFastFormatter("{{message}}"))

func (*Log) SetFormatter

func (l *Log) SetFormatter(formatter FormatterFunc) *Log

SetFormatter configures the backend formatter library. By default, this will be set to the formatter generated by NewFastFormatter. Values configured here must be of type FormatterFunc.

func (*Log) SetFormatterFunc

func (l *Log) SetFormatterFunc(fn func(string) FormatterFunc) *Log

SetFormatterFunc configures a FormatterFunc factory function. This function must accept a single string (this is the format string configurable via SetFormat) and return a FormatterFunc.

func (*Log) SetLevel

func (l *Log) SetLevel(level Level) *Log

SetLevel changes the logger's level. Error messages that are at this level--or lower--will be logged; everything else will be ignored. Note that in this context "lower" means the literal integer value of the logger and not the relative importance of its data. For example, setting a logging level of Error will log anything at an Error or below (which includes Alert, Emergency, and Critical). Likewise, setting a logging level of Debug will log literally everything.

If you wish to control what the logger instance logs such as logging only Error-level messages, you'll need to manipulate the backends. This can be done by setting a backend for the Error level and clearing the default backend by setting it to nil.

func (*Log) SetNewline

func (l *Log) SetNewline(nl bool) *Log

SetNewline configures whether the logger will automatically append a newline to each entry. True by default.

func (*Log) SetOnExit added in v2.3.0

func (l *Log) SetOnExit(fn func(string)) *Log

func (*Log) SetOnPanic added in v2.3.0

func (l *Log) SetOnPanic(fn func(string)) *Log

func (*Log) SetOption

func (l *Log) SetOption(option string, value interface{}) *Log

SetOption is the recommended method for setting metadata values in the logger. It's possible to set options by manipulating the Log.Options map directly but there is no stability guarantee provided for its continued export status.

func (*Log) SetRawBackend

func (l *Log) SetRawBackend(backend io.Writer) *Log

SetRawBackend behaves identically to SetBackend with the exception that it does not wrap the backend argument in a SyncWriter.

func (*Log) SetRawBackendForLevel

func (l *Log) SetRawBackendForLevel(level Level, backend io.Writer) *Log

SetRawBackendForLevel behaves identically to SetBackendForLevel with the exception that it does not wrap the backend argument in a SyncWriter.

func (*Log) SetTimezone

func (l *Log) SetTimezone(tz *time.Location) *Log

SetTimezone sets the logger's timezone to the specified location. The logger uses time.UTC by default. Change this to time.Local to display the server's local time.

func (*Log) Warn

func (l *Log) Warn(v ...interface{})

Warn logs a warning.

func (*Log) Warnf

func (l *Log) Warnf(format string, v ...interface{})

Warnf logs a warning with formatting.

func (*Log) Warning

func (l *Log) Warning(v ...interface{})

Warning is an alias for Warn.

func (*Log) Warningf

func (l *Log) Warningf(format string, v ...interface{})

Warningf is an alias for Warnf.

func (*Log) WithMeta added in v2.1.0

func (l *Log) WithMeta(meta map[string]interface{}) *Log

WithMeta returns a complete copy of the current logger, associated with the specified metadata. How this data is output will depend on the backend, template, and logger configuration.

Metadata is not printed by default. Bear in mind that calling WithMeta will greatly reduce the performance of your logger.

TODO: Return a *MetaLog that includes the above?

func (*Log) WithMetaOpts added in v2.1.0

func (l *Log) WithMetaOpts(meta map[string]interface{}, opts MetaOptions) *Log

WithMetaOpts is like WithMeta but allows callers to specify additional options. Presently, only the `lineno` option is available; if this is true, this will also include line number and file name logging.

func (*Log) Writer

func (l *Log) Writer() io.Writer

Writer is provided to satisfy the BasicLogger interface as provided by the go `log` package. This will return either the configured backend, all backends, or both, depending on what is available. Backend levels are ignored.

type Message

type Message struct {
	Timestamp time.Time
	Level     Level
	Message   string
}

Message instance. This is used internally for the formatter template.

func (*Message) FormatTime

func (f *Message) FormatTime(format string) string

FormatTime is the time formatting function. This is useful if client code wishes to use a Go template pipeline to change the format of the timestamp.

This is a convenience method and isn't required.

type MetaOptions added in v2.1.0

type MetaOptions struct {
	LineNo bool
	Caller WhichCaller
}

type PkgLogger

type PkgLogger interface {
	ImmutableLogger

	Attach(string, *Log)
	GetLogger(string) *Log
	Inherit(string) *Log
	Iterate(func(*Log))
	IterateAll(func(*Log))

	Chain(*Log)
	ClearBackend(Level) io.Writer
	DestroyLogger(string)
	SetBackend(io.Writer) *Log
	SetBackendForLevel(Level, io.Writer) *Log
	SetFormatter(FormatterFunc) *Log
	SetLevel(Level) *Log
	SetOption(string, interface{})
	SetRawBackend(io.Writer) *Log
	SetRawBackendForLevel(Level, io.Writer) *Log
	SetTimezone(*time.Location) *Log

	Writer() io.Writer
}

type StdLogger

type StdLogger interface {
	Fatal(...interface{})
	Fatalf(string, ...interface{})
	Fatalln(...interface{})
	Flags() int
	Output(int, string) error
	Panic(...interface{})
	Panicf(string, ...interface{})
	Panicln(...interface{})
	Prefix() string
	Print(...interface{})
	Printf(string, ...interface{})
	Println(...interface{})
	SetFlags(int)
	SetOutput(io.Writer)
	SetPrefix(string)
	Writer() io.Writer
}

StdLogger defines an interface matching the logger from the Golang standard library logger.

func CoreLogger

func CoreLogger(logger *Log) StdLogger

type SyncWriter

type SyncWriter struct {
	io.Writer
	sync.Mutex
}

SyncWriter provides an implementation of io.Writer that synchronizes logging messages such that interleaving output over a shared writer won't happen.

When using Logging's default settings, the internal reference to os.Stdout will be wrapped.

func (*SyncWriter) Wrapped

func (w *SyncWriter) Wrapped() io.Writer

Wrapped returns the wrapped writer.

func (*SyncWriter) Write

func (w *SyncWriter) Write(p []byte) (int, error)

Write implementation satisfying io.Writer guarded by an internal mutex.

type WhichCaller added in v2.2.0

type WhichCaller int
const (
	DefaultCaller  WhichCaller = -1
	PreviousCaller WhichCaller = iota
)

type Wrapper

type Wrapper interface {
	Wrapped() io.Writer
	Write([]byte) (int, error)
}

Wrapper defines an io.Writer wrapper type that exposes the wrapped io.Writer directly via the Wrapped() function member.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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