...

Source file src/github.com/rs/zerolog/log.go

Documentation: github.com/rs/zerolog

     1  // Package zerolog provides a lightweight logging library dedicated to JSON logging.
     2  //
     3  // A global Logger can be use for simple logging:
     4  //
     5  //     import "github.com/rs/zerolog/log"
     6  //
     7  //     log.Info().Msg("hello world")
     8  //     // Output: {"time":1494567715,"level":"info","message":"hello world"}
     9  //
    10  // NOTE: To import the global logger, import the "log" subpackage "github.com/rs/zerolog/log".
    11  //
    12  // Fields can be added to log messages:
    13  //
    14  //     log.Info().Str("foo", "bar").Msg("hello world")
    15  //     // Output: {"time":1494567715,"level":"info","message":"hello world","foo":"bar"}
    16  //
    17  // Create logger instance to manage different outputs:
    18  //
    19  //     logger := zerolog.New(os.Stderr).With().Timestamp().Logger()
    20  //     logger.Info().
    21  //            Str("foo", "bar").
    22  //            Msg("hello world")
    23  //     // Output: {"time":1494567715,"level":"info","message":"hello world","foo":"bar"}
    24  //
    25  // Sub-loggers let you chain loggers with additional context:
    26  //
    27  //     sublogger := log.With().Str("component": "foo").Logger()
    28  //     sublogger.Info().Msg("hello world")
    29  //     // Output: {"time":1494567715,"level":"info","message":"hello world","component":"foo"}
    30  //
    31  // Level logging
    32  //
    33  //     zerolog.SetGlobalLevel(zerolog.InfoLevel)
    34  //
    35  //     log.Debug().Msg("filtered out message")
    36  //     log.Info().Msg("routed message")
    37  //
    38  //     if e := log.Debug(); e.Enabled() {
    39  //         // Compute log output only if enabled.
    40  //         value := compute()
    41  //         e.Str("foo": value).Msg("some debug message")
    42  //     }
    43  //     // Output: {"level":"info","time":1494567715,"routed message"}
    44  //
    45  // Customize automatic field names:
    46  //
    47  //     log.TimestampFieldName = "t"
    48  //     log.LevelFieldName = "p"
    49  //     log.MessageFieldName = "m"
    50  //
    51  //     log.Info().Msg("hello world")
    52  //     // Output: {"t":1494567715,"p":"info","m":"hello world"}
    53  //
    54  // Log with no level and message:
    55  //
    56  //     log.Log().Str("foo","bar").Msg("")
    57  //     // Output: {"time":1494567715,"foo":"bar"}
    58  //
    59  // Add contextual fields to global Logger:
    60  //
    61  //     log.Logger = log.With().Str("foo", "bar").Logger()
    62  //
    63  // Sample logs:
    64  //
    65  //     sampled := log.Sample(&zerolog.BasicSampler{N: 10})
    66  //     sampled.Info().Msg("will be logged every 10 messages")
    67  //
    68  // Log with contextual hooks:
    69  //
    70  //     // Create the hook:
    71  //     type SeverityHook struct{}
    72  //
    73  //     func (h SeverityHook) Run(e *zerolog.Event, level zerolog.Level, msg string) {
    74  //          if level != zerolog.NoLevel {
    75  //              e.Str("severity", level.String())
    76  //          }
    77  //     }
    78  //
    79  //     // And use it:
    80  //     var h SeverityHook
    81  //     log := zerolog.New(os.Stdout).Hook(h)
    82  //     log.Warn().Msg("")
    83  //     // Output: {"level":"warn","severity":"warn"}
    84  //
    85  //
    86  // Caveats
    87  //
    88  // There is no fields deduplication out-of-the-box.
    89  // Using the same key multiple times creates new key in final JSON each time.
    90  //
    91  //     logger := zerolog.New(os.Stderr).With().Timestamp().Logger()
    92  //     logger.Info().
    93  //            Timestamp().
    94  //            Msg("dup")
    95  //     // Output: {"level":"info","time":1494567715,"time":1494567715,"message":"dup"}
    96  //
    97  // In this case, many consumers will take the last value,
    98  // but this is not guaranteed; check yours if in doubt.
    99  package zerolog
   100  
   101  import (
   102  	"errors"
   103  	"fmt"
   104  	"io"
   105  	"io/ioutil"
   106  	"os"
   107  	"strconv"
   108  )
   109  
   110  // Level defines log levels.
   111  type Level int8
   112  
   113  const (
   114  	// DebugLevel defines debug log level.
   115  	DebugLevel Level = iota
   116  	// InfoLevel defines info log level.
   117  	InfoLevel
   118  	// WarnLevel defines warn log level.
   119  	WarnLevel
   120  	// ErrorLevel defines error log level.
   121  	ErrorLevel
   122  	// FatalLevel defines fatal log level.
   123  	FatalLevel
   124  	// PanicLevel defines panic log level.
   125  	PanicLevel
   126  	// NoLevel defines an absent log level.
   127  	NoLevel
   128  	// Disabled disables the logger.
   129  	Disabled
   130  
   131  	// TraceLevel defines trace log level.
   132  	TraceLevel Level = -1
   133  	// Values less than TraceLevel are handled as numbers.
   134  )
   135  
   136  func (l Level) String() string {
   137  	switch l {
   138  	case TraceLevel:
   139  		return LevelTraceValue
   140  	case DebugLevel:
   141  		return LevelDebugValue
   142  	case InfoLevel:
   143  		return LevelInfoValue
   144  	case WarnLevel:
   145  		return LevelWarnValue
   146  	case ErrorLevel:
   147  		return LevelErrorValue
   148  	case FatalLevel:
   149  		return LevelFatalValue
   150  	case PanicLevel:
   151  		return LevelPanicValue
   152  	case Disabled:
   153  		return "disabled"
   154  	case NoLevel:
   155  		return ""
   156  	}
   157  	return strconv.Itoa(int(l))
   158  }
   159  
   160  // ParseLevel converts a level string into a zerolog Level value.
   161  // returns an error if the input string does not match known values.
   162  func ParseLevel(levelStr string) (Level, error) {
   163  	switch levelStr {
   164  	case LevelFieldMarshalFunc(TraceLevel):
   165  		return TraceLevel, nil
   166  	case LevelFieldMarshalFunc(DebugLevel):
   167  		return DebugLevel, nil
   168  	case LevelFieldMarshalFunc(InfoLevel):
   169  		return InfoLevel, nil
   170  	case LevelFieldMarshalFunc(WarnLevel):
   171  		return WarnLevel, nil
   172  	case LevelFieldMarshalFunc(ErrorLevel):
   173  		return ErrorLevel, nil
   174  	case LevelFieldMarshalFunc(FatalLevel):
   175  		return FatalLevel, nil
   176  	case LevelFieldMarshalFunc(PanicLevel):
   177  		return PanicLevel, nil
   178  	case LevelFieldMarshalFunc(Disabled):
   179  		return Disabled, nil
   180  	case LevelFieldMarshalFunc(NoLevel):
   181  		return NoLevel, nil
   182  	}
   183  	i, err := strconv.Atoi(levelStr)
   184  	if err != nil {
   185  		return NoLevel, fmt.Errorf("Unknown Level String: '%s', defaulting to NoLevel", levelStr)
   186  	}
   187  	if i > 127 || i < -128 {
   188  		return NoLevel, fmt.Errorf("Out-Of-Bounds Level: '%d', defaulting to NoLevel", i)
   189  	}
   190  	return Level(i), nil
   191  }
   192  
   193  // UnmarshalText implements encoding.TextUnmarshaler to allow for easy reading from toml/yaml/json formats
   194  func (l *Level) UnmarshalText(text []byte) error {
   195  	if l == nil {
   196  		return errors.New("can't unmarshal a nil *Level")
   197  	}
   198  	var err error
   199  	*l, err = ParseLevel(string(text))
   200  	return err
   201  }
   202  
   203  // MarshalText implements encoding.TextMarshaler to allow for easy writing into toml/yaml/json formats
   204  func (l Level) MarshalText() ([]byte, error) {
   205  	return []byte(LevelFieldMarshalFunc(l)), nil
   206  }
   207  
   208  // A Logger represents an active logging object that generates lines
   209  // of JSON output to an io.Writer. Each logging operation makes a single
   210  // call to the Writer's Write method. There is no guarantee on access
   211  // serialization to the Writer. If your Writer is not thread safe,
   212  // you may consider a sync wrapper.
   213  type Logger struct {
   214  	w       LevelWriter
   215  	level   Level
   216  	sampler Sampler
   217  	context []byte
   218  	hooks   []Hook
   219  	stack   bool
   220  }
   221  
   222  // New creates a root logger with given output writer. If the output writer implements
   223  // the LevelWriter interface, the WriteLevel method will be called instead of the Write
   224  // one.
   225  //
   226  // Each logging operation makes a single call to the Writer's Write method. There is no
   227  // guarantee on access serialization to the Writer. If your Writer is not thread safe,
   228  // you may consider using sync wrapper.
   229  func New(w io.Writer) Logger {
   230  	if w == nil {
   231  		w = ioutil.Discard
   232  	}
   233  	lw, ok := w.(LevelWriter)
   234  	if !ok {
   235  		lw = levelWriterAdapter{w}
   236  	}
   237  	return Logger{w: lw, level: TraceLevel}
   238  }
   239  
   240  // Nop returns a disabled logger for which all operation are no-op.
   241  func Nop() Logger {
   242  	return New(nil).Level(Disabled)
   243  }
   244  
   245  // Output duplicates the current logger and sets w as its output.
   246  func (l Logger) Output(w io.Writer) Logger {
   247  	l2 := New(w)
   248  	l2.level = l.level
   249  	l2.sampler = l.sampler
   250  	l2.stack = l.stack
   251  	if len(l.hooks) > 0 {
   252  		l2.hooks = append(l2.hooks, l.hooks...)
   253  	}
   254  	if l.context != nil {
   255  		l2.context = make([]byte, len(l.context), cap(l.context))
   256  		copy(l2.context, l.context)
   257  	}
   258  	return l2
   259  }
   260  
   261  // With creates a child logger with the field added to its context.
   262  func (l Logger) With() Context {
   263  	context := l.context
   264  	l.context = make([]byte, 0, 500)
   265  	if context != nil {
   266  		l.context = append(l.context, context...)
   267  	} else {
   268  		// This is needed for AppendKey to not check len of input
   269  		// thus making it inlinable
   270  		l.context = enc.AppendBeginMarker(l.context)
   271  	}
   272  	return Context{l}
   273  }
   274  
   275  // UpdateContext updates the internal logger's context.
   276  //
   277  // Use this method with caution. If unsure, prefer the With method.
   278  func (l *Logger) UpdateContext(update func(c Context) Context) {
   279  	if l == disabledLogger {
   280  		return
   281  	}
   282  	if cap(l.context) == 0 {
   283  		l.context = make([]byte, 0, 500)
   284  	}
   285  	if len(l.context) == 0 {
   286  		l.context = enc.AppendBeginMarker(l.context)
   287  	}
   288  	c := update(Context{*l})
   289  	l.context = c.l.context
   290  }
   291  
   292  // Level creates a child logger with the minimum accepted level set to level.
   293  func (l Logger) Level(lvl Level) Logger {
   294  	l.level = lvl
   295  	return l
   296  }
   297  
   298  // GetLevel returns the current Level of l.
   299  func (l Logger) GetLevel() Level {
   300  	return l.level
   301  }
   302  
   303  // Sample returns a logger with the s sampler.
   304  func (l Logger) Sample(s Sampler) Logger {
   305  	l.sampler = s
   306  	return l
   307  }
   308  
   309  // Hook returns a logger with the h Hook.
   310  func (l Logger) Hook(h Hook) Logger {
   311  	l.hooks = append(l.hooks, h)
   312  	return l
   313  }
   314  
   315  // Trace starts a new message with trace level.
   316  //
   317  // You must call Msg on the returned event in order to send the event.
   318  func (l *Logger) Trace() *Event {
   319  	return l.newEvent(TraceLevel, nil)
   320  }
   321  
   322  // Debug starts a new message with debug level.
   323  //
   324  // You must call Msg on the returned event in order to send the event.
   325  func (l *Logger) Debug() *Event {
   326  	return l.newEvent(DebugLevel, nil)
   327  }
   328  
   329  // Info starts a new message with info level.
   330  //
   331  // You must call Msg on the returned event in order to send the event.
   332  func (l *Logger) Info() *Event {
   333  	return l.newEvent(InfoLevel, nil)
   334  }
   335  
   336  // Warn starts a new message with warn level.
   337  //
   338  // You must call Msg on the returned event in order to send the event.
   339  func (l *Logger) Warn() *Event {
   340  	return l.newEvent(WarnLevel, nil)
   341  }
   342  
   343  // Error starts a new message with error level.
   344  //
   345  // You must call Msg on the returned event in order to send the event.
   346  func (l *Logger) Error() *Event {
   347  	return l.newEvent(ErrorLevel, nil)
   348  }
   349  
   350  // Err starts a new message with error level with err as a field if not nil or
   351  // with info level if err is nil.
   352  //
   353  // You must call Msg on the returned event in order to send the event.
   354  func (l *Logger) Err(err error) *Event {
   355  	if err != nil {
   356  		return l.Error().Err(err)
   357  	}
   358  
   359  	return l.Info()
   360  }
   361  
   362  // Fatal starts a new message with fatal level. The os.Exit(1) function
   363  // is called by the Msg method, which terminates the program immediately.
   364  //
   365  // You must call Msg on the returned event in order to send the event.
   366  func (l *Logger) Fatal() *Event {
   367  	return l.newEvent(FatalLevel, func(msg string) { os.Exit(1) })
   368  }
   369  
   370  // Panic starts a new message with panic level. The panic() function
   371  // is called by the Msg method, which stops the ordinary flow of a goroutine.
   372  //
   373  // You must call Msg on the returned event in order to send the event.
   374  func (l *Logger) Panic() *Event {
   375  	return l.newEvent(PanicLevel, func(msg string) { panic(msg) })
   376  }
   377  
   378  // WithLevel starts a new message with level. Unlike Fatal and Panic
   379  // methods, WithLevel does not terminate the program or stop the ordinary
   380  // flow of a goroutine when used with their respective levels.
   381  //
   382  // You must call Msg on the returned event in order to send the event.
   383  func (l *Logger) WithLevel(level Level) *Event {
   384  	switch level {
   385  	case TraceLevel:
   386  		return l.Trace()
   387  	case DebugLevel:
   388  		return l.Debug()
   389  	case InfoLevel:
   390  		return l.Info()
   391  	case WarnLevel:
   392  		return l.Warn()
   393  	case ErrorLevel:
   394  		return l.Error()
   395  	case FatalLevel:
   396  		return l.newEvent(FatalLevel, nil)
   397  	case PanicLevel:
   398  		return l.newEvent(PanicLevel, nil)
   399  	case NoLevel:
   400  		return l.Log()
   401  	case Disabled:
   402  		return nil
   403  	default:
   404  		return l.newEvent(level, nil)
   405  	}
   406  }
   407  
   408  // Log starts a new message with no level. Setting GlobalLevel to Disabled
   409  // will still disable events produced by this method.
   410  //
   411  // You must call Msg on the returned event in order to send the event.
   412  func (l *Logger) Log() *Event {
   413  	return l.newEvent(NoLevel, nil)
   414  }
   415  
   416  // Print sends a log event using debug level and no extra field.
   417  // Arguments are handled in the manner of fmt.Print.
   418  func (l *Logger) Print(v ...interface{}) {
   419  	if e := l.Debug(); e.Enabled() {
   420  		e.CallerSkipFrame(1).Msg(fmt.Sprint(v...))
   421  	}
   422  }
   423  
   424  // Printf sends a log event using debug level and no extra field.
   425  // Arguments are handled in the manner of fmt.Printf.
   426  func (l *Logger) Printf(format string, v ...interface{}) {
   427  	if e := l.Debug(); e.Enabled() {
   428  		e.CallerSkipFrame(1).Msg(fmt.Sprintf(format, v...))
   429  	}
   430  }
   431  
   432  // Write implements the io.Writer interface. This is useful to set as a writer
   433  // for the standard library log.
   434  func (l Logger) Write(p []byte) (n int, err error) {
   435  	n = len(p)
   436  	if n > 0 && p[n-1] == '\n' {
   437  		// Trim CR added by stdlog.
   438  		p = p[0 : n-1]
   439  	}
   440  	l.Log().CallerSkipFrame(1).Msg(string(p))
   441  	return
   442  }
   443  
   444  func (l *Logger) newEvent(level Level, done func(string)) *Event {
   445  	enabled := l.should(level)
   446  	if !enabled {
   447  		if done != nil {
   448  			done("")
   449  		}
   450  		return nil
   451  	}
   452  	e := newEvent(l.w, level)
   453  	e.done = done
   454  	e.ch = l.hooks
   455  	if level != NoLevel && LevelFieldName != "" {
   456  		e.Str(LevelFieldName, LevelFieldMarshalFunc(level))
   457  	}
   458  	if l.context != nil && len(l.context) > 1 {
   459  		e.buf = enc.AppendObjectData(e.buf, l.context)
   460  	}
   461  	if l.stack {
   462  		e.Stack()
   463  	}
   464  	return e
   465  }
   466  
   467  // should returns true if the log event should be logged.
   468  func (l *Logger) should(lvl Level) bool {
   469  	if lvl < l.level || lvl < GlobalLevel() {
   470  		return false
   471  	}
   472  	if l.sampler != nil && !samplingDisabled() {
   473  		return l.sampler.Sample(lvl)
   474  	}
   475  	return true
   476  }
   477  

View as plain text