types

package
v0.0.0-...-183aff7 Latest Latest
Warning

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

Go to latest
Published: Mar 14, 2024 License: BSD-3-Clause Imports: 6 Imported by: 2

Documentation

Overview

Package types of logger unifies different types of loggers into interfaces Logger. For example it allows to upgrade simple fmt.Printf to be a fully functional Logger. Therefore multiple wrappers are implemented here to provide different functions which could be missing in some loggers.

Package types of logger unifies different types of loggers into interfaces Logger. For example it allows to upgrade simple fmt.Printf to be a fully functional Logger. Therefore multiple wrappers are implemented here to provide different functions which could be missing in some loggers.

Index

Constants

View Source
const (
	// LevelUndefined is an erroneous value of log-level which just corresponds
	// to the zero-value.
	LevelUndefined = Level(iota)

	// LevelNone means to do not log anything.
	//
	// But even if a Logger is setup with this level, messages with levels Panic
	// and Fatal will still cause panics and os.Exit, just we except this to avoid
	// sending log messages (some Logger implementations may ignore this rule).
	LevelNone

	// LevelFatal means non-recoverable error case.
	//
	// If a message sent with this level then os.Exit is invoked in the end of processing the message.
	//
	// If a Logger is setup with this level, it will just ignore messages with level higher than Panic,
	// will silently panic on a Panic message and will loudly exit on a Fatal message.
	//
	// Some Logger implementations may ignore the rule about panicking "silently".
	LevelFatal

	// LevelPanic means a panic case (basically a recoverable, but critical problem).
	//
	// If a message sent with this level then panic() is invoked in the end of processing the message.
	//
	// If a Logger is setup with this level, it will ignore messages with level higher than Panic.
	LevelPanic

	// LevelError means an error case (not a critical problem, but yet an error).
	//
	// A message with this level is just logged if the Logger is setup with level no less that this.
	LevelError

	// LevelWarning means an odd/unexpected/wrong/undesired/etc case. Basically this is something
	// to keep an eye on. For example which could explain odd/erroneous behavior of the application
	// in future.
	//
	// A message with this level is just logged if the Logger is setup with level no less that this.
	LevelWarning

	// LevelInfo means an information message, essential enough to notify the end user (who is
	// not a developer of the application), but about something benign and that does not
	// says to any wrong behavior of the application.
	//
	// A message with this level is just logged if the Logger is setup with level no less that this.
	//
	// Recommended as the default level.
	LevelInfo

	// LevelDebug means a message non-essential for the end user, but useful for debugging
	// the application by its developer.
	//
	// A message with this level is just logged if the Logger is setup with level no less that this.
	LevelDebug

	// LevelTrace is for all other messages.
	//
	// For example, sometimes in complex processes/application it sometimes useful
	// to have an extra layer to put an insane amount put all useless messages, which
	// may suddenly become very useful for some very difficult debug process.
	//
	// A message with this level is just logged if the Logger is setup with level no less that this.
	LevelTrace

	// EndOfLevel just defines a maximum level + 1.
	EndOfLevel
)

Variables

This section is empty.

Functions

This section is empty.

Types

type Config

type Config struct {
	// GetCallerPC defines the line of code which invoked the logging entry,
	// see the description of "GetCallerPC" .
	GetCallerFunc GetCallerPC

	// ImplementationSpecificOptions is a set of Logger-implementation-specific
	// options.
	ImplementationSpecificOptions []any
}

Config is a resulting configuration of a collection of Options.

type Emitter

type Emitter interface {
	Flusher

	// Emit just logs the provided Entry. It does not modify it.
	//
	// If it is reasonably possible then the implementation of Emitter
	// should not panic or os.Exit even if the Level is Fatal or Panic.
	// Otherwise for example it prevents from logging a problem through other
	// Emitters if there are multiple of them.
	Emit(entry *Entry)
}

Emitter is a log entry sender. It is not obligated to provide functionality for logging levels, hooks, contextual fields or any other fancy stuff, and it just sends what is was told to.

