1// Copyright 2014-2017 Ulrich Kunitz. All rights reserved. 2// Use of this source code is governed by a BSD-style 3// license that can be found in the LICENSE file. 4 5// Package xlog provides a simple logging package that allows to disable 6// certain message categories. It defines a type, Logger, with multiple 7// methods for formatting output. The package has also a predefined 8// 'standard' Logger accessible through helper function Print[f|ln], 9// Fatal[f|ln], Panic[f|ln], Warn[f|ln], Print[f|ln] and Debug[f|ln] 10// that are easier to use then creating a Logger manually. That logger 11// writes to standard error and prints the date and time of each logged 12// message, which can be configured using the function SetFlags. 13// 14// The Fatal functions call os.Exit(1) after the message is output 15// unless not suppressed by the flags. The Panic functions call panic 16// after the writing the log message unless suppressed. 17package xlog 18 19import ( 20 "fmt" 21 "io" 22 "os" 23 "runtime" 24 "sync" 25 "time" 26) 27 28// The flags define what information is prefixed to each log entry 29// generated by the Logger. The Lno* versions allow the suppression of 30// specific output. The bits are or'ed together to control what will be 31// printed. There is no control over the order of the items printed and 32// the format. The full format is: 33// 34// 2009-01-23 01:23:23.123123 /a/b/c/d.go:23: message 35// 36const ( 37 Ldate = 1 << iota // the date: 2009-01-23 38 Ltime // the time: 01:23:23 39 Lmicroseconds // microsecond resolution: 01:23:23.123123 40 Llongfile // full file name and line number: /a/b/c/d.go:23 41 Lshortfile // final file name element and line number: d.go:23 42 Lnopanic // suppresses output from Panic[f|ln] but not the panic call 43 Lnofatal // suppresses output from Fatal[f|ln] but not the exit 44 Lnowarn // suppresses output from Warn[f|ln] 45 Lnoprint // suppresses output from Print[f|ln] 46 Lnodebug // suppresses output from Debug[f|ln] 47 // initial values for the standard logger 48 Lstdflags = Ldate | Ltime | Lnodebug 49) 50 51// A Logger represents an active logging object that generates lines of 52// output to an io.Writer. Each logging operation if not suppressed 53// makes a single call to the Writer's Write method. A Logger can be 54// used simultaneously from multiple goroutines; it guarantees to 55// serialize access to the Writer. 56type Logger struct { 57 mu sync.Mutex // ensures atomic writes; and protects the following 58 // fields 59 prefix string // prefix to write at beginning of each line 60 flag int // properties 61 out io.Writer // destination for output 62 buf []byte // for accumulating text to write 63} 64 65// New creates a new Logger. The out argument sets the destination to 66// which the log output will be written. The prefix appears at the 67// beginning of each log line. The flag argument defines the logging 68// properties. 69func New(out io.Writer, prefix string, flag int) *Logger { 70 return &Logger{out: out, prefix: prefix, flag: flag} 71} 72 73// std is the standard logger used by the package scope functions. 74var std = New(os.Stderr, "", Lstdflags) 75 76// itoa converts the integer to ASCII. A negative widths will avoid 77// zero-padding. The function supports only non-negative integers. 78func itoa(buf *[]byte, i int, wid int) { 79 var u = uint(i) 80 if u == 0 && wid <= 1 { 81 *buf = append(*buf, '0') 82 return 83 } 84 var b [32]byte 85 bp := len(b) 86 for ; u > 0 || wid > 0; u /= 10 { 87 bp-- 88 wid-- 89 b[bp] = byte(u%10) + '0' 90 } 91 *buf = append(*buf, b[bp:]...) 92} 93 94// formatHeader puts the header into the buf field of the buffer. 95func (l *Logger) formatHeader(t time.Time, file string, line int) { 96 l.buf = append(l.buf, l.prefix...) 97 if l.flag&(Ldate|Ltime|Lmicroseconds) != 0 { 98 if l.flag&Ldate != 0 { 99 year, month, day := t.Date() 100 itoa(&l.buf, year, 4) 101 l.buf = append(l.buf, '-') 102 itoa(&l.buf, int(month), 2) 103 l.buf = append(l.buf, '-') 104 itoa(&l.buf, day, 2) 105 l.buf = append(l.buf, ' ') 106 } 107 if l.flag&(Ltime|Lmicroseconds) != 0 { 108 hour, min, sec := t.Clock() 109 itoa(&l.buf, hour, 2) 110 l.buf = append(l.buf, ':') 111 itoa(&l.buf, min, 2) 112 l.buf = append(l.buf, ':') 113 itoa(&l.buf, sec, 2) 114 if l.flag&Lmicroseconds != 0 { 115 l.buf = append(l.buf, '.') 116 itoa(&l.buf, t.Nanosecond()/1e3, 6) 117 } 118 l.buf = append(l.buf, ' ') 119 } 120 } 121 if l.flag&(Lshortfile|Llongfile) != 0 { 122 if l.flag&Lshortfile != 0 { 123 short := file 124 for i := len(file) - 1; i > 0; i-- { 125 if file[i] == '/' { 126 short = file[i+1:] 127 break 128 } 129 } 130 file = short 131 } 132 l.buf = append(l.buf, file...) 133 l.buf = append(l.buf, ':') 134 itoa(&l.buf, line, -1) 135 l.buf = append(l.buf, ": "...) 136 } 137} 138 139func (l *Logger) output(calldepth int, now time.Time, s string) error { 140 var file string 141 var line int 142 if l.flag&(Lshortfile|Llongfile) != 0 { 143 l.mu.Unlock() 144 var ok bool 145 _, file, line, ok = runtime.Caller(calldepth) 146 if !ok { 147 file = "???" 148 line = 0 149 } 150 l.mu.Lock() 151 } 152 l.buf = l.buf[:0] 153 l.formatHeader(now, file, line) 154 l.buf = append(l.buf, s...) 155 if len(s) == 0 || s[len(s)-1] != '\n' { 156 l.buf = append(l.buf, '\n') 157 } 158 _, err := l.out.Write(l.buf) 159 return err 160} 161 162// Output writes the string s with the header controlled by the flags to 163// the l.out writer. A newline will be appended if s doesn't end in a 164// newline. Calldepth is used to recover the PC, although all current 165// calls of Output use the call depth 2. Access to the function is serialized. 166func (l *Logger) Output(calldepth, noflag int, v ...interface{}) error { 167 now := time.Now() 168 l.mu.Lock() 169 defer l.mu.Unlock() 170 if l.flag&noflag != 0 { 171 return nil 172 } 173 s := fmt.Sprint(v...) 174 return l.output(calldepth+1, now, s) 175} 176 177// Outputf works like output but formats the output like Printf. 178func (l *Logger) Outputf(calldepth int, noflag int, format string, v ...interface{}) error { 179 now := time.Now() 180 l.mu.Lock() 181 defer l.mu.Unlock() 182 if l.flag&noflag != 0 { 183 return nil 184 } 185 s := fmt.Sprintf(format, v...) 186 return l.output(calldepth+1, now, s) 187} 188 189// Outputln works like output but formats the output like Println. 190func (l *Logger) Outputln(calldepth int, noflag int, v ...interface{}) error { 191 now := time.Now() 192 l.mu.Lock() 193 defer l.mu.Unlock() 194 if l.flag&noflag != 0 { 195 return nil 196 } 197 s := fmt.Sprintln(v...) 198 return l.output(calldepth+1, now, s) 199} 200 201// Panic prints the message like Print and calls panic. The printing 202// might be suppressed by the flag Lnopanic. 203func (l *Logger) Panic(v ...interface{}) { 204 l.Output(2, Lnopanic, v...) 205 s := fmt.Sprint(v...) 206 panic(s) 207} 208 209// Panic prints the message like Print and calls panic. The printing 210// might be suppressed by the flag Lnopanic. 211func Panic(v ...interface{}) { 212 std.Output(2, Lnopanic, v...) 213 s := fmt.Sprint(v...) 214 panic(s) 215} 216 217// Panicf prints the message like Printf and calls panic. The printing 218// might be suppressed by the flag Lnopanic. 219func (l *Logger) Panicf(format string, v ...interface{}) { 220 l.Outputf(2, Lnopanic, format, v...) 221 s := fmt.Sprintf(format, v...) 222 panic(s) 223} 224 225// Panicf prints the message like Printf and calls panic. The printing 226// might be suppressed by the flag Lnopanic. 227func Panicf(format string, v ...interface{}) { 228 std.Outputf(2, Lnopanic, format, v...) 229 s := fmt.Sprintf(format, v...) 230 panic(s) 231} 232 233// Panicln prints the message like Println and calls panic. The printing 234// might be suppressed by the flag Lnopanic. 235func (l *Logger) Panicln(v ...interface{}) { 236 l.Outputln(2, Lnopanic, v...) 237 s := fmt.Sprintln(v...) 238 panic(s) 239} 240 241// Panicln prints the message like Println and calls panic. The printing 242// might be suppressed by the flag Lnopanic. 243func Panicln(v ...interface{}) { 244 std.Outputln(2, Lnopanic, v...) 245 s := fmt.Sprintln(v...) 246 panic(s) 247} 248 249// Fatal prints the message like Print and calls os.Exit(1). The 250// printing might be suppressed by the flag Lnofatal. 251func (l *Logger) Fatal(v ...interface{}) { 252 l.Output(2, Lnofatal, v...) 253 os.Exit(1) 254} 255 256// Fatal prints the message like Print and calls os.Exit(1). The 257// printing might be suppressed by the flag Lnofatal. 258func Fatal(v ...interface{}) { 259 std.Output(2, Lnofatal, v...) 260 os.Exit(1) 261} 262 263// Fatalf prints the message like Printf and calls os.Exit(1). The 264// printing might be suppressed by the flag Lnofatal. 265func (l *Logger) Fatalf(format string, v ...interface{}) { 266 l.Outputf(2, Lnofatal, format, v...) 267 os.Exit(1) 268} 269 270// Fatalf prints the message like Printf and calls os.Exit(1). The 271// printing might be suppressed by the flag Lnofatal. 272func Fatalf(format string, v ...interface{}) { 273 std.Outputf(2, Lnofatal, format, v...) 274 os.Exit(1) 275} 276 277// Fatalln prints the message like Println and calls os.Exit(1). The 278// printing might be suppressed by the flag Lnofatal. 279func (l *Logger) Fatalln(format string, v ...interface{}) { 280 l.Outputln(2, Lnofatal, v...) 281 os.Exit(1) 282} 283 284// Fatalln prints the message like Println and calls os.Exit(1). The 285// printing might be suppressed by the flag Lnofatal. 286func Fatalln(format string, v ...interface{}) { 287 std.Outputln(2, Lnofatal, v...) 288 os.Exit(1) 289} 290 291// Warn prints the message like Print. The printing might be suppressed 292// by the flag Lnowarn. 293func (l *Logger) Warn(v ...interface{}) { 294 l.Output(2, Lnowarn, v...) 295} 296 297// Warn prints the message like Print. The printing might be suppressed 298// by the flag Lnowarn. 299func Warn(v ...interface{}) { 300 std.Output(2, Lnowarn, v...) 301} 302 303// Warnf prints the message like Printf. The printing might be suppressed 304// by the flag Lnowarn. 305func (l *Logger) Warnf(format string, v ...interface{}) { 306 l.Outputf(2, Lnowarn, format, v...) 307} 308 309// Warnf prints the message like Printf. The printing might be suppressed 310// by the flag Lnowarn. 311func Warnf(format string, v ...interface{}) { 312 std.Outputf(2, Lnowarn, format, v...) 313} 314 315// Warnln prints the message like Println. The printing might be suppressed 316// by the flag Lnowarn. 317func (l *Logger) Warnln(v ...interface{}) { 318 l.Outputln(2, Lnowarn, v...) 319} 320 321// Warnln prints the message like Println. The printing might be suppressed 322// by the flag Lnowarn. 323func Warnln(v ...interface{}) { 324 std.Outputln(2, Lnowarn, v...) 325} 326 327// Print prints the message like fmt.Print. The printing might be suppressed 328// by the flag Lnoprint. 329func (l *Logger) Print(v ...interface{}) { 330 l.Output(2, Lnoprint, v...) 331} 332 333// Print prints the message like fmt.Print. The printing might be suppressed 334// by the flag Lnoprint. 335func Print(v ...interface{}) { 336 std.Output(2, Lnoprint, v...) 337} 338 339// Printf prints the message like fmt.Printf. The printing might be suppressed 340// by the flag Lnoprint. 341func (l *Logger) Printf(format string, v ...interface{}) { 342 l.Outputf(2, Lnoprint, format, v...) 343} 344 345// Printf prints the message like fmt.Printf. The printing might be suppressed 346// by the flag Lnoprint. 347func Printf(format string, v ...interface{}) { 348 std.Outputf(2, Lnoprint, format, v...) 349} 350 351// Println prints the message like fmt.Println. The printing might be 352// suppressed by the flag Lnoprint. 353func (l *Logger) Println(v ...interface{}) { 354 l.Outputln(2, Lnoprint, v...) 355} 356 357// Println prints the message like fmt.Println. The printing might be 358// suppressed by the flag Lnoprint. 359func Println(v ...interface{}) { 360 std.Outputln(2, Lnoprint, v...) 361} 362 363// Debug prints the message like Print. The printing might be suppressed 364// by the flag Lnodebug. 365func (l *Logger) Debug(v ...interface{}) { 366 l.Output(2, Lnodebug, v...) 367} 368 369// Debug prints the message like Print. The printing might be suppressed 370// by the flag Lnodebug. 371func Debug(v ...interface{}) { 372 std.Output(2, Lnodebug, v...) 373} 374 375// Debugf prints the message like Printf. The printing might be suppressed 376// by the flag Lnodebug. 377func (l *Logger) Debugf(format string, v ...interface{}) { 378 l.Outputf(2, Lnodebug, format, v...) 379} 380 381// Debugf prints the message like Printf. The printing might be suppressed 382// by the flag Lnodebug. 383func Debugf(format string, v ...interface{}) { 384 std.Outputf(2, Lnodebug, format, v...) 385} 386 387// Debugln prints the message like Println. The printing might be suppressed 388// by the flag Lnodebug. 389func (l *Logger) Debugln(v ...interface{}) { 390 l.Outputln(2, Lnodebug, v...) 391} 392 393// Debugln prints the message like Println. The printing might be suppressed 394// by the flag Lnodebug. 395func Debugln(v ...interface{}) { 396 std.Outputln(2, Lnodebug, v...) 397} 398 399// Flags returns the current flags used by the logger. 400func (l *Logger) Flags() int { 401 l.mu.Lock() 402 defer l.mu.Unlock() 403 return l.flag 404} 405 406// Flags returns the current flags used by the standard logger. 407func Flags() int { 408 return std.Flags() 409} 410 411// SetFlags sets the flags of the logger. 412func (l *Logger) SetFlags(flag int) { 413 l.mu.Lock() 414 defer l.mu.Unlock() 415 l.flag = flag 416} 417 418// SetFlags sets the flags for the standard logger. 419func SetFlags(flag int) { 420 std.SetFlags(flag) 421} 422 423// Prefix returns the prefix used by the logger. 424func (l *Logger) Prefix() string { 425 l.mu.Lock() 426 defer l.mu.Unlock() 427 return l.prefix 428} 429 430// Prefix returns the prefix used by the standard logger of the package. 431func Prefix() string { 432 return std.Prefix() 433} 434 435// SetPrefix sets the prefix for the logger. 436func (l *Logger) SetPrefix(prefix string) { 437 l.mu.Lock() 438 defer l.mu.Unlock() 439 l.prefix = prefix 440} 441 442// SetPrefix sets the prefix of the standard logger of the package. 443func SetPrefix(prefix string) { 444 std.SetPrefix(prefix) 445} 446 447// SetOutput sets the output of the logger. 448func (l *Logger) SetOutput(w io.Writer) { 449 l.mu.Lock() 450 defer l.mu.Unlock() 451 l.out = w 452} 453 454// SetOutput sets the output for the standard logger of the package. 455func SetOutput(w io.Writer) { 456 std.SetOutput(w) 457} 458