xlog.go 13 KB

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