Note: Some specific Emitter implementations may support filtering of messages based on log level or/and add structured fields internally or do other stuff. But it is expected that even if a Emitter actually supports that kind of functionality, it will still be by default configured in a way like it has no such functionality (thus maximal logging level, no contextual fields and so on). However, if a Emitter is returned from a Logger, then it may (or may not) inherit properties of Logger (like logging level or structured fields). The undefined behavior here is left intentionally to provide more flexibility to Logger implementations to achieve better performance. It is considered than any Emitter managed by a Logger may have any configuration the Logger may consider the optimal one at any moment.

All methods are thread-safe.

type Emitters

type Emitters []Emitter

Emitters is a set of Emitter-s.

Only the last Emitter is allowed to panic or/and os.Exit (on Level-s Fatal and Panic). Do not use a set of Emitters if this rule is not satisfied. Check guarantees these provided by specific a Emitter implementation.

func (Emitters) Emit

func (s Emitters) Emit(entry *Entry)

Emit implements Emitter.

func (Emitters) Flush

func (s Emitters) Flush()

Flush implements Emitter.

type Entry

type Entry struct {
	// Timestamp defines the time moment when the entry was issued (for example method `Debugf` was called).
	Timestamp time.Time

	// Level is the logging level of the entry.
	Level Level

	// Message is an arbitrary string explaining the event, an unstructured message.
	// It is set by `*f` (e.g. `Debugf`) functions, by argument "message" in
	// LogFields/TraceFields/etc function or by unstructured values in Log/Trace/Debug/etc functions.
	Message string

	// Fields implements ways to read the structured fields to be logged.
	//
	// To avoid copying the fields into an intermediate format (which most likely
	// will be transformed into something else anyway in the Logger implementation)
	// we provide here an accessor to Fields instead of compiled Fields themselves.
	Fields field.AbstractFields

	// TraceIDs is the collection of unique IDs associated with this logging entry.
	// For example it may be useful to attach an unique ID to each network request,
	// so that it will be possible to fetch the whole log of processing for any network request.
	TraceIDs belt.TraceIDs

	// Properties defines special implementation-specific behavior related to the Entry.
	//
	// See description of EntryProperty.
	Properties EntryProperties

	// Caller is the Program Counter of the position in the code which initiated the logging
	// of the entry.
	//
	// See also OptionGetCallerFunc and DefaultGetCallerFunc.
	Caller runtime.PC
}

Entry a single log entry to be logged/written.

type EntryProperties

type EntryProperties []EntryProperty

EntryProperties is a collection of EntryProperty-es.

func (EntryProperties) Add

Add returns the concatenation of EntryProperties.

Note! It does not work similar to classical `append` function, instead it nests two slices into a new slice to optimize for CPU and RAM (by avoiding extra memory allocation and copying).

func (EntryProperties) Has

Has returns true if the collection of properties contains a specific EntryProperty. It should be equal by both: type and value.

type EntryProperty

type EntryProperty any

EntryProperty defines special implementation-specific behavior related to a specific Entry.

Any Emitter implementation, Hook or other tool may use it for internal or/and external needs.

For example, a Emitter may support both async and sync logging, and it could be possible to request sync logging through a property.

Another example is: if an error monitor and a logger are hooked to each other then these properties could be used to avoid loops (to mark already processed entries).

type Flusher

type Flusher interface {
	// Flush forces to flush all buffers.
	Flush()
}

Flusher defines a method to flush all buffers.

type GetCallerPC

type GetCallerPC = func() runtime.PC

GetCallerPC is a function which returns the Program Counter (PC) of the piece of code which invoked logging the entry.

It is called by a Logger to fill the value Entry.Caller.

var DefaultGetCallerFunc GetCallerPC = func() runtime.PC {
	return runtime.Caller(nil)
}

DefaultGetCallerFunc is the default GetCallerPC function. It is used if a Logger was initialized without option OptionGetCallerFunc.

type Hook

type Hook interface {
	// ProcessLogEntry is called right before sending the Entry to a Emitter.
	//
	// If the returned value is false, then the sending and processing by other hooks
	// are cancelled.
	//
	// It is allowed to modify the entry.
	ProcessLogEntry(*Entry) bool

	// Flush gracefully empties any buffers the hook may have.
	Flush()
}

