Documentation ¶
Overview ¶
Package logger provides logging mechanism for SLAV projects. It was created, as we didn't find a logger fitting our requirements:
* have syslog-like levels;
* do not panic with highest priority log;
* have structured log entities (to allow automated parsing).
Basics ¶
The usage of logger is really simple:
if data, err := someFunction(ctx); err != nil{ logger.WithError(err).WithProperty("context", ctx).Warning("Some warning.") }
Below, you can see output from logger with default settings. You can adjust it to your liking (see Backend section).
[0.000093] [WAR] [filename.go:11] "Some warning." {context:someFuncInput;error:"error msg";} ^timestamp ^lvl ^call context ^message ^properties ^error
Where:
* Timestamp - time of log creation - set during log entity processing;
* Level - level of log message entity - defined during call to a logging function;
* CallContext - source code context - set during log entity processing;
* Message - string part of log message entity - defined during call to a logging function;
* Properties - a key-value map of log message entities - defined by calls of: WithProperty, WithProperties and WithError functions.
Usage ¶
The simplest use-case would be to use default logger (residing in the logger package):
logger.Warning("Some warning.")
You can also create your instance of logger and customize it:
// Create new instance of Logger. log := logger.NewLogger() // Set threshold to omit logs below Notice level. log.SetThreshold(logger.NoticeLevel) // Register custom backend. log.AddBackend("myBackend", Backend{ Filter: NewFilterPassAll(), Serializer: NewSerializerJSON(), Writer: NewWriterFile(filename, 0444), }) // Set the logger as default. logger.SetDefault(log)
Logging entries ¶
There are 8 log levels defined - exactly matching syslog levels. Please refer to documentation of type Level for consts names.
To log an entity with one of these levels simply use dedicated method of Logger. For every log level there are 2 methods available: normal and formatted that can be used the same way fmt.Print and fmt.Printf are:
logger.Notice("You were notified!") logger.Noticef("You were notified about %s!", "usage of logger")
You can also use generic methods: Log, Logf which require level as the first parameter.
Adding more information ¶
To make parsing of logger messages easier, you should use logger.Properties. Properties can be serialized separately and easily parsed. WithProperty and WithProperties methods insert new or update existing key-value properties of the log message entity, e.g.
logger.WithProperty("ID", 17).Info("New object created.") logger.WithProperties(logger.Properties{ name: "John", lastname: "Covalsky", }).Critical("Object deceased.")
There is also a special property for logging errors than can be added by WithError function:
result, err := doStuff() if err != nil { logger.WithError(err).Error("Getting things done failed.") }
Every log message entity gets CallContext during processing, containing:
* Path - path the source file from which a log was created;
* File - filename of the source file;
* Line - line number;
* Package - package name;
* Type - name of type for which method was defined (in case of methods only);
* Function - name of function or method.
It is up to Serializer used in Backends (described further down this document) which information is written to logs.
There are situations when some kind of auxiliary helper functions log an error. In such case your intention is probably to have context of calling the helper function rather than helper function itself. IncDepth method can be used to change the default call stack depth and get call context of the caller, e.g.
... 15 func exitOnErr(msg string, err error) { 16 if err != nil { 17 logger.IncDepth(1).WithError(err).Error(msg + " IncDep(1)") 18 logger.WithError(err).Error(msg) 19 os.Exit(1) 20 } 21 } 22 23 func main() { 24 obj, err := NewObj() 25 exitOnErr("Failed to create object.", err) 26 }
Will give you following (when default settings are used):
[0.000099] [ERR] [yourapp.go:25] "Failed to create object. IncDep(1)" {error:"error msg";} [0.000209] [ERR] [yourapp.go:18] "Failed to create object." {error:"error msg";}
If methods from this paragraph are run on an existing Entry structure, they modify and return it. If they are run on Logger structure, they create and return new Entry structure with defined properties.
Processing log messages ¶
Every log message entity is processed after calling one of Log, Logf, Debug, Debugf, Info, Infof, ... logging functions.
Processing of an entity consist of following steps:
1) Verification of threshold. If it fails, the log entity is dropped.
2) Adding timestamp and call context.
3) Passing an Entry structure to every Backend registered in Logger and continuing processing in every backend.
Backends ¶
Backends are customizable parts of logger that allow filtering logs, defining the way they are formatted and choosing the destination where they are finally written.
Logger can have multiple backends registered. Every backend works independently, so e.g. filtering an Entry by one of them does not affect processing the log entitty in another one. Backends are identified with name (string), so adding new backend with a name that is already used, will replace old backend.
Multiple backends with different filters can be used for logging specific entities into additional files, logs, network locations, etc. For example: all security logs or network logs containing some special property can be passed to specific files.
Backends can be dynamically added or removed from Logger with following functions:
* AddBackend - add (or replace) a single backend;
* RemoveBackend - remove a single backend;
* RemoveAllBackends - clear all backends collection from Logger.
After removing all backends, you should add at least one, as your logger won't be able to log anything at all.
Every backend consists of 3 elements:
* Filter - for choosing which entities should be handled by the Backend;
* Serializer - for marshalling Entry structure into []byte;
* Writer - for saving/sending entities.
Filter ¶
Filter's role is to verify if log message entity should be logged by a backend. It is an interface that requires implementation of a single method:
Verify(*Entry) (bool, error)
There is a FilterPassAll implementation of Filter implementation. It accepts all log message entities.
Serializer ¶
Serializer's role is to marshal Entry structure to a slice of bytes, so it can be written by Writer. It is an interface that requires implementation of a single method:
Serialize(*Entry) ([]byte, error)
There are 2 example implementations of this interface:
* SerializerJSON - that uses JSON format for Entry serialization;
* SerializerText - that is intended to produce human-readable from of logs for consoles or log files.
Both of them are configurable. Please see fields' descriptions of structures defining them for details.
Writer ¶
Writer's role is to save/send serialized log message entity. It is an interface that requires implementation of a single method:
Write(level Level, p []byte) (n int, err error)
which is very similiar to io.Writer interface, but requiring a log level as there are some destinations (e.g. syslog) that require this information.
There are 3 example implementations of this interface:
* WriterFile - that saves log entities into files;
* WriterStderr - that prints logs to standard error output;
* WriterSyslog - that logs to system logger using log/syslog package.
See their constructors for more customized usage.
Index ¶
- Constants
- Variables
- func AddBackend(name string, b Backend)
- func Alert(args ...interface{})
- func Alertf(format string, args ...interface{})
- func Critical(args ...interface{})
- func Criticalf(format string, args ...interface{})
- func Debug(args ...interface{})
- func Debugf(format string, args ...interface{})
- func Emergency(args ...interface{})
- func Emergencyf(format string, args ...interface{})
- func Error(args ...interface{})
- func Errorf(format string, args ...interface{})
- func Info(args ...interface{})
- func Infof(format string, args ...interface{})
- func Log(level Level, args ...interface{})
- func Logf(level Level, format string, args ...interface{})
- func Notice(args ...interface{})
- func Noticef(format string, args ...interface{})
- func RemoveAllBackends()
- func RemoveBackend(name string) error
- func SetDefault(logger *Logger)
- func SetThreshold(level Level) error
- func Warning(args ...interface{})
- func Warningf(format string, args ...interface{})
- type Backend
- type CallContext
- type CallContextMode
- type Entry
- func (e *Entry) Alert(args ...interface{})
- func (e *Entry) Alertf(format string, args ...interface{})
- func (e *Entry) Critical(args ...interface{})
- func (e *Entry) Criticalf(format string, args ...interface{})
- func (e *Entry) Debug(args ...interface{})
- func (e *Entry) Debugf(format string, args ...interface{})
- func (e *Entry) Emergency(args ...interface{})
- func (e *Entry) Emergencyf(format string, args ...interface{})
- func (e *Entry) Error(args ...interface{})
- func (e *Entry) Errorf(format string, args ...interface{})
- func (e *Entry) IncDepth(dep int) *Entry
- func (e *Entry) Info(args ...interface{})
- func (e *Entry) Infof(format string, args ...interface{})
- func (e *Entry) Log(level Level, args ...interface{})
- func (e *Entry) Logf(level Level, format string, args ...interface{})
- func (e *Entry) Notice(args ...interface{})
- func (e *Entry) Noticef(format string, args ...interface{})
- func (e *Entry) Warning(args ...interface{})
- func (e *Entry) Warningf(format string, args ...interface{})
- func (e *Entry) WithError(err error) *Entry
- func (e *Entry) WithProperties(props Properties) *Entry
- func (e *Entry) WithProperty(key string, value interface{}) *Entry
- type Filter
- type FilterPassAll
- type Level
- type Logger
- func (l *Logger) AddBackend(name string, b Backend)
- func (l *Logger) Alert(args ...interface{})
- func (l *Logger) Alertf(format string, args ...interface{})
- func (l *Logger) Critical(args ...interface{})
- func (l *Logger) Criticalf(format string, args ...interface{})
- func (l *Logger) Debug(args ...interface{})
- func (l *Logger) Debugf(format string, args ...interface{})
- func (l *Logger) Emergency(args ...interface{})
- func (l *Logger) Emergencyf(format string, args ...interface{})
- func (l *Logger) Error(args ...interface{})
- func (l *Logger) Errorf(format string, args ...interface{})
- func (l *Logger) IncDepth(dep int) *Entry
- func (l *Logger) Info(args ...interface{})
- func (l *Logger) Infof(format string, args ...interface{})
- func (l *Logger) Log(level Level, args ...interface{})
- func (l *Logger) Logf(level Level, format string, args ...interface{})
- func (l *Logger) Notice(args ...interface{})
- func (l *Logger) Noticef(format string, args ...interface{})
- func (l *Logger) PassThreshold(level Level) bool
- func (l *Logger) RemoveAllBackends()
- func (l *Logger) RemoveBackend(name string) error
- func (l *Logger) SetThreshold(level Level) error
- func (l *Logger) Threshold() Level
- func (l *Logger) Warning(args ...interface{})
- func (l *Logger) Warningf(format string, args ...interface{})
- func (l *Logger) WithError(err error) *Entry
- func (l *Logger) WithProperties(props Properties) *Entry
- func (l *Logger) WithProperty(key string, value interface{}) *Entry
- type Properties
- type QuoteMode
- type Serializer
- type SerializerJSON
- type SerializerText
- type TimestampMode
- type Writer
- type WriterFile
- type WriterStderr
- type WriterSyslog
Constants ¶
const ( // EmergLevelStr is string representation of EmergLevel EmergLevelStr = "emergency" // AlertLevelStr is string representation of AlertLevel AlertLevelStr = "alert" // CritLevelStr is string representation of CritLevel CritLevelStr = "critical" // ErrLevelStr is string representation of ErrLevel ErrLevelStr = "error" // WarningLevelStr is string representation of WarningLevel WarningLevelStr = "warning" // NoticeLevelStr is string representation of NoticeLevel NoticeLevelStr = "notice" // InfoLevelStr is string representation of InfoLevel InfoLevelStr = "info" // DebugLevelStr is string representation of DebugLevel DebugLevelStr = "debug" // UnknownLevel is string representation of unknown logging level UnknownLevelStr = "unknown" )
Log levels strings
const ( // DefaultSerializerTextTimeFormat is the default date and time format. DefaultSerializerTextTimeFormat = time.RFC3339 // DefaultTimestampMode is the default mode for logging time stamp. DefaultTimestampMode = TimestampModeDiff // DefaultQuoteMode is the default quoting mode. DefaultQuoteMode = QuoteModeSpecialAndEmpty // DefaultCallContextMode is the default context mode. DefaultCallContextMode = CallContextModeCompact )
Define default SerializerText properties.
const ( // DefaultSerializerJSONTimestampFormat is the default date and time format. DefaultSerializerJSONTimestampFormat = time.RFC3339 )
const ( // DefaultThreshold is the default level of each newly created Logger. DefaultThreshold = InfoLevel )
const (
// ErrorProperty defines key of error property added to message by WithError functions.
ErrorProperty = "error"
)
Variables ¶
var ( // ErrInvalidLogLevel is returned in case of unknown log level usage. ErrInvalidLogLevel = errors.New("invalid log level") // ErrInvalidBackendName is returned in case of unknown backend name. ErrInvalidBackendName = errors.New("invalid backend name") // ErrInvalidEntry is returned in case of invalid entry struct. ErrInvalidEntry = errors.New("invalid log entry structure") )
Functions ¶
func AddBackend ¶
AddBackend adds or replaces a backend with given name in default logger.
func Alertf ¶
func Alertf(format string, args ...interface{})
Alertf logs alert level formatted message to default logger.
func Critical ¶
func Critical(args ...interface{})
Critical logs critical level message to default logger.
func Criticalf ¶
func Criticalf(format string, args ...interface{})
Criticalf logs critical level formatted message to default logger.
func Debugf ¶
func Debugf(format string, args ...interface{})
Debugf logs debug level formatted message to default logger.
func Emergency ¶
func Emergency(args ...interface{})
Emergency logs emergency level message to default logger.
func Emergencyf ¶
func Emergencyf(format string, args ...interface{})
Emergencyf logs emergency level formatted message to default logger.
func Errorf ¶
func Errorf(format string, args ...interface{})
Errorf logs error level formatted message to default logger.
func Infof ¶
func Infof(format string, args ...interface{})
Infof logs info level formatted message to default logger.
func Log ¶
func Log(level Level, args ...interface{})
Log builds log message and logs entry to default logger.
func Noticef ¶
func Noticef(format string, args ...interface{})
Noticef logs notice level formatted message to default logger.
func RemoveAllBackends ¶
func RemoveAllBackends()
RemoveAllBackends clears all backends from default logger.
func RemoveBackend ¶
RemoveBackend removes a backend with given name from default logger.
func SetThreshold ¶
SetThreshold defines default Logger's filter level. Only entries with level equal or less than threshold will be logged.
Types ¶
type Backend ¶
type Backend struct { // Logger points to Logger instance. Logger *Logger // Filter verifies if entry should be logged by a backend. Filter // Serializer converts entry into raw bytes slice. Serializer // Writer writes data to final destination. Writer }
Backend is responsible for serializing and writing log entries. It can also filter logs and process only some of them.
type CallContext ¶
type CallContext struct { Path string `json:"path"` File string `json:"file"` Line int `json:"line"` Package string `json:"package"` Type string `json:"type,omitempty"` Function string `json:"function"` }
CallContext defines log creation source code context.
type CallContextMode ¶
type CallContextMode uint8
CallContextMode defines possible modes of printing call source code context.
const ( // CallContextModeNone - no context is used. CallContextModeNone CallContextMode = iota // CallContextModeCompact - file name and line number are used. CallContextModeCompact // CallContextModeFunction - file name, line number and function name are used. CallContextModeFunction // CallContextModeFile - full file path and line number are used. CallContextModeFile // CallContextModePackage - package name, line number and function are used. CallContextModePackage )
type Entry ¶
type Entry struct { // Logger points to instance that manages this Entry. Logger *Logger // Level defines importance of log message. Level Level // Message contains actual log message. Message string // Properties hold key-value pairs of log message properties. Properties Properties // Timestamp stores point in time of log message creation. Timestamp time.Time // CallContext stores the source code context of log creation. CallContext *CallContext // contains filtered or unexported fields }
Entry defines a single log message entity.
func WithProperties ¶
func WithProperties(props Properties) *Entry
WithProperties creates a log message with multiple properties in default logger.
func WithProperty ¶
WithProperty creates a log message with a single property in default logger.
func (*Entry) Critical ¶
func (e *Entry) Critical(args ...interface{})
Critical logs critical level message.
func (*Entry) Emergency ¶
func (e *Entry) Emergency(args ...interface{})
Emergency logs emergency level message.
func (*Entry) Emergencyf ¶
Emergencyf logs emergency level formatted message.
func (*Entry) Notice ¶
func (e *Entry) Notice(args ...interface{})
Notice logs notice level message.
func (*Entry) Warning ¶
func (e *Entry) Warning(args ...interface{})
Warning logs warning level message.
func (*Entry) WithProperties ¶
func (e *Entry) WithProperties(props Properties) *Entry
WithProperties adds properties to the log message.
func (*Entry) WithProperty ¶
WithProperty adds a single property to the log message.
type Filter ¶
type Filter interface { // Verify decides if log entry should be processed by a backend. // It returns true if entry should be processed. // It returns false if entry should be ignored. Verify(*Entry) (bool, error) }
Filter verifies if entry should be logged by a backend.
type FilterPassAll ¶
type FilterPassAll struct{}
FilterPassAll is a dummy implementation of Filter interface which accepts all entries.
func NewFilterPassAll ¶
func NewFilterPassAll() *FilterPassAll
NewFilterPassAll creates and returns a new FilterPassAll object.
type Level ¶
type Level uint32
Level of log entries importance.
const ( // EmergLevel is used when system is unusable. // It matches syslog's LOG_EMERG level. EmergLevel Level = iota // AlertLevel is used when action must be taken immediately. // It matches syslog's LOG_ALERT level. AlertLevel // CritLevel is used when critical conditions occur. // It matches syslog's LOG_CRIT level. CritLevel // ErrLevel is used when error conditions occur. // It matches syslog's LOG_ERR level. ErrLevel // WarningLevel is used when warning conditions occur. // It matches syslog's LOG_WARNING level. WarningLevel // NoticeLevel is used when normal, but significant, conditions occur. // It matches syslog's LOG_NOTICE level. NoticeLevel // InfoLevel is used for logging informational message. // It matches syslog's LOG_INFO level. InfoLevel // DebugLevel is used for logging debug-level message. // It matches syslog's LOG_DEBUG level. DebugLevel )
The log level's definitions are consistent with Unix syslog levels.
func StringToLevel ¶
StringToLevel converts string value to loggers' Level type. It is to be used when providing user with ability to specify logging level - e.g. setting log level via cli flag.. If string is not matched, invalid level (DebugLevel+1) and ErrInvalidLogLevel is returned.
type Logger ¶
type Logger struct {
// contains filtered or unexported fields
}
Logger defines type for a single logger instance.
func NewLogger ¶
func NewLogger() *Logger
NewLogger creates a new Logger instance with default configuration. Default level threshold is set to InfoLevel.
func (*Logger) AddBackend ¶
AddBackend adds or replaces a backend with given name.
func (*Logger) Critical ¶
func (l *Logger) Critical(args ...interface{})
Critical logs critical level message.
func (*Logger) Emergency ¶
func (l *Logger) Emergency(args ...interface{})
Emergency logs emergency level message.
func (*Logger) Emergencyf ¶
Emergencyf logs emergency level formatted message.
func (*Logger) Notice ¶
func (l *Logger) Notice(args ...interface{})
Notice logs notice level message.
func (*Logger) PassThreshold ¶
PassThreshold verifies if message with given level passes threshold and should be logged.
func (*Logger) RemoveAllBackends ¶
func (l *Logger) RemoveAllBackends()
RemoveAllBackends clears all backends.
func (*Logger) RemoveBackend ¶
RemoveBackend removes a backend with given name.
func (*Logger) SetThreshold ¶
SetThreshold defines Logger's filter level. Only entries with level equal or less than threshold will be logged.
func (*Logger) Warning ¶
func (l *Logger) Warning(args ...interface{})
Warning logs warning level message.
func (*Logger) WithProperties ¶
func (l *Logger) WithProperties(props Properties) *Entry
WithProperties creates a log message with multiple properties.
func (*Logger) WithProperty ¶
WithProperty creates a log message with a single property.
type Properties ¶
type Properties map[string]interface{}
Properties allow structurization of log messages by defining key-value properties.
type QuoteMode ¶
type QuoteMode uint8
QuoteMode defines possible quoting modes.
const ( // QuoteModeNone - no quoting is used. QuoteModeNone QuoteMode = iota // QuoteModeSpecial - values containing special characters are quoted. QuoteModeSpecial // QuoteModeSpecialAndEmpty - values containing special characters and empty are quoted. QuoteModeSpecialAndEmpty // QuoteModeAll - all values are quoted. QuoteModeAll )
type Serializer ¶
type Serializer interface { // Serialize converts entry to byte slice. Serialize(*Entry) ([]byte, error) }
Serializer converts entry into raw bytes slice. After that it is ready to be passed to Writer.
type SerializerJSON ¶
type SerializerJSON struct { // TimestampFormat defines format for displaying date and time. // See https://godoc.org/time#Time.Format description for details. TimestampFormat string }
SerializerJSON serializes entry to JSON format.
func NewSerializerJSON ¶
func NewSerializerJSON() *SerializerJSON
NewSerializerJSON creates and returns a new default SerializerJSON object.
type SerializerText ¶
type SerializerText struct { // TimeFormat defines format for displaying date and time. // Used only when TimestampMode is set to TimestampModeFull. // See https://godoc.org/time#Time.Format description for details. TimeFormat string // TimestampMode defines mode for logging date and time. TimestampMode TimestampMode // QuoteMode defines which values are quoted. QuoteMode QuoteMode // CallContextMode defines way of serializing source code context. CallContextMode CallContextMode // UseColors set to true enables usage of colors. UseColors bool // contains filtered or unexported fields }
SerializerText serializes entry to text format.
func NewSerializerText ¶
func NewSerializerText() *SerializerText
NewSerializerText creates and returns a new default SerializerText with default values.
type TimestampMode ¶
type TimestampMode uint8
TimestampMode defines possible time stamp logging modes.
const ( // TimestampModeNone - no time stamp used. TimestampModeNone TimestampMode = iota // TimestampModeDiff - seconds since creation of SerializerText. // Usualy it is equal to the binary start as logger and its serializer // are created mostly by packages' init functions. TimestampModeDiff // TimestampModeFull - date and time in UTC. TimestampModeFull )
type Writer ¶
Writer enhances io.Writer Write method with Level parameter.
Write writes len(p) bytes from p to the underlying data stream. It returns the number of bytes written from p (0 <= n <= len(p)) and any error encountered that caused the write to stop early. Write must return a non-nil error if it returns n < len(p). Write must not modify the slice data, even temporarily.
Implementations must not retain p.
type WriterFile ¶
type WriterFile struct {
// contains filtered or unexported fields
}
WriterFile is a simple wrapper for os.File opened in append mode. It implements Writer interface.
func NewWriterFile ¶
func NewWriterFile(filePath string, perm os.FileMode) *WriterFile
NewWriterFile opens given file in write mode for appending and returns a new WriterFile object wrapping that file. The file permissions can be set using perm parameter. It panics when opening a file is not possible.
type WriterStderr ¶
type WriterStderr struct {
// contains filtered or unexported fields
}
WriterStderr is a simple writer printing logs to standard error output (StdErr). It synchronizes writes with mutex. It implements Writer interface.
func NewWriterStderr ¶
func NewWriterStderr() *WriterStderr
NewWriterStderr creates a new WriterStderr object.
type WriterSyslog ¶
type WriterSyslog struct {
// contains filtered or unexported fields
}
WriterSyslog writes to syslog using standard log/syslog package. It implements Writer interface.
func NewWriterSyslog ¶
func NewWriterSyslog(network, raddr string, facility syslog.Priority, tag string) *WriterSyslog
NewWriterSyslog creates a new WriterSyslog object connecting it to the log daemon. Connection uses specified network and raddr address