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. 99package zerolog 100 101import ( 102 "fmt" 103 "io" 104 "io/ioutil" 105 "os" 106 "strconv" 107) 108 109// Level defines log levels. 110type Level int8 111 112const ( 113 // DebugLevel defines debug log level. 114 DebugLevel Level = iota 115 // InfoLevel defines info log level. 116 InfoLevel 117 // WarnLevel defines warn log level. 118 WarnLevel 119 // ErrorLevel defines error log level. 120 ErrorLevel 121 // FatalLevel defines fatal log level. 122 FatalLevel 123 // PanicLevel defines panic log level. 124 PanicLevel 125 // NoLevel defines an absent log level. 126 NoLevel 127 // Disabled disables the logger. 128 Disabled 129 130 // TraceLevel defines trace log level. 131 TraceLevel Level = -1 132 // Values less than TraceLevel are handled as numbers. 133) 134 135func (l Level) String() string { 136 switch l { 137 case TraceLevel: 138 return LevelTraceValue 139 case DebugLevel: 140 return LevelDebugValue 141 case InfoLevel: 142 return LevelInfoValue 143 case WarnLevel: 144 return LevelWarnValue 145 case ErrorLevel: 146 return LevelErrorValue 147 case FatalLevel: 148 return LevelFatalValue 149 case PanicLevel: 150 return LevelPanicValue 151 case Disabled: 152 return "disabled" 153 case NoLevel: 154 return "" 155 } 156 return strconv.Itoa(int(l)) 157} 158 159// ParseLevel converts a level string into a zerolog Level value. 160// returns an error if the input string does not match known values. 161func ParseLevel(levelStr string) (Level, error) { 162 switch levelStr { 163 case LevelFieldMarshalFunc(TraceLevel): 164 return TraceLevel, nil 165 case LevelFieldMarshalFunc(DebugLevel): 166 return DebugLevel, nil 167 case LevelFieldMarshalFunc(InfoLevel): 168 return InfoLevel, nil 169 case LevelFieldMarshalFunc(WarnLevel): 170 return WarnLevel, nil 171 case LevelFieldMarshalFunc(ErrorLevel): 172 return ErrorLevel, nil 173 case LevelFieldMarshalFunc(FatalLevel): 174 return FatalLevel, nil 175 case LevelFieldMarshalFunc(PanicLevel): 176 return PanicLevel, nil 177 case LevelFieldMarshalFunc(Disabled): 178 return Disabled, nil 179 case LevelFieldMarshalFunc(NoLevel): 180 return NoLevel, nil 181 } 182 i, err := strconv.Atoi(levelStr) 183 if err != nil { 184 return NoLevel, fmt.Errorf("Unknown Level String: '%s', defaulting to NoLevel", levelStr) 185 } 186 if i > 127 || i < -128 { 187 return NoLevel, fmt.Errorf("Out-Of-Bounds Level: '%d', defaulting to NoLevel", i) 188 } 189 return Level(i), nil 190} 191 192// A Logger represents an active logging object that generates lines 193// of JSON output to an io.Writer. Each logging operation makes a single 194// call to the Writer's Write method. There is no guarantee on access 195// serialization to the Writer. If your Writer is not thread safe, 196// you may consider a sync wrapper. 197type Logger struct { 198 w LevelWriter 199 level Level 200 sampler Sampler 201 context []byte 202 hooks []Hook 203 stack bool 204} 205 206// New creates a root logger with given output writer. If the output writer implements 207// the LevelWriter interface, the WriteLevel method will be called instead of the Write 208// one. 209// 210// Each logging operation makes a single call to the Writer's Write method. There is no 211// guarantee on access serialization to the Writer. If your Writer is not thread safe, 212// you may consider using sync wrapper. 213func New(w io.Writer) Logger { 214 if w == nil { 215 w = ioutil.Discard 216 } 217 lw, ok := w.(LevelWriter) 218 if !ok { 219 lw = levelWriterAdapter{w} 220 } 221 return Logger{w: lw, level: TraceLevel} 222} 223 224// Nop returns a disabled logger for which all operation are no-op. 225func Nop() Logger { 226 return New(nil).Level(Disabled) 227} 228 229// Output duplicates the current logger and sets w as its output. 230func (l Logger) Output(w io.Writer) Logger { 231 l2 := New(w) 232 l2.level = l.level 233 l2.sampler = l.sampler 234 l2.stack = l.stack 235 if len(l.hooks) > 0 { 236 l2.hooks = append(l2.hooks, l.hooks...) 237 } 238 if l.context != nil { 239 l2.context = make([]byte, len(l.context), cap(l.context)) 240 copy(l2.context, l.context) 241 } 242 return l2 243} 244 245// With creates a child logger with the field added to its context. 246func (l Logger) With() Context { 247 context := l.context 248 l.context = make([]byte, 0, 500) 249 if context != nil { 250 l.context = append(l.context, context...) 251 } else { 252 // This is needed for AppendKey to not check len of input 253 // thus making it inlinable 254 l.context = enc.AppendBeginMarker(l.context) 255 } 256 return Context{l} 257} 258 259// UpdateContext updates the internal logger's context. 260// 261// Use this method with caution. If unsure, prefer the With method. 262func (l *Logger) UpdateContext(update func(c Context) Context) { 263 if l == disabledLogger { 264 return 265 } 266 if cap(l.context) == 0 { 267 l.context = make([]byte, 0, 500) 268 } 269 if len(l.context) == 0 { 270 l.context = enc.AppendBeginMarker(l.context) 271 } 272 c := update(Context{*l}) 273 l.context = c.l.context 274} 275 276// Level creates a child logger with the minimum accepted level set to level. 277func (l Logger) Level(lvl Level) Logger { 278 l.level = lvl 279 return l 280} 281 282// GetLevel returns the current Level of l. 283func (l Logger) GetLevel() Level { 284 return l.level 285} 286 287// Sample returns a logger with the s sampler. 288func (l Logger) Sample(s Sampler) Logger { 289 l.sampler = s 290 return l 291} 292 293// Hook returns a logger with the h Hook. 294func (l Logger) Hook(h Hook) Logger { 295 l.hooks = append(l.hooks, h) 296 return l 297} 298 299// Trace starts a new message with trace level. 300// 301// You must call Msg on the returned event in order to send the event. 302func (l *Logger) Trace() *Event { 303 return l.newEvent(TraceLevel, nil) 304} 305 306// Debug starts a new message with debug level. 307// 308// You must call Msg on the returned event in order to send the event. 309func (l *Logger) Debug() *Event { 310 return l.newEvent(DebugLevel, nil) 311} 312 313// Info starts a new message with info level. 314// 315// You must call Msg on the returned event in order to send the event. 316func (l *Logger) Info() *Event { 317 return l.newEvent(InfoLevel, nil) 318} 319 320// Warn starts a new message with warn level. 321// 322// You must call Msg on the returned event in order to send the event. 323func (l *Logger) Warn() *Event { 324 return l.newEvent(WarnLevel, nil) 325} 326 327// Error starts a new message with error level. 328// 329// You must call Msg on the returned event in order to send the event. 330func (l *Logger) Error() *Event { 331 return l.newEvent(ErrorLevel, nil) 332} 333 334// Err starts a new message with error level with err as a field if not nil or 335// with info level if err is nil. 336// 337// You must call Msg on the returned event in order to send the event. 338func (l *Logger) Err(err error) *Event { 339 if err != nil { 340 return l.Error().Err(err) 341 } 342 343 return l.Info() 344} 345 346// Fatal starts a new message with fatal level. The os.Exit(1) function 347// is called by the Msg method, which terminates the program immediately. 348// 349// You must call Msg on the returned event in order to send the event. 350func (l *Logger) Fatal() *Event { 351 return l.newEvent(FatalLevel, func(msg string) { os.Exit(1) }) 352} 353 354// Panic starts a new message with panic level. The panic() function 355// is called by the Msg method, which stops the ordinary flow of a goroutine. 356// 357// You must call Msg on the returned event in order to send the event. 358func (l *Logger) Panic() *Event { 359 return l.newEvent(PanicLevel, func(msg string) { panic(msg) }) 360} 361 362// WithLevel starts a new message with level. Unlike Fatal and Panic 363// methods, WithLevel does not terminate the program or stop the ordinary 364// flow of a gourotine when used with their respective levels. 365// 366// You must call Msg on the returned event in order to send the event. 367func (l *Logger) WithLevel(level Level) *Event { 368 switch level { 369 case TraceLevel: 370 return l.Trace() 371 case DebugLevel: 372 return l.Debug() 373 case InfoLevel: 374 return l.Info() 375 case WarnLevel: 376 return l.Warn() 377 case ErrorLevel: 378 return l.Error() 379 case FatalLevel: 380 return l.newEvent(FatalLevel, nil) 381 case PanicLevel: 382 return l.newEvent(PanicLevel, nil) 383 case NoLevel: 384 return l.Log() 385 case Disabled: 386 return nil 387 default: 388 return l.newEvent(level, nil) 389 } 390} 391 392// Log starts a new message with no level. Setting GlobalLevel to Disabled 393// will still disable events produced by this method. 394// 395// You must call Msg on the returned event in order to send the event. 396func (l *Logger) Log() *Event { 397 return l.newEvent(NoLevel, nil) 398} 399 400// Print sends a log event using debug level and no extra field. 401// Arguments are handled in the manner of fmt.Print. 402func (l *Logger) Print(v ...interface{}) { 403 if e := l.Debug(); e.Enabled() { 404 e.CallerSkipFrame(1).Msg(fmt.Sprint(v...)) 405 } 406} 407 408// Printf sends a log event using debug level and no extra field. 409// Arguments are handled in the manner of fmt.Printf. 410func (l *Logger) Printf(format string, v ...interface{}) { 411 if e := l.Debug(); e.Enabled() { 412 e.CallerSkipFrame(1).Msg(fmt.Sprintf(format, v...)) 413 } 414} 415 416// Write implements the io.Writer interface. This is useful to set as a writer 417// for the standard library log. 418func (l Logger) Write(p []byte) (n int, err error) { 419 n = len(p) 420 if n > 0 && p[n-1] == '\n' { 421 // Trim CR added by stdlog. 422 p = p[0 : n-1] 423 } 424 l.Log().CallerSkipFrame(1).Msg(string(p)) 425 return 426} 427 428func (l *Logger) newEvent(level Level, done func(string)) *Event { 429 enabled := l.should(level) 430 if !enabled { 431 return nil 432 } 433 e := newEvent(l.w, level) 434 e.done = done 435 e.ch = l.hooks 436 if level != NoLevel && LevelFieldName != "" { 437 e.Str(LevelFieldName, LevelFieldMarshalFunc(level)) 438 } 439 if l.context != nil && len(l.context) > 1 { 440 e.buf = enc.AppendObjectData(e.buf, l.context) 441 } 442 if l.stack { 443 e.Stack() 444 } 445 return e 446} 447 448// should returns true if the log event should be logged. 449func (l *Logger) should(lvl Level) bool { 450 if lvl < l.level || lvl < GlobalLevel() { 451 return false 452 } 453 if l.sampler != nil && !samplingDisabled() { 454 return l.sampler.Sample(lvl) 455 } 456 return true 457} 458