Hook is a pre-processor for log entries. It may for example modify them or cancel them.

type Hooks

type Hooks []Hook

Hooks is a collection of Hook-s.

func (Hooks) Flush

func (s Hooks) Flush()

Flush implements Hook.

func (Hooks) ProcessLogEntry

func (s Hooks) ProcessLogEntry(e *Entry) bool

ProcessLogEntry implements Hook.

type Level

type Level int

Level is a severity of a message/Entry.

There are two ways to use Level: 1. To define a severity of a specific message/Entry (when logging). 2. To define a severity of messages/Entries be actually logged (when configuring a Logger).

func ParseLogLevel

func ParseLogLevel(in string) (Level, error)

ParseLogLevel parses incoming string into a Level and returns LevelUndefined with an error if an unknown logging level was passed.

func (Level) Byte

func (logLevel Level) Byte() byte

Byte is similar to String, but returns a single byte, which describes in a human-readable way the logging level.

func (*Level) Set

func (logLevel *Level) Set(value string) error

Set updates the logging level values based on the passed string value. This method just implements flag.Value and pflag.Value.

func (Level) String

func (logLevel Level) String() string

String just implements fmt.Stringer, flag.Value and pflag.Value.

func (*Level) Type

func (logLevel *Level) Type() string

Type just implements pflag.Value.

type Logger

type Logger interface {
	belt.Tool

	// Logf logs an unstructured message. Though, of course, all
	// contextual structured fields will also be logged.
	//
	// This method exists mostly for convenience, for people who
	// has not got used to proper structured logging, yet.
	// See `LogFields` and `Log`. If one have variables they want to
	// log, it is better for scalable observability to log them
	// as structured values, instead of injecting them into a
	// non-structured string.
	Logf(level Level, format string, args ...any)

	// LogFields logs structured fields with a explanation message.
	//
	// Anything that implements field.AbstractFields might be used
	// as a collection of fields to be logged.
	//
	// Examples:
	//
	// 	l.LogFields(logger.LevelDebug, "new_request", field.Fields{{Key: "user_id", Value: userID}, {Key: "group_id", Value: groupID}})
	// 	l.LogFields(logger.LevelInfo, "affected entries", field.Field{Key: "mysql_affected", Value: affectedRows})
	// 	l.LogFields(logger.LevelError, "unable to fetch user info", request) // where `request` implements field.AbstractFields
	//
	// Sometimes it is inconvenient to manually describe each field,
	// and for such cases see method `Log`.
	LogFields(level Level, message string, fields field.AbstractFields)

	// Log extracts structured fields from provided values, joins
	// the rest into an unstructured message and logs the result.
	//
	// This function provides convenience (relatively to LogFields)
	// at cost of a bit of performance.
	//
	// There are few ways to extract structured fields, which are
	// applied for each value from `values` (in descending priority order):
	// 1. If a `value` is an `*Entry` then the Entry is used (with its fields).
	//    This works only if this is the only argument. Otherwise it is
	//    threated as a simple structure (see point #3).
	// 2. If a `value` implements field.AbstractFields then ForEachField method
	//    is used (so it is become similar to LogFields).
	// 3. If a `value` is a structure (or a pointer to a structure) then
	//    fields of the structure are interpreted as structured fields
	//    to be logged (see explanation below).
	// 4. If a `value` is a map then fields a constructed out of this map.
	//
	// Structured arguments are processed effectively the same
	// as they would have through a sequence of WithField/WithFields.
	//
	// Everything that does not fit into any of the rules above is just
	// joined into an unstructured message (and works the same way
	// as `message` in LogFields).
	//
	// How structures are parsed:
	// Structures are parsed recursively. Each field name of the path in a tree
	// of structures is added to the resulting field name (for example in "struct{A struct{B int}}"
	// the field name will be `A.B`).
	// To enforce another name use tag `log` (for example "struct{A int `log:"anotherName"`}"),
	// to prevent a field from logging use tag `log:"-"`.
	//
	// Examples:
	//
	// 	user, err := getUser()
	// 	if err != nil {
	// 		l.Log(logger.LevelError, err)
	// 		return err
	// 	}
	// 	l.Log(logger.LevelDebug, "current user", user) // fields of structure "user" will be logged
	// 	l.Log(logger.LevelDebug, map[string]any{"user_id": user.ID, "group_id", user.GroupID})
	// 	l.Log(logger.LevelDebug, field.Fields{{Key: "user_id", Value: user.ID}, {Key: "group_id", Value: user.GroupID}})
	// 	l.Log(logger.LevelDebug, "current user ID is ", user.ID, " and group ID is ", user.GroupID) // will result into message "current user ID is 1234 and group ID is 5678".
	Log(level Level, values ...any)

	// Emitter returns the Emitter (see the description of interface "Emitter").
	Emitter() Emitter

	// Level returns the current logging level (see description of "Level").
	Level() Level

	// TraceFields is just a shorthand for LogFields(logger.LevelTrace, ...)
	TraceFields(message string, fields field.AbstractFields)

	// DebugFields is just a shorthand for LogFields(logger.LevelDebug, ...)
	DebugFields(message string, fields field.AbstractFields)

	// InfoFields is just a shorthand for LogFields(logger.LevelInfo, ...)
	InfoFields(message string, fields field.AbstractFields)

	// WarnFields is just a shorthand for LogFields(logger.LevelWarn, ...)
	WarnFields(message string, fields field.AbstractFields)

	// ErrorFields is just a shorthand for LogFields(logger.LevelError, ...)
	ErrorFields(message string, fields field.AbstractFields)

	// PanicFields is just a shorthand for LogFields(logger.LevelPanic, ...)
	//
	// Be aware: Panic level also triggers a `panic`.
	PanicFields(message string, fields field.AbstractFields)

	// FatalFields is just a shorthand for LogFields(logger.LevelFatal, ...)
	//
	// Be aware: Panic level also triggers an `os.Exit`.
	FatalFields(message string, fields field.AbstractFields)

	// Trace is just a shorthand for Log(logger.LevelTrace, ...)
	Trace(values ...any)

	// Debug is just a shorthand for Log(logger.LevelDebug, ...)
	Debug(values ...any)

	// Info is just a shorthand for Log(logger.LevelInfo, ...)
	Info(values ...any)

	// Warn is just a shorthand for Log(logger.LevelWarn, ...)
	Warn(values ...any)

	// Error is just a shorthand for Log(logger.LevelError, ...)
	Error(values ...any)

	// Panic is just a shorthand for Log(logger.LevelPanic, ...)
	//
	// Be aware: Panic level also triggers a `panic`.
	Panic(values ...any)

	// Fatal is just a shorthand for Log(logger.LevelFatal, ...)
	//
	// Be aware: Fatal level also triggers an `os.Exit`.
	Fatal(values ...any)

	// Tracef is just a shorthand for Logf(logger.LevelTrace, ...)
	Tracef(format string, args ...any)

	// Debugf is just a shorthand for Logf(logger.LevelDebug, ...)
	Debugf(format string, args ...any)

	// Infof is just a shorthand for Logf(logger.LevelInfo, ...)
	Infof(format string, args ...any)

	// Warnf is just a shorthand for Logf(logger.LevelWarn, ...)
	Warnf(format string, args ...any)

	// Errorf is just a shorthand for Logf(logger.LevelError, ...)
	Errorf(format string, args ...any)

	// Panicf is just a shorthand for Logf(logger.LevelPanic, ...)
	//
	// Be aware: Panic level also triggers a `panic`.
	Panicf(format string, args ...any)

	// Fatalf is just a shorthand for Logf(logger.LevelFatal, ...)
	//
	// Be aware: Fatal level also triggers an `os.Exit`.
	Fatalf(format string, args ...any)

	// WithLevel returns a logger with logger level set to the given argument.
	//
	// See also the description of type "Level".
	WithLevel(Level) Logger

	// WithPreHooks returns a Logger which includes/appends pre-hooks from the arguments.
	//
	// See also description of "PreHook".
	//
	// Special case: to reset hooks use `WithPreHooks()` (without any arguments).
	WithPreHooks(...PreHook) Logger

	// WithHooks returns a Logger which includes/appends hooks from the arguments.
	//
	// See also description of "Hook".
	//
	// Special case: to reset hooks use `WithHooks()` (without any arguments).
	WithHooks(...Hook) Logger

	// WithField returns the logger with the added field (used for structured logging).
	WithField(key string, value any, props ...field.Property) Logger

	// WithFields returns the logger with the added fields (used for structured logging)
	WithFields(fields field.AbstractFields) Logger

	// WithMessagePrefix adds a string to all messages logged through the derived logger.
	WithMessagePrefix(prefix string) Logger

	// WithEntryProperties adds props to EntryProperties of each emitted Entry.
	// This could be used only for enabling implementation-specific behavior.
	WithEntryProperties(props ...EntryProperty) Logger
}

Logger is an abstract generic structured logger. It is supposed to be one of the belt.Tools provided by the Belt. And therefore interface supposed to be used by end users of the `logger` package, so it already contains syntax sugar.

All methods are thread-safe.

For an optimized interface with the same functionality use interface CompactLogger.

type Option

type Option interface {
	// contains filtered or unexported methods
}

Option is an abstract option which changes the behavior of a Logger.

type OptionGetCallerFunc

type OptionGetCallerFunc GetCallerPC

OptionGetCallerFunc overrides GetCallerPC (see description of "GetCallerPC").

type Options

type Options []Option

Options is a collection of Option-s.

func (Options) Config

func (s Options) Config() Config

Config returns the resulting configuration of a collection of Options.

type PreHook

type PreHook interface {
	// ProcessInput is executed when functions Log, Trace, Debug, Info, Warn, Error, Panic and Fatal are called.
	//
	// TraceIDs are provided by Logger/CompactLogger and the rest arguments are just passed-through.
	ProcessInput(belt.TraceIDs, Level, ...any) PreHookResult

	// ProcessInputf is executed when functions Logf, Tracef, Debugf, Infof, Warnf, Errorf, Panicf and Fatalf are called.
	//
	// TraceIDs are provided by Logger/CompactLogger and the rest arguments are just passed-through.
	ProcessInputf(belt.TraceIDs, Level, string, ...any) PreHookResult

	// ProcessInputf is executed when functions LogFields, TraceFields, DebugFields, InfoFields, WarnFields, ErrorFields, PanicFields and FatalFields are called.
	//
	// TraceIDs are provided by Logger/CompactLogger and the rest arguments are just passed-through.
	ProcessInputFields(belt.TraceIDs, Level, string, field.AbstractFields) PreHookResult
}

PreHook is executed very early in a Logger, allowing to discard or change an Entry before any essential computations are done.

For example it may be useful for samplers.

type PreHookResult

type PreHookResult struct {
	// Skip forces a Logger to do not log this Entry.
	Skip bool

	// ExtraFields adds additional fields to the Entry.
	ExtraFields field.AbstractFields

	// ExtraEntryProperties adds additional Entry.Properties.
	ExtraEntryProperties EntryProperties
}

PreHookResult is a result of computations returned by a PreHook.

type PreHooks

type PreHooks []PreHook

PreHooks is a collection of PreHook-s.

func (PreHooks) ProcessInput

func (s PreHooks) ProcessInput(traceIDs belt.TraceIDs, level Level, values ...any) PreHookResult

ProcessInput implements PreHook.

func (PreHooks) ProcessInputFields

func (s PreHooks) ProcessInputFields(traceIDs belt.TraceIDs, level Level, message string, addFields field.AbstractFields) PreHookResult

ProcessInputFields implements PreHook.

func (PreHooks) ProcessInputf

func (s PreHooks) ProcessInputf(traceIDs belt.TraceIDs, level Level, format string, args ...any) PreHookResult

ProcessInputf implements PreHook.

Jump to

Keyboard shortcuts

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