zlog/log.go

477 lines
13 KiB
Go
Raw Normal View History

2022-03-20 19:19:42 +00:00
// Package zlog provides a lightweight logging library dedicated to JSON logging.
2017-05-12 05:24:39 +00:00
//
// A global Logger can be use for simple logging:
//
2022-11-03 15:18:09 +00:00
// import "tuxpa.in/a/zlog/log"
2017-05-12 05:24:39 +00:00
//
2022-10-12 23:37:23 +00:00
// log.Info().Msg("hello world")
// // Output: {"time":1494567715,"level":"info","message":"hello world"}
2017-05-12 05:24:39 +00:00
//
2022-11-03 15:18:09 +00:00
// NOTE: To import the global logger, import the "log" subpackage "tuxpa.in/a/zlog/log".
2017-05-12 05:24:39 +00:00
//
// Fields can be added to log messages:
//
2022-10-12 23:37:23 +00:00
// log.Info().Str("foo", "bar").Msg("hello world")
// // Output: {"time":1494567715,"level":"info","message":"hello world","foo":"bar"}
2017-05-12 05:24:39 +00:00
//
// Create logger instance to manage different outputs:
//
2022-10-12 23:37:23 +00:00
// logger := zlog.New(os.Stderr).With().Timestamp().Logger()
// logger.Info().
// Str("foo", "bar").
// Msg("hello world")
// // Output: {"time":1494567715,"level":"info","message":"hello world","foo":"bar"}
2017-05-12 05:24:39 +00:00
//
// Sub-loggers let you chain loggers with additional context:
//
2022-10-12 23:37:23 +00:00
// sublogger := log.With().Str("component": "foo").Logger()
// sublogger.Info().Msg("hello world")
// // Output: {"time":1494567715,"level":"info","message":"hello world","component":"foo"}
2017-05-12 05:24:39 +00:00
//
// Level logging
//
2022-10-12 23:37:23 +00:00
// zlog.SetGlobalLevel(zlog.InfoLevel)
2017-05-12 05:24:39 +00:00
//
2022-10-12 23:37:23 +00:00
// log.Debug().Msg("filtered out message")
// log.Info().Msg("routed message")
2017-05-12 05:24:39 +00:00
//
2022-10-12 23:37:23 +00:00
// if e := log.Debug(); e.Enabled() {
// // Compute log output only if enabled.
// value := compute()
// e.Str("foo": value).Msg("some debug message")
// }
// // Output: {"level":"info","time":1494567715,"routed message"}
2017-05-12 05:24:39 +00:00
//
// Customize automatic field names:
//
2022-10-12 23:37:23 +00:00
// log.TimestampFieldName = "t"
// log.LevelFieldName = "p"
// log.MessageFieldName = "m"
2017-05-12 05:24:39 +00:00
//
2022-10-12 23:37:23 +00:00
// log.Info().Msg("hello world")
// // Output: {"t":1494567715,"p":"info","m":"hello world"}
2017-05-12 05:24:39 +00:00
//
// Log with no level and message:
//
2022-10-12 23:37:23 +00:00
// log.Log().Str("foo","bar").Msg("")
// // Output: {"time":1494567715,"foo":"bar"}
2017-05-12 05:24:39 +00:00
//
// Add contextual fields to global Logger:
//
2022-10-12 23:37:23 +00:00
// log.Logger = log.With().Str("foo", "bar").Logger()
2017-05-12 05:24:39 +00:00
//
// Sample logs:
//
2022-10-12 23:37:23 +00:00
// sampled := log.Sample(&zlog.BasicSampler{N: 10})
// sampled.Info().Msg("will be logged every 10 messages")
2017-05-12 05:24:39 +00:00
//
2017-12-01 17:52:37 +00:00
// Log with contextual hooks:
//
2022-10-12 23:37:23 +00:00
// // Create the hook:
// type SeverityHook struct{}
2017-12-01 17:52:37 +00:00
//
2022-10-12 23:37:23 +00:00
// func (h SeverityHook) Run(e *zlog.Event, level zlog.Level, msg string) {
// if level != zlog.NoLevel {
// e.Str("severity", level.String())
// }
// }
2017-12-01 17:52:37 +00:00
//
2022-10-12 23:37:23 +00:00
// // And use it:
// var h SeverityHook
// log := zlog.New(os.Stdout).Hook(h)
// log.Warn().Msg("")
// // Output: {"level":"warn","severity":"warn"}
2017-12-01 17:52:37 +00:00
//
2022-10-12 23:37:23 +00:00
// # Caveats
//
// There is no fields deduplication out-of-the-box.
// Using the same key multiple times creates new key in final JSON each time.
//
2022-10-12 23:37:23 +00:00
// logger := zlog.New(os.Stderr).With().Timestamp().Logger()
// logger.Info().
// Timestamp().
// Msg("dup")
// // Output: {"level":"info","time":1494567715,"time":1494567715,"message":"dup"}
//
// In this case, many consumers will take the last value,
// but this is not guaranteed; check yours if in doubt.
2022-03-20 19:19:42 +00:00
package zlog
2017-05-12 05:24:39 +00:00
import (
2022-10-12 23:37:23 +00:00
"errors"
2017-09-02 02:56:35 +00:00
"fmt"
2017-05-12 05:24:39 +00:00
"io"
2017-05-19 16:56:31 +00:00
"io/ioutil"
2017-05-12 05:24:39 +00:00
"os"
"strconv"
2022-11-11 13:15:40 +00:00
"strings"
2017-05-12 05:24:39 +00:00
)
// Level defines log levels.
2019-11-04 19:39:22 +00:00
type Level int8
2017-05-12 05:24:39 +00:00
const (
// DebugLevel defines debug log level.
DebugLevel Level = iota
// InfoLevel defines info log level.
InfoLevel
// WarnLevel defines warn log level.
WarnLevel
// ErrorLevel defines error log level.
ErrorLevel
// FatalLevel defines fatal log level.
FatalLevel
// PanicLevel defines panic log level.
PanicLevel
2017-12-01 17:52:37 +00:00
// NoLevel defines an absent log level.
NoLevel
2017-05-12 05:24:39 +00:00
// Disabled disables the logger.
Disabled
2019-11-18 17:34:23 +00:00
// TraceLevel defines trace log level.
TraceLevel Level = -1
// Values less than TraceLevel are handled as numbers.
2017-05-12 05:24:39 +00:00
)
func (l Level) String() string {
switch l {
2019-11-04 19:39:22 +00:00
case TraceLevel:
2021-05-13 22:05:00 +00:00
return LevelTraceValue
2017-05-12 05:24:39 +00:00
case DebugLevel:
2021-05-13 22:05:00 +00:00
return LevelDebugValue
2017-05-12 05:24:39 +00:00
case InfoLevel:
2021-05-13 22:05:00 +00:00
return LevelInfoValue
2017-05-12 05:24:39 +00:00
case WarnLevel:
2021-05-13 22:05:00 +00:00
return LevelWarnValue
2017-05-12 05:24:39 +00:00
case ErrorLevel:
2021-05-13 22:05:00 +00:00
return LevelErrorValue
2017-05-12 05:24:39 +00:00
case FatalLevel:
2021-05-13 22:05:00 +00:00
return LevelFatalValue
2017-05-12 05:24:39 +00:00
case PanicLevel:
2021-05-13 22:05:00 +00:00
return LevelPanicValue
case Disabled:
return "disabled"
2017-12-01 17:52:37 +00:00
case NoLevel:
return ""
2017-05-12 05:24:39 +00:00
}
return strconv.Itoa(int(l))
2017-05-12 05:24:39 +00:00
}
2022-03-20 19:19:42 +00:00
// ParseLevel converts a level string into a zlog Level value.
// returns an error if the input string does not match known values.
func ParseLevel(levelStr string) (Level, error) {
2022-11-11 13:15:40 +00:00
switch strings.ToLower(levelStr) {
2019-11-04 19:39:22 +00:00
case LevelFieldMarshalFunc(TraceLevel):
return TraceLevel, nil
case LevelFieldMarshalFunc(DebugLevel):
return DebugLevel, nil
case LevelFieldMarshalFunc(InfoLevel):
return InfoLevel, nil
case LevelFieldMarshalFunc(WarnLevel):
return WarnLevel, nil
case LevelFieldMarshalFunc(ErrorLevel):
return ErrorLevel, nil
case LevelFieldMarshalFunc(FatalLevel):
return FatalLevel, nil
case LevelFieldMarshalFunc(PanicLevel):
return PanicLevel, nil
case LevelFieldMarshalFunc(Disabled):
return Disabled, nil
case LevelFieldMarshalFunc(NoLevel):
return NoLevel, nil
}
i, err := strconv.Atoi(levelStr)
if err != nil {
return NoLevel, fmt.Errorf("Unknown Level String: '%s', defaulting to NoLevel", levelStr)
}
if i > 127 || i < -128 {
return NoLevel, fmt.Errorf("Out-Of-Bounds Level: '%d', defaulting to NoLevel", i)
}
return Level(i), nil
}
2022-10-12 23:37:23 +00:00
// UnmarshalText implements encoding.TextUnmarshaler to allow for easy reading from toml/yaml/json formats
func (l *Level) UnmarshalText(text []byte) error {
if l == nil {
return errors.New("can't unmarshal a nil *Level")
}
var err error
*l, err = ParseLevel(string(text))
return err
}
// MarshalText implements encoding.TextMarshaler to allow for easy writing into toml/yaml/json formats
func (l Level) MarshalText() ([]byte, error) {
return []byte(LevelFieldMarshalFunc(l)), nil
}
2017-05-12 05:24:39 +00:00
// A Logger represents an active logging object that generates lines
// of JSON output to an io.Writer. Each logging operation makes a single
2019-12-27 17:23:15 +00:00
// call to the Writer's Write method. There is no guarantee on access
2017-05-12 05:24:39 +00:00
// serialization to the Writer. If your Writer is not thread safe,
// you may consider a sync wrapper.
type Logger struct {
w LevelWriter
level Level
2017-08-29 01:52:15 +00:00
sampler Sampler
context []byte
2017-12-01 17:52:37 +00:00
hooks []Hook
2021-03-23 22:01:01 +00:00
stack bool
2017-05-12 05:24:39 +00:00
}
// New creates a root logger with given output writer. If the output writer implements
// the LevelWriter interface, the WriteLevel method will be called instead of the Write
// one.
//
// Each logging operation makes a single call to the Writer's Write method. There is no
2019-12-27 17:23:15 +00:00
// guarantee on access serialization to the Writer. If your Writer is not thread safe,
// you may consider using sync wrapper.
2017-05-12 05:24:39 +00:00
func New(w io.Writer) Logger {
if w == nil {
w = ioutil.Discard
2017-05-12 05:24:39 +00:00
}
lw, ok := w.(LevelWriter)
if !ok {
lw = levelWriterAdapter{w}
}
2019-11-04 19:39:22 +00:00
return Logger{w: lw, level: TraceLevel}
2017-05-12 05:24:39 +00:00
}
2017-06-02 07:24:52 +00:00
// Nop returns a disabled logger for which all operation are no-op.
func Nop() Logger {
return New(nil).Level(Disabled)
}
// Output duplicates the current logger and sets w as its output.
func (l Logger) Output(w io.Writer) Logger {
l2 := New(w)
l2.level = l.level
2017-08-29 01:52:15 +00:00
l2.sampler = l.sampler
l2.stack = l.stack
2017-12-01 17:52:37 +00:00
if len(l.hooks) > 0 {
l2.hooks = append(l2.hooks, l.hooks...)
}
if l.context != nil {
l2.context = make([]byte, len(l.context), cap(l.context))
copy(l2.context, l.context)
}
return l2
}
2017-05-12 05:24:39 +00:00
// With creates a child logger with the field added to its context.
func (l Logger) With() Context {
context := l.context
l.context = make([]byte, 0, 500)
if context != nil {
l.context = append(l.context, context...)
Make AppendKey in json inlinable (#226) This change increase performance by inlining this frequently called function Benchmark: | name | old time/op | new time/op | delta | params | |---|---|---|---|---| | LogEmpty-8 | 14.1ns ±10% | 15.6ns ±13% | +10.43% | (p=0.003 n=10+10) | | Disabled-8 | 1.27ns ± 0% | 1.35ns ± 1% | +6.54% | (p=0.000 n=9+10) | | Info-8 | 39.8ns ± 5% | 37.9ns ± 2% | -4.55% | (p=0.000 n=10+10) | | ContextFields-8 | 42.2ns ± 4% | 39.7ns ± 3% | -6.04% | (p=0.000 n=10+10) | | ContextAppend-8 | 15.3ns ± 0% | 14.5ns ± 0% | -5.23% | (p=0.000 n=9+10) | | LogFields-8 | 179ns ± 0% | 176ns ± 1% | -1.23% | (p=0.000 n=10+10) | | LogArrayObject-8 | 526ns ± 1% | 491ns ± 1% | -6.65% | (p=0.000 n=9+10) | | LogFieldType/Bools-8 | 34.5ns ± 2% | 33.3ns ± 4% | -3.63% | (p=0.000 n=9+10) | | LogFieldType/Int-8 | 29.7ns ± 4% | 28.3ns ± 6% | -4.71% | (p=0.003 n=10+10) | | LogFieldType/Str-8 | 29.6ns ± 3% | 27.1ns ± 2% | -8.19% | (p=0.000 n=10+10) | | LogFieldType/Time-8 | 119ns ± 0% | 118ns ± 0% | -0.84% | (p=0.000 n=9+9) | | LogFieldType/Interfaces-8 | 504ns ± 1% | 516ns ± 1% | +2.46% | (p=0.000 n=10+10) | | LogFieldType/Object-8 | 73.7ns ± 2% | 71.6ns ± 1% | -2.94% | (p=0.000 n=10+10) | | LogFieldType/Bool-8 | 28.9ns ± 6% | 25.9ns ± 3% | -10.35% | (p=0.000 n=9+10) | | LogFieldType/Strs-8 | 53.7ns ± 2% | 51.6ns ± 1% | -3.95% | (p=0.000 n=9+10) | | LogFieldType/Err-8 | 39.2ns ± 2% | 38.1ns ± 4% | -2.66% | (p=0.006 n=10+10) | | LogFieldType/Interface-8 | 147ns ± 1% | 145ns ± 1% | -1.22% | (p=0.001 n=10+10) | | LogFieldType/Interface(Object)-8 | 78.8ns ± 1% | 76.9ns ± 1% | -2.43% | (p=0.000 n=10+10) | | LogFieldType/Interface(Objects)-8 | 516ns ± 0% | 507ns ± 1% | -1.66% | (p=0.000 n=8+10) | | LogFieldType/Ints-8 | 52.4ns ± 1% | 48.1ns ± 1% | -8.28% | (p=0.000 n=10+10) | | LogFieldType/Float-8 | 39.8ns ± 1% | 38.4ns ± 2% | -3.33% | (p=0.000 n=10+9) | | LogFieldType/Times-8 | 887ns ± 0% | 887ns ± 0% | ~ | (p=0.164 n=8+10) | | LogFieldType/Dur-8 | 41.1ns ± 2% | 40.2ns ± 6% | -2.10% | (p=0.014 n=10+10) | | LogFieldType/Durs-8 | 266ns ± 0% | 262ns ± 0% | -1.35% | (p=0.000 n=7+10) | | LogFieldType/Floats-8 | 166ns ± 0% | 165ns ± 1% | ~ | (p=0.238 n=10+10) | | LogFieldType/Errs-8 | 126ns ± 1% | 120ns ± 2% | -4.61% | (p=0.000 n=10+10) | | ContextFieldType/Bool-8 | 140ns ± 2% | 140ns ± 2% | ~ | (p=0.701 n=10+9) | | ContextFieldType/Err-8 | 150ns ± 3% | 150ns ± 2% | ~ | (p=0.932 n=10+10) | | ContextFieldType/Interfaces-8 | 631ns ± 1% | 628ns ± 1% | ~ | (p=0.108 n=10+10) | | ContextFieldType/Floats-8 | 263ns ± 1% | 257ns ± 1% | -2.05% | (p=0.000 n=10+10) | | ContextFieldType/Errs-8 | 205ns ± 2% | 204ns ± 2% | ~ | (p=0.499 n=10+9) | | ContextFieldType/Dur-8 | 146ns ± 3% | 149ns ± 2% | +1.86% | (p=0.011 n=9+10) | | ContextFieldType/Durs-8 | 372ns ± 1% | 367ns ± 1% | -1.24% | (p=0.000 n=10+10) | | ContextFieldType/Bools-8 | 145ns ± 2% | 144ns ± 3% | ~ | (p=0.447 n=10+10) | | ContextFieldType/Ints-8 | 157ns ± 3% | 157ns ± 2% | ~ | (p=0.976 n=9+9) | | ContextFieldType/Float-8 | 147ns ± 3% | 148ns ± 4% | ~ | (p=0.385 n=9+10) | | ContextFieldType/Strs-8 | 158ns ± 3% | 157ns ± 2% | ~ | (p=0.666 n=10+10) | | ContextFieldType/Time-8 | 143ns ± 2% | 141ns ± 3% | -1.75% | (p=0.035 n=10+10) | | ContextFieldType/Times-8 | 159ns ± 4% | 159ns ± 2% | ~ | (p=0.978 n=10+10) | | ContextFieldType/Interface(Object)-8 | 252ns ± 2% | 251ns ± 2% | ~ | (p=0.415 n=10+10) | | ContextFieldType/Timestamp-8 | 167ns ± 2% | 167ns ± 3% | ~ | (p=0.662 n=10+10) | | ContextFieldType/Int-8 | 142ns ± 4% | 140ns ± 2% | -2.04% | (p=0.026 n=10+10) | | ContextFieldType/Str-8 | 142ns ± 1% | 141ns ± 3% | -1.00% | (p=0.016 n=9+10) | | ContextFieldType/Interface-8 | 253ns ± 1% | 249ns ± 3% | ~ | (p=0.055 n=9+10) | | ContextFieldType/Interface(Objects)-8 | 632ns ± 1% | 624ns ± 1% | -1.20% | (p=0.000 n=10+9) | | ContextFieldType/Object-8 | 194ns ± 2% | 192ns ± 2% | ~ | (p=0.083 n=10+10) | | Hooks/Nop/Single-8 | 16.5ns ± 6% | 15.5ns ± 5% | -5.95% | (p=0.001 n=10+10) | | Hooks/Nop/Multi-8 | 18.5ns ± 6% | 17.8ns ± 4% | -3.66% | (p=0.009 n=10+9) | | Hooks/Simple-8 | 31.0ns ± 2% | 28.1ns ± 2% | -9.24% | (p=0.000 n=8+9) | | Samplers/BasicSampler_1-8 | 0.65ns ± 1% | 0.63ns ± 1% | -1.78% | (p=0.000 n=10+9) | | Samplers/BasicSampler_5-8 | 30.0ns ± 1% | 32.2ns ± 0% | +7.29% | (p=0.000 n=10+9) | | Samplers/RandomSampler-8 | 92.8ns ± 1% | 90.8ns ± 1% | -2.25% | (p=0.000 n=10+10) | | Samplers/BurstSampler-8 | 34.5ns ± 1% | 36.6ns ± 1% | +5.95% | (p=0.000 n=9+9) | | Samplers/BurstSamplerNext-8 | 46.3ns ± 0% | 46.1ns ± 0% | -0.41% | (p=0.001 n=9+7) | | ConsoleWriter-8 | 5.90µs ± 0% | 5.84µs ± 1% | -0.91% | (p=0.000 n=10+10) |
2020-05-06 02:44:34 +00:00
} else {
// This is needed for AppendKey to not check len of input
// thus making it inlinable
l.context = enc.AppendBeginMarker(l.context)
}
2017-05-12 05:24:39 +00:00
return Context{l}
}
// UpdateContext updates the internal logger's context.
//
// Use this method with caution. If unsure, prefer the With method.
func (l *Logger) UpdateContext(update func(c Context) Context) {
if l == disabledLogger {
return
}
if cap(l.context) == 0 {
l.context = make([]byte, 0, 500)
}
if len(l.context) == 0 {
l.context = enc.AppendBeginMarker(l.context)
}
c := update(Context{*l})
l.context = c.l.context
}
2017-06-05 19:59:25 +00:00
// Level creates a child logger with the minimum accepted level set to level.
2017-05-12 05:24:39 +00:00
func (l Logger) Level(lvl Level) Logger {
2017-09-03 18:01:28 +00:00
l.level = lvl
return l
2017-05-12 05:24:39 +00:00
}
2019-06-20 23:44:55 +00:00
// GetLevel returns the current Level of l.
func (l Logger) GetLevel() Level {
return l.level
}
2017-08-29 01:52:15 +00:00
// Sample returns a logger with the s sampler.
func (l Logger) Sample(s Sampler) Logger {
2017-09-03 18:01:28 +00:00
l.sampler = s
return l
2017-05-12 05:24:39 +00:00
}
2017-12-01 17:52:37 +00:00
// Hook returns a logger with the h Hook.
func (l Logger) Hook(h Hook) Logger {
l.hooks = append(l.hooks, h)
return l
}
2019-11-04 19:39:22 +00:00
// Trace starts a new message with trace level.
//
// You must call Msg on the returned event in order to send the event.
func (l *Logger) Trace() *Event {
return l.newEvent(TraceLevel, nil)
}
2017-05-12 05:24:39 +00:00
// Debug starts a new message with debug level.
//
// You must call Msg on the returned event in order to send the event.
func (l *Logger) Debug() *Event {
2017-12-01 17:52:37 +00:00
return l.newEvent(DebugLevel, nil)
2017-05-12 05:24:39 +00:00
}
// Info starts a new message with info level.
//
// You must call Msg on the returned event in order to send the event.
func (l *Logger) Info() *Event {
2017-12-01 17:52:37 +00:00
return l.newEvent(InfoLevel, nil)
2017-05-12 05:24:39 +00:00
}
// Warn starts a new message with warn level.
//
// You must call Msg on the returned event in order to send the event.
func (l *Logger) Warn() *Event {
2017-12-01 17:52:37 +00:00
return l.newEvent(WarnLevel, nil)
2017-05-12 05:24:39 +00:00
}
// Error starts a new message with error level.
//
// You must call Msg on the returned event in order to send the event.
func (l *Logger) Error() *Event {
2017-12-01 17:52:37 +00:00
return l.newEvent(ErrorLevel, nil)
2017-05-12 05:24:39 +00:00
}
// Err starts a new message with error level with err as a field if not nil or
// with info level if err is nil.
//
// You must call Msg on the returned event in order to send the event.
func (l *Logger) Err(err error) *Event {
if err != nil {
return l.Error().Err(err)
}
2019-10-04 14:31:06 +00:00
return l.Info()
}
2017-05-12 05:24:39 +00:00
// Fatal starts a new message with fatal level. The os.Exit(1) function
// is called by the Msg method, which terminates the program immediately.
2017-05-12 05:24:39 +00:00
//
// You must call Msg on the returned event in order to send the event.
func (l *Logger) Fatal() *Event {
2017-12-01 17:52:37 +00:00
return l.newEvent(FatalLevel, func(msg string) { os.Exit(1) })
2017-05-12 05:24:39 +00:00
}
// Panic starts a new message with panic level. The panic() function
// is called by the Msg method, which stops the ordinary flow of a goroutine.
2017-05-12 05:24:39 +00:00
//
// You must call Msg on the returned event in order to send the event.
func (l *Logger) Panic() *Event {
2017-12-01 17:52:37 +00:00
return l.newEvent(PanicLevel, func(msg string) { panic(msg) })
2017-05-12 05:24:39 +00:00
}
// WithLevel starts a new message with level. Unlike Fatal and Panic
// methods, WithLevel does not terminate the program or stop the ordinary
// flow of a goroutine when used with their respective levels.
//
// You must call Msg on the returned event in order to send the event.
func (l *Logger) WithLevel(level Level) *Event {
switch level {
2019-11-04 19:39:22 +00:00
case TraceLevel:
return l.Trace()
case DebugLevel:
return l.Debug()
case InfoLevel:
return l.Info()
case WarnLevel:
return l.Warn()
case ErrorLevel:
return l.Error()
case FatalLevel:
return l.newEvent(FatalLevel, nil)
case PanicLevel:
return l.newEvent(PanicLevel, nil)
2017-12-01 17:52:37 +00:00
case NoLevel:
return l.Log()
case Disabled:
return nil
default:
return l.newEvent(level, nil)
}
}
2017-05-12 05:24:39 +00:00
// Log starts a new message with no level. Setting GlobalLevel to Disabled
// will still disable events produced by this method.
//
// You must call Msg on the returned event in order to send the event.
func (l *Logger) Log() *Event {
2017-12-01 17:52:37 +00:00
return l.newEvent(NoLevel, nil)
2017-05-12 05:24:39 +00:00
}
2017-09-02 02:56:35 +00:00
// Print sends a log event using debug level and no extra field.
// Arguments are handled in the manner of fmt.Print.
func (l *Logger) Print(v ...interface{}) {
2017-09-02 02:56:35 +00:00
if e := l.Debug(); e.Enabled() {
e.CallerSkipFrame(1).Msg(fmt.Sprint(v...))
2017-09-02 02:56:35 +00:00
}
}
// Printf sends a log event using debug level and no extra field.
// Arguments are handled in the manner of fmt.Printf.
func (l *Logger) Printf(format string, v ...interface{}) {
2017-09-02 02:56:35 +00:00
if e := l.Debug(); e.Enabled() {
e.CallerSkipFrame(1).Msg(fmt.Sprintf(format, v...))
2017-09-02 02:56:35 +00:00
}
}
// Write implements the io.Writer interface. This is useful to set as a writer
// for the standard library log.
func (l Logger) Write(p []byte) (n int, err error) {
n = len(p)
if n > 0 && p[n-1] == '\n' {
// Trim CR added by stdlog.
p = p[0 : n-1]
}
l.Log().CallerSkipFrame(1).Msg(string(p))
return
}
2017-12-01 17:52:37 +00:00
func (l *Logger) newEvent(level Level, done func(string)) *Event {
2017-05-19 16:56:31 +00:00
enabled := l.should(level)
if !enabled {
if done != nil {
done("")
}
return nil
2017-05-19 16:56:31 +00:00
}
e := newEvent(l.w, level)
e.done = done
e.ch = l.hooks
if level != NoLevel && LevelFieldName != "" {
e.Str(LevelFieldName, LevelFieldMarshalFunc(level))
2017-05-12 05:24:39 +00:00
}
Make AppendKey in json inlinable (#226) This change increase performance by inlining this frequently called function Benchmark: | name | old time/op | new time/op | delta | params | |---|---|---|---|---| | LogEmpty-8 | 14.1ns ±10% | 15.6ns ±13% | +10.43% | (p=0.003 n=10+10) | | Disabled-8 | 1.27ns ± 0% | 1.35ns ± 1% | +6.54% | (p=0.000 n=9+10) | | Info-8 | 39.8ns ± 5% | 37.9ns ± 2% | -4.55% | (p=0.000 n=10+10) | | ContextFields-8 | 42.2ns ± 4% | 39.7ns ± 3% | -6.04% | (p=0.000 n=10+10) | | ContextAppend-8 | 15.3ns ± 0% | 14.5ns ± 0% | -5.23% | (p=0.000 n=9+10) | | LogFields-8 | 179ns ± 0% | 176ns ± 1% | -1.23% | (p=0.000 n=10+10) | | LogArrayObject-8 | 526ns ± 1% | 491ns ± 1% | -6.65% | (p=0.000 n=9+10) | | LogFieldType/Bools-8 | 34.5ns ± 2% | 33.3ns ± 4% | -3.63% | (p=0.000 n=9+10) | | LogFieldType/Int-8 | 29.7ns ± 4% | 28.3ns ± 6% | -4.71% | (p=0.003 n=10+10) | | LogFieldType/Str-8 | 29.6ns ± 3% | 27.1ns ± 2% | -8.19% | (p=0.000 n=10+10) | | LogFieldType/Time-8 | 119ns ± 0% | 118ns ± 0% | -0.84% | (p=0.000 n=9+9) | | LogFieldType/Interfaces-8 | 504ns ± 1% | 516ns ± 1% | +2.46% | (p=0.000 n=10+10) | | LogFieldType/Object-8 | 73.7ns ± 2% | 71.6ns ± 1% | -2.94% | (p=0.000 n=10+10) | | LogFieldType/Bool-8 | 28.9ns ± 6% | 25.9ns ± 3% | -10.35% | (p=0.000 n=9+10) | | LogFieldType/Strs-8 | 53.7ns ± 2% | 51.6ns ± 1% | -3.95% | (p=0.000 n=9+10) | | LogFieldType/Err-8 | 39.2ns ± 2% | 38.1ns ± 4% | -2.66% | (p=0.006 n=10+10) | | LogFieldType/Interface-8 | 147ns ± 1% | 145ns ± 1% | -1.22% | (p=0.001 n=10+10) | | LogFieldType/Interface(Object)-8 | 78.8ns ± 1% | 76.9ns ± 1% | -2.43% | (p=0.000 n=10+10) | | LogFieldType/Interface(Objects)-8 | 516ns ± 0% | 507ns ± 1% | -1.66% | (p=0.000 n=8+10) | | LogFieldType/Ints-8 | 52.4ns ± 1% | 48.1ns ± 1% | -8.28% | (p=0.000 n=10+10) | | LogFieldType/Float-8 | 39.8ns ± 1% | 38.4ns ± 2% | -3.33% | (p=0.000 n=10+9) | | LogFieldType/Times-8 | 887ns ± 0% | 887ns ± 0% | ~ | (p=0.164 n=8+10) | | LogFieldType/Dur-8 | 41.1ns ± 2% | 40.2ns ± 6% | -2.10% | (p=0.014 n=10+10) | | LogFieldType/Durs-8 | 266ns ± 0% | 262ns ± 0% | -1.35% | (p=0.000 n=7+10) | | LogFieldType/Floats-8 | 166ns ± 0% | 165ns ± 1% | ~ | (p=0.238 n=10+10) | | LogFieldType/Errs-8 | 126ns ± 1% | 120ns ± 2% | -4.61% | (p=0.000 n=10+10) | | ContextFieldType/Bool-8 | 140ns ± 2% | 140ns ± 2% | ~ | (p=0.701 n=10+9) | | ContextFieldType/Err-8 | 150ns ± 3% | 150ns ± 2% | ~ | (p=0.932 n=10+10) | | ContextFieldType/Interfaces-8 | 631ns ± 1% | 628ns ± 1% | ~ | (p=0.108 n=10+10) | | ContextFieldType/Floats-8 | 263ns ± 1% | 257ns ± 1% | -2.05% | (p=0.000 n=10+10) | | ContextFieldType/Errs-8 | 205ns ± 2% | 204ns ± 2% | ~ | (p=0.499 n=10+9) | | ContextFieldType/Dur-8 | 146ns ± 3% | 149ns ± 2% | +1.86% | (p=0.011 n=9+10) | | ContextFieldType/Durs-8 | 372ns ± 1% | 367ns ± 1% | -1.24% | (p=0.000 n=10+10) | | ContextFieldType/Bools-8 | 145ns ± 2% | 144ns ± 3% | ~ | (p=0.447 n=10+10) | | ContextFieldType/Ints-8 | 157ns ± 3% | 157ns ± 2% | ~ | (p=0.976 n=9+9) | | ContextFieldType/Float-8 | 147ns ± 3% | 148ns ± 4% | ~ | (p=0.385 n=9+10) | | ContextFieldType/Strs-8 | 158ns ± 3% | 157ns ± 2% | ~ | (p=0.666 n=10+10) | | ContextFieldType/Time-8 | 143ns ± 2% | 141ns ± 3% | -1.75% | (p=0.035 n=10+10) | | ContextFieldType/Times-8 | 159ns ± 4% | 159ns ± 2% | ~ | (p=0.978 n=10+10) | | ContextFieldType/Interface(Object)-8 | 252ns ± 2% | 251ns ± 2% | ~ | (p=0.415 n=10+10) | | ContextFieldType/Timestamp-8 | 167ns ± 2% | 167ns ± 3% | ~ | (p=0.662 n=10+10) | | ContextFieldType/Int-8 | 142ns ± 4% | 140ns ± 2% | -2.04% | (p=0.026 n=10+10) | | ContextFieldType/Str-8 | 142ns ± 1% | 141ns ± 3% | -1.00% | (p=0.016 n=9+10) | | ContextFieldType/Interface-8 | 253ns ± 1% | 249ns ± 3% | ~ | (p=0.055 n=9+10) | | ContextFieldType/Interface(Objects)-8 | 632ns ± 1% | 624ns ± 1% | -1.20% | (p=0.000 n=10+9) | | ContextFieldType/Object-8 | 194ns ± 2% | 192ns ± 2% | ~ | (p=0.083 n=10+10) | | Hooks/Nop/Single-8 | 16.5ns ± 6% | 15.5ns ± 5% | -5.95% | (p=0.001 n=10+10) | | Hooks/Nop/Multi-8 | 18.5ns ± 6% | 17.8ns ± 4% | -3.66% | (p=0.009 n=10+9) | | Hooks/Simple-8 | 31.0ns ± 2% | 28.1ns ± 2% | -9.24% | (p=0.000 n=8+9) | | Samplers/BasicSampler_1-8 | 0.65ns ± 1% | 0.63ns ± 1% | -1.78% | (p=0.000 n=10+9) | | Samplers/BasicSampler_5-8 | 30.0ns ± 1% | 32.2ns ± 0% | +7.29% | (p=0.000 n=10+9) | | Samplers/RandomSampler-8 | 92.8ns ± 1% | 90.8ns ± 1% | -2.25% | (p=0.000 n=10+10) | | Samplers/BurstSampler-8 | 34.5ns ± 1% | 36.6ns ± 1% | +5.95% | (p=0.000 n=9+9) | | Samplers/BurstSamplerNext-8 | 46.3ns ± 0% | 46.1ns ± 0% | -0.41% | (p=0.001 n=9+7) | | ConsoleWriter-8 | 5.90µs ± 0% | 5.84µs ± 1% | -0.91% | (p=0.000 n=10+10) |
2020-05-06 02:44:34 +00:00
if l.context != nil && len(l.context) > 1 {
Get back some ns by removing the extra inferance added by binary support benchstat old new name old time/op new time/op delta LogEmpty-8 15.2ns ±14% 13.4ns ± 3% -12.11% (p=0.008 n=5+5) Disabled-8 2.50ns ± 1% 2.28ns ± 6% -8.81% (p=0.008 n=5+5) Info-8 44.4ns ± 1% 36.4ns ± 4% -17.99% (p=0.008 n=5+5) ContextFields-8 47.6ns ± 1% 39.4ns ± 7% -17.30% (p=0.008 n=5+5) ContextAppend-8 18.9ns ± 4% 15.2ns ± 4% -19.68% (p=0.008 n=5+5) LogFields-8 181ns ± 2% 173ns ± 2% -4.63% (p=0.008 n=5+5) LogArrayObject-8 530ns ± 3% 487ns ± 3% -8.11% (p=0.008 n=5+5) LogFieldType/Int-8 29.5ns ± 3% 28.8ns ± 2% ~ (p=0.167 n=5+5) LogFieldType/Interface-8 180ns ± 7% 175ns ± 4% ~ (p=0.579 n=5+5) LogFieldType/Interface(Object)-8 87.8ns ± 3% 80.5ns ± 1% -8.29% (p=0.008 n=5+5) LogFieldType/Object-8 83.7ns ± 2% 77.2ns ± 3% -7.76% (p=0.008 n=5+5) LogFieldType/Bools-8 34.6ns ± 3% 32.3ns ± 6% -6.64% (p=0.032 n=5+5) LogFieldType/Float-8 43.0ns ± 4% 40.5ns ± 4% -5.86% (p=0.016 n=5+5) LogFieldType/Str-8 29.8ns ± 2% 26.5ns ± 5% -11.01% (p=0.008 n=5+5) LogFieldType/Err-8 32.8ns ± 2% 29.8ns ± 4% -9.21% (p=0.008 n=5+5) LogFieldType/Durs-8 309ns ± 3% 304ns ± 3% ~ (p=0.238 n=5+5) LogFieldType/Floats-8 175ns ± 2% 174ns ± 3% ~ (p=0.968 n=5+5) LogFieldType/Strs-8 51.0ns ± 3% 48.4ns ± 6% -5.06% (p=0.032 n=5+5) LogFieldType/Dur-8 44.5ns ± 3% 41.3ns ± 3% -7.11% (p=0.008 n=5+5) LogFieldType/Interface(Objects)-8 758ns ± 3% 760ns ± 6% ~ (p=1.000 n=5+5) LogFieldType/Interfaces-8 772ns ± 5% 762ns ± 4% ~ (p=0.794 n=5+5) LogFieldType/Bool-8 28.0ns ± 6% 26.5ns ± 9% ~ (p=0.143 n=5+5) LogFieldType/Ints-8 49.6ns ± 2% 46.2ns ± 2% -6.70% (p=0.008 n=5+5) LogFieldType/Errs-8 46.5ns ±11% 40.9ns ± 4% -11.92% (p=0.008 n=5+5) LogFieldType/Time-8 115ns ± 3% 113ns ± 3% ~ (p=0.167 n=5+5) LogFieldType/Times-8 810ns ± 1% 811ns ± 3% ~ (p=0.889 n=5+5) ContextFieldType/Errs-8 158ns ± 6% 156ns ±12% ~ (p=1.000 n=5+5) ContextFieldType/Times-8 165ns ±11% 173ns ± 9% ~ (p=0.651 n=5+5) ContextFieldType/Interface-8 289ns ±13% 287ns ±11% ~ (p=0.690 n=5+5) ContextFieldType/Interface(Object)-8 285ns ±12% 297ns ± 6% ~ (p=0.238 n=5+5) ContextFieldType/Interface(Objects)-8 941ns ± 6% 941ns ± 5% ~ (p=1.000 n=5+5) ContextFieldType/Object-8 201ns ± 5% 210ns ±12% ~ (p=0.262 n=5+5) ContextFieldType/Ints-8 173ns ±10% 165ns ± 9% ~ (p=0.198 n=5+5) ContextFieldType/Floats-8 297ns ± 6% 292ns ± 7% ~ (p=0.579 n=5+5) ContextFieldType/Timestamp-8 174ns ± 9% 174ns ±11% ~ (p=0.810 n=5+5) ContextFieldType/Durs-8 445ns ± 9% 425ns ± 3% ~ (p=0.151 n=5+5) ContextFieldType/Interfaces-8 944ns ± 6% 876ns ±10% ~ (p=0.095 n=5+5) ContextFieldType/Strs-8 179ns ±11% 165ns ±13% ~ (p=0.135 n=5+5) ContextFieldType/Dur-8 158ns ± 8% 160ns ±19% ~ (p=1.000 n=5+5) ContextFieldType/Time-8 152ns ±15% 148ns ±14% ~ (p=0.952 n=5+5) ContextFieldType/Str-8 146ns ±12% 147ns ±16% ~ (p=0.841 n=5+5) ContextFieldType/Err-8 138ns ±12% 145ns ±17% ~ (p=0.595 n=5+5) ContextFieldType/Int-8 145ns ±10% 146ns ±13% ~ (p=0.873 n=5+5) ContextFieldType/Float-8 181ns ± 9% 162ns ±12% ~ (p=0.151 n=5+5) ContextFieldType/Bool-8 153ns ±10% 131ns ±19% ~ (p=0.063 n=5+5) ContextFieldType/Bools-8 149ns ±11% 160ns ±16% ~ (p=0.500 n=5+5)
2018-05-10 22:01:41 +00:00
e.buf = enc.AppendObjectData(e.buf, l.context)
2017-12-01 17:52:37 +00:00
}
2021-03-23 22:01:01 +00:00
if l.stack {
e.Stack()
}
2017-05-12 05:24:39 +00:00
return e
}
// should returns true if the log event should be logged.
func (l *Logger) should(lvl Level) bool {
if lvl < l.level || lvl < GlobalLevel() {
2017-05-12 05:24:39 +00:00
return false
}
2017-08-29 01:52:15 +00:00
if l.sampler != nil && !samplingDisabled() {
return l.sampler.Sample(lvl)
2017-05-12 05:24:39 +00:00
}
return true
}