Documentation ¶
Overview ¶
Package structlog provides structured logger which looks friendly as plain text (more like handcrafted vertical-aligned log lines which doesn't feels like key/value pairs) but also really useful as JSON (each important value in log line became separate key/value pair).
In short, with structlog you will have to write just this:
log := structlog.New() log.Warn("something goes wrong", "somevar", var, "err", err)
and structlog will take care of the rest (output plain text or JSON, format plain text output to make it easy to read, include in output extra key/value pairs - both added by you before that call and calculated automatically like caller's details or stack trace).
Well, not really. First you'll need to configure logger, to define what "easy to read" means in your case - but this has to be done just once, usually in main(), and then you'll get simple and powerful logging as promised above.
Overview ¶
It was designed to produce easy to read, vertically-aligned log lines while your project is small, and later, when your project will grow to use something like ELK Stack, switch by changing one option to produce easy to parse JSON log records.
You can log key/value pairs without bothering about output format (plain text or JSON) and then fine-tune it plain text output by:
- Re-ordering output values by choosing which keys should be output as prefix (before log message) and as suffix (after other keys).
- Defining internal order of prefix and suffix keys.
- Defining key/value output style using fmt.Sprintf 'verbs', including ability to output only value, without key name.
- Choosing which ones of pre-defined key/values to include in output:
- caller's package
- caller's function name
- caller's file and line
- multiline stack trace (a-la panic output)
Supported log levels: Err, Warn, Info and Debug.
On import it calls stdlib's log.SetFlags(0) and by default will use stdlib's log.Print() to output log lines - this is to make sure structlog's output goes at same place as logging from other packages (which often use stdlib's log).
Inheritance ¶
For convenience you may have multiple loggers, and create new logger in such a way to inherit all settings from existing logger. These settings often include predefined key/value pairs to be automatically output in each logged line in addition to logger formatting setting.
All loggers created using structlog.New() will inherit settings from logger in global variable structlog.DefaultLogger. So, usually you will configure structlog.DefaultLogger in your main(), to apply this configuration to each and every logger created in any other package of your application.
Then you can do some extra setup on your logger (usually - just add some default key/value pair which should be output by each log call), and call log.New() method to get new logger which will inherit this extra setup.
E.g. imagine HTTP middlewares: first will detect IP of connected client and store it in logger, second will check authentication and optionally add key/value pair with user ID - as result everything logged by your HTTP handler later using logger preconfigured by these middlewares will include remote IP and user ID in each log record - without needs to manually include it in each line where you log something.
Contents ¶
★ Creating a new logger:
New (function) - will inherit from structlog.DefaultLogger New (method) - will inherit from it's object NewZeroLogger - new empty logger (usually you won't need this)
★ Passing logger inside context.Context:
NewContext FromContext
★ Normal logging:
Debug Info Warn Err PrintErr - like Err, but don't return error (usually you won't need this)
★ Logging useful with defer:
DebugIfFail InfoIfFail WarnIfFail ErrIfFail Recover
★ Delayed logging:
WrapErr
★ Configuring structlog.DefaultLogger in your main():
AppendPrefixKeys PrependSuffixKeys SetKeyValFormat SetKeysFormat SetLogFormat SetPrefixKeys SetSuffixKeys SetTimeFormat SetTimeValFormat
★ Configuring current logger:
SetDefaultKeyvals AddCallDepth
★ Handling log levels:
IsDebug IsInfo ParseLevel SetLogLevel
★ Passing this logger to 3rd-party packages which expects interface of stdlib's log.Logger:
Fatal Fatalf Fatalln Panic Panicf Panicln Print Printf Println
★ Redirecting log output (useful to redirect to ioutil.Discard in tests):
SetOutput SetPrinter
Index ¶
- Constants
- Variables
- func NewContext(ctx context.Context, log *Logger) context.Context
- func ParseLevel(levelName string) logLevel
- type Logger
- func (l *Logger) AddCallDepth(depth int) *Logger
- func (l *Logger) AppendPrefixKeys(keys ...string) *Logger
- func (l *Logger) Debug(msg interface{}, keyvals ...interface{})
- func (l *Logger) DebugIfFail(f func() error, keyvals ...interface{})
- func (l *Logger) Err(msg interface{}, keyvals ...interface{}) error
- func (l *Logger) ErrIfFail(f func() error, keyvals ...interface{})
- func (l *Logger) Fatal(v ...interface{})
- func (l *Logger) Fatalf(format string, v ...interface{})
- func (l *Logger) Fatalln(v ...interface{})
- func (l *Logger) Info(msg interface{}, keyvals ...interface{})
- func (l *Logger) InfoIfFail(f func() error, keyvals ...interface{})
- func (l *Logger) IsDebug() bool
- func (l *Logger) IsInfo() bool
- func (l *Logger) New(defaultKeyvals ...interface{}) *Logger
- func (l *Logger) Panic(v ...interface{})
- func (l *Logger) Panicf(format string, v ...interface{})
- func (l *Logger) Panicln(v ...interface{})
- func (l *Logger) PrependSuffixKeys(keys ...string) *Logger
- func (l *Logger) Print(v ...interface{})
- func (l *Logger) PrintErr(msg interface{}, keyvals ...interface{})
- func (l *Logger) Printf(format string, v ...interface{})
- func (l *Logger) Println(v ...interface{})
- func (l *Logger) Recover(err *error, keyvals ...interface{})
- func (l *Logger) SetDefaultKeyvals(keyvals ...interface{}) *Logger
- func (l *Logger) SetKeyValFormat(format string) *Logger
- func (l *Logger) SetKeysFormat(keysFormat map[string]string) *Logger
- func (l *Logger) SetLogFormat(format logFormat) *Logger
- func (l *Logger) SetLogLevel(level logLevel) *Logger
- func (l *Logger) SetOutput(w io.Writer) *Logger
- func (l *Logger) SetPrefixKeys(keys ...string) *Logger
- func (l *Logger) SetPrinter(printer Printer) *Logger
- func (l *Logger) SetSuffixKeys(keys ...string) *Logger
- func (l *Logger) SetTimeFormat(format string) *Logger
- func (l *Logger) SetTimeValFormat(format string) *Logger
- func (l *Logger) Warn(msg interface{}, keyvals ...interface{})
- func (l *Logger) WarnIfFail(f func() error, keyvals ...interface{})
- func (l *Logger) WrapErr(err error, keyvals ...interface{}) error
- type Printer
- type PrinterFunc
Examples ¶
Constants ¶
const ( Text logFormat = iota JSON )
Log formats.
const ( DBG logLevel = iota INF WRN ERR )
Log levels.
const ( DefaultLogFormat = Text DefaultLogLevel = DBG DefaultKeyValFormat = ` %s=%v` DefaultTimeFormat = time.StampMicro DefaultTimeValFormat = time.RFC3339Nano MissingValue = "(MISSING)" )
Defaults.
const ( KeyTime = "_t" // Key name used to output current time. KeyApp = "_a" // Key name used to output app name. KeyPID = "_p" // Key name used to output PID. KeyLevel = "_l" // Key name used to output log level. KeyUnit = "_u" // Key name used to output unit/module/package name. KeyMessage = "_m" // Key name used to output log message. KeyFunc = "_f" // Key name used to output caller's function name. KeySource = "_s" // Key name used to output caller's file and line. KeyStack = "__" // Key name used to output multiline stack trace. )
Predefined key names.
const Auto = "\x00"
Auto can be used as value for KeyTime, KeyUnit and KeyStack to automatically generate their values: current time, caller package's directory name and full stack of the current goroutine.
Variables ¶
var DefaultLogger = NewZeroLogger( KeyApp, path.Base(os.Args[0]), KeyPID, os.Getpid(), ).SetPrefixKeys( KeyTime, KeyApp, KeyPID, KeyLevel, KeyUnit, ).SetSuffixKeys( KeyFunc, KeySource, KeyStack, ).SetKeysFormat(map[string]string{ KeyTime: "%[2]s ", KeyApp: "%[2]s", KeyPID: "[%[2]d]", KeyLevel: " %[2]s", KeyUnit: " %[2]s:", KeyMessage: " %#[2]q", KeyFunc: " \t@ %[2]s", KeySource: "(%[2]s)", KeyStack: "\n%[2]s", })
DefaultLogger provides sane defaults inherited by new logger objects created with New(). Feel free to change it settings when your app start.
Functions ¶
func NewContext ¶ added in v0.3.0
NewContext returns a new Context that carries value log.
func ParseLevel ¶
func ParseLevel(levelName string) logLevel
ParseLevel convert levelName from flag or config file into logLevel.
Types ¶
type Logger ¶
Logger implements structured logger.
func FromContext ¶ added in v0.3.0
FromContext returns the Logger value stored in ctx or defaultLog or New() if defaultLog is nil.
func New ¶
func New(defaultKeyvals ...interface{}) *Logger
New creates and returns a new logger which inherits all settings from DefaultLogger.
func NewZeroLogger ¶
func NewZeroLogger(defaultKeyvals ...interface{}) *Logger
NewZeroLogger creates and returns a new logger with empty settings.
func (*Logger) AddCallDepth ¶
AddCallDepth will add depth to amount of skipped stack frames while calculating default values for KeyUnit, KeyFunc and KeySource.
Use it if you want to report from perspective of your caller.
It doesn't creates a new logger, it returns l just for convenience.
func (*Logger) AppendPrefixKeys ¶
AppendPrefixKeys appends keys to current prefixKeys for l.
XXX Panics if will be called after using l (or logger created using l.New()) to log anything.
It doesn't creates a new logger, it returns l just for convenience.
func (*Logger) Debug ¶
func (l *Logger) Debug(msg interface{}, keyvals ...interface{})
Debug log defaultKeyvals, msg and keyvals with level DBG.
func (*Logger) DebugIfFail ¶
DebugIfFail will run f and log defaultKeyvals, returned error and keyvals with level DBG if returned error is not nil.
defer log.DebugIfFail(file.Close)
func (*Logger) Err ¶
Err log defaultKeyvals, msg and keyvals with level ERR and returns first arg of error type or msg if there are no errors in args.
return log.Err("message to log", "error to log and return", err) return log.Err(errors.New("error to log and return"), "error to log", err)
func (*Logger) ErrIfFail ¶
ErrIfFail will run f and log defaultKeyvals, returned error and keyvals with level ERR if returned error is not nil.
defer log.ErrIfFail(file.Close)
func (*Logger) Fatal ¶
func (l *Logger) Fatal(v ...interface{})
Fatal works like log.Fatal. Use level ERR. Also output defaultKeyvals for prefixKeys/suffixKeys.
func (*Logger) Fatalf ¶
Fatalf works like log.Fatalf. Use level ERR. Also output defaultKeyvals for prefixKeys/suffixKeys.
func (*Logger) Fatalln ¶
func (l *Logger) Fatalln(v ...interface{})
Fatalln works like log.Fatalln. Use level ERR. Also output defaultKeyvals for prefixKeys/suffixKeys.
func (*Logger) Info ¶
func (l *Logger) Info(msg interface{}, keyvals ...interface{})
Info log defaultKeyvals, msg and keyvals with level INF.
func (*Logger) InfoIfFail ¶
InfoIfFail will run f and log defaultKeyvals, returned error and keyvals with level INF if returned error is not nil.
defer log.InfoIfFail(file.Close)
func (*Logger) Panic ¶
func (l *Logger) Panic(v ...interface{})
Panic works like log.Panic. Use level ERR. Also output defaultKeyvals for prefixKeys/suffixKeys.
func (*Logger) Panicf ¶
Panicf works like log.Panicf. Use level ERR. Also output defaultKeyvals for prefixKeys/suffixKeys.
func (*Logger) Panicln ¶
func (l *Logger) Panicln(v ...interface{})
Panicln works like log.Panicln. Use level ERR. Also output defaultKeyvals for prefixKeys/suffixKeys.
func (*Logger) PrependSuffixKeys ¶
PrependSuffixKeys prepend keys to current suffixKeys for l.
XXX Panics if will be called after using l (or logger created using l.New()) to log anything.
It doesn't creates a new logger, it returns l just for convenience.
func (*Logger) Print ¶
func (l *Logger) Print(v ...interface{})
Print works like log.Print. Use level INF. Also output defaultKeyvals for prefixKeys/suffixKeys.
func (*Logger) PrintErr ¶
func (l *Logger) PrintErr(msg interface{}, keyvals ...interface{})
PrintErr log defaultKeyvals, msg and keyvals with level ERR.
In most cases you should use Err instead, to both log and handle error.
func (*Logger) Printf ¶
Printf works like log.Printf. Use level INF. Also output defaultKeyvals for prefixKeys/suffixKeys.
func (*Logger) Println ¶
func (l *Logger) Println(v ...interface{})
Println works like log.Println. Use level INF. Also output defaultKeyvals for prefixKeys/suffixKeys.
func (*Logger) Recover ¶
Recover calls recover(), and if it returns non-nil, then log defaultKeyvals, value returned by recover() and keyvals with stack trace and level ERR plus stores value returned by recover() into err if err is not nil.
defer log.Recover(nil) func PanicToErr() (err error) { defer log.Recover(&err); ... }
func (*Logger) SetDefaultKeyvals ¶
SetDefaultKeyvals add/replace values for keys in defaultKeyvals.
The keyvals must be a list of key/value pairs, keys must be a string. In case of odd amount of elements in keyvals it'll log error and use MissingValue as value for last key. In case of non-string keys it'll log error and convert key to string.
Keys in defaultKeyvals will provide default values for prefixKeys/suffixKeys, but these values will be used only if their key is included in prefixKeys or suffixKeys and same key won't be included within keyvals provided with log message.
To delete keys from defaultKeyvals set their value to nil. This is very useful if unwanted key was inherited from parent logger.
It doesn't creates a new logger, it returns l just for convenience.
func (*Logger) SetKeyValFormat ¶
SetKeyValFormat changes fmt format string used to output key/value pair for keys which doesn't have custom format set by SetKeysFormat (default value is DefaultKeyValFormat).
See SetKeysFormat for more details.
It doesn't creates a new logger, it returns l just for convenience.
func (*Logger) SetKeysFormat ¶
SetKeysFormat add/replace custom fmt format string for keys. If key doesn't have custom format string then it will use format set using SetKeyValFormat (default value is DefaultKeyValFormat).
These format strings will be used as fmt.Sprintf(format,key,val), so you can refer to key name and it value as %[1] and %[2] - this is very useful in case you wanna output only key value, without name.
No extra spaces will be output between key/value pairs, so if you need some delimiters then include them inside format strings.
It doesn't creates a new logger, it returns l just for convenience.
func (*Logger) SetLogFormat ¶
SetLogFormat changes log output format (default value is DefaultLogFormat).
It doesn't creates a new logger, it returns l just for convenience.
func (*Logger) SetLogLevel ¶
SetLogLevel changes minimum required log level to output log (default value is DefaultLogLevel).
It doesn't creates a new logger, it returns l just for convenience.
func (*Logger) SetPrefixKeys ¶
SetPrefixKeys replace current prefixKeys for l.
These keys will be output right after l's parent prefixKeys, if any.
XXX Panics if will be called after using l (or logger created using l.New()) to log anything.
It doesn't creates a new logger, it returns l just for convenience.
func (*Logger) SetPrinter ¶ added in v0.2.0
SetPrinter changes log output destination (default value is PrinterFunc(log.Print), i.e. use standard logger, which will be configured using log.SetFlags(0) while importing this package).
It doesn't creates a new logger, it returns l just for convenience.
func (*Logger) SetSuffixKeys ¶
SetSuffixKeys replace current suffixKeys for l.
These keys will be output just before l's parent suffixKeys, if any.
XXX Panics if will be called after using l (or logger created using l.New()) to log anything.
It doesn't creates a new logger, it returns l just for convenience.
func (*Logger) SetTimeFormat ¶
SetTimeFormat changes format for time.Time.Format used when output log time (default value is DefaultTimeFormat).
It doesn't creates a new logger, it returns l just for convenience.
func (*Logger) SetTimeValFormat ¶
SetTimeValFormat changes format for time.Time.Format used when output time.Time values (default value is DefaultTimeValFormat).
It doesn't creates a new logger, it returns l just for convenience.
func (*Logger) Warn ¶
func (l *Logger) Warn(msg interface{}, keyvals ...interface{})
Warn log defaultKeyvals, msg and keyvals with level WRN.
func (*Logger) WarnIfFail ¶
WarnIfFail will run f and log defaultKeyvals, returned error and keyvals with level WRN if returned error is not nil.
defer log.WarnIfFail(file.Close)
func (*Logger) WrapErr ¶ added in v0.4.0
WrapErr returns given err wrapped with keyvals. If returned err will be logged later these keyvals will be included in output.
If called with nil error it'll return nil.
Example ¶
package main import ( "fmt" "io" "os" "github.com/powerman/structlog" ) func main() { // Use NewZeroLogger to avoid reconfiguring // structlog.DefaultLogger in example, but in real code usually // reconfiguring DefaultLogger is better than using NewZeroLogger. log := structlog.NewZeroLogger(). SetOutput(os.Stdout). SetPrefixKeys(structlog.KeyLevel). SetKeysFormat(map[string]string{ structlog.KeyLevel: "%[2]s", structlog.KeyMessage: " %#[2]q", }) lowLevelFunc := func() error { return log.WrapErr(io.EOF, "details", "about error") } middleLevelFunc := func(action string) error { if err := lowLevelFunc(); err != nil { err = fmt.Errorf("lowLevelFunc: %w", err) return log.WrapErr(err, "action", action) } return nil } topLevelFunc := func() { if err := middleLevelFunc("doit"); err != nil { log.Warn("log only at top level", "err", err) } } topLevelFunc() }
Output: WRN `log only at top level` details=about error action=doit err=lowLevelFunc: EOF
type Printer ¶ added in v0.2.0
type Printer interface {
// Print outputs v plus \n. Arguments are handled in the manner of fmt.Print.
Print(v ...interface{})
}
Printer is an interface used to output log.
type PrinterFunc ¶ added in v0.2.0
type PrinterFunc func(v ...interface{})
The PrinterFunc type is an adapter to allow the use of ordinary functions as Printer.
func (PrinterFunc) Print ¶ added in v0.2.0
func (f PrinterFunc) Print(v ...interface{})
Print outputs v plus \n. Arguments are handled in the manner of fmt.Print.