PageRenderTime 53ms CodeModel.GetById 24ms RepoModel.GetById 1ms app.codeStats 0ms

/log4go.go

https://code.google.com/p/log4go/
Go | 484 lines | 283 code | 47 blank | 154 comment | 29 complexity | e2ef2bfeaf8b1c782a9947a6402e2249 MD5 | raw file
Possible License(s): BSD-3-Clause
  1. // Copyright (C) 2010, Kyle Lemons <kyle@kylelemons.net>. All rights reserved.
  2. // Package log4go provides level-based and highly configurable logging.
  3. //
  4. // Enhanced Logging
  5. //
  6. // This is inspired by the logging functionality in Java. Essentially, you create a Logger
  7. // object and create output filters for it. You can send whatever you want to the Logger,
  8. // and it will filter that based on your settings and send it to the outputs. This way, you
  9. // can put as much debug code in your program as you want, and when you're done you can filter
  10. // out the mundane messages so only the important ones show up.
  11. //
  12. // Utility functions are provided to make life easier. Here is some example code to get started:
  13. //
  14. // log := log4go.NewLogger()
  15. // log.AddFilter("stdout", log4go.DEBUG, log4go.NewConsoleLogWriter())
  16. // log.AddFilter("log", log4go.FINE, log4go.NewFileLogWriter("example.log", true))
  17. // log.Info("The time is now: %s", time.LocalTime().Format("15:04:05 MST 2006/01/02"))
  18. //
  19. // The first two lines can be combined with the utility NewDefaultLogger:
  20. //
  21. // log := log4go.NewDefaultLogger(log4go.DEBUG)
  22. // log.AddFilter("log", log4go.FINE, log4go.NewFileLogWriter("example.log", true))
  23. // log.Info("The time is now: %s", time.LocalTime().Format("15:04:05 MST 2006/01/02"))
  24. //
  25. // Usage notes:
  26. // - The ConsoleLogWriter does not display the source of the message to standard
  27. // output, but the FileLogWriter does.
  28. // - The utility functions (Info, Debug, Warn, etc) derive their source from the
  29. // calling function, and this incurs extra overhead.
  30. //
  31. // Changes from 2.0:
  32. // - The external interface has remained mostly stable, but a lot of the
  33. // internals have been changed, so if you depended on any of this or created
  34. // your own LogWriter, then you will probably have to update your code. In
  35. // particular, Logger is now a map and ConsoleLogWriter is now a channel
  36. // behind-the-scenes, and the LogWrite method no longer has return values.
  37. //
  38. // Future work: (please let me know if you think I should work on any of these particularly)
  39. // - Log file rotation
  40. // - Logging configuration files ala log4j
  41. // - Have the ability to remove filters?
  42. // - Have GetInfoChannel, GetDebugChannel, etc return a chan string that allows
  43. // for another method of logging
  44. // - Add an XML filter type
  45. package log4go
  46. import (
  47. "errors"
  48. "os"
  49. "fmt"
  50. "time"
  51. "strings"
  52. "runtime"
  53. )
  54. // Version information
  55. const (
  56. L4G_VERSION = "log4go-v3.0.1"
  57. L4G_MAJOR = 3
  58. L4G_MINOR = 0
  59. L4G_BUILD = 1
  60. )
  61. /****** Constants ******/
  62. // These are the integer logging levels used by the logger
  63. type level int
  64. const (
  65. FINEST level = iota
  66. FINE
  67. DEBUG
  68. TRACE
  69. INFO
  70. WARNING
  71. ERROR
  72. CRITICAL
  73. )
  74. // Logging level strings
  75. var (
  76. levelStrings = [...]string{"FNST", "FINE", "DEBG", "TRAC", "INFO", "WARN", "EROR", "CRIT"}
  77. )
  78. func (l level) String() string {
  79. if l < 0 || int(l) > len(levelStrings) {
  80. return "UNKNOWN"
  81. }
  82. return levelStrings[int(l)]
  83. }
  84. /****** Variables ******/
  85. var (
  86. // LogBufferLength specifies how many log messages a particular log4go
  87. // logger can buffer at a time before writing them.
  88. LogBufferLength = 32
  89. )
  90. /****** LogRecord ******/
  91. // A LogRecord contains all of the pertinent information for each message
  92. type LogRecord struct {
  93. Level level // The log level
  94. Created time.Time // The time at which the log message was created (nanoseconds)
  95. Source string // The message source
  96. Message string // The log message
  97. }
  98. /****** LogWriter ******/
  99. // This is an interface for anything that should be able to write logs
  100. type LogWriter interface {
  101. // This will be called to log a LogRecord message.
  102. LogWrite(rec *LogRecord)
  103. // This should clean up anything lingering about the LogWriter, as it is called before
  104. // the LogWriter is removed. LogWrite should not be called after Close.
  105. Close()
  106. }
  107. /****** Logger ******/
  108. // A Filter represents the log level below which no log records are written to
  109. // the associated LogWriter.
  110. type Filter struct {
  111. Level level
  112. LogWriter
  113. }
  114. // A Logger represents a collection of Filters through which log messages are
  115. // written.
  116. type Logger map[string]*Filter
  117. // Create a new logger.
  118. //
  119. // DEPRECATED: Use make(Logger) instead.
  120. func NewLogger() Logger {
  121. os.Stderr.WriteString("warning: use of deprecated NewLogger\n")
  122. return make(Logger)
  123. }
  124. // Create a new logger with a "stdout" filter configured to send log messages at
  125. // or above lvl to standard output.
  126. //
  127. // DEPRECATED: use NewDefaultLogger instead.
  128. func NewConsoleLogger(lvl level) Logger {
  129. os.Stderr.WriteString("warning: use of deprecated NewConsoleLogger\n")
  130. return Logger{
  131. "stdout": &Filter{lvl, NewConsoleLogWriter()},
  132. }
  133. }
  134. // Create a new logger with a "stdout" filter configured to send log messages at
  135. // or above lvl to standard output.
  136. func NewDefaultLogger(lvl level) Logger {
  137. return Logger{
  138. "stdout": &Filter{lvl, NewConsoleLogWriter()},
  139. }
  140. }
  141. // Closes all log writers in preparation for exiting the program or a
  142. // reconfiguration of logging. Calling this is not really imperative, unless
  143. // you want to guarantee that all log messages are written. Close removes
  144. // all filters (and thus all LogWriters) from the logger.
  145. func (log Logger) Close() {
  146. // Close all open loggers
  147. for name, filt := range log {
  148. filt.Close()
  149. delete(log, name)
  150. }
  151. }
  152. // Add a new LogWriter to the Logger which will only log messages at lvl or
  153. // higher. This function should not be called from multiple goroutines.
  154. // Returns the logger for chaining.
  155. func (log Logger) AddFilter(name string, lvl level, writer LogWriter) Logger {
  156. log[name] = &Filter{lvl, writer}
  157. return log
  158. }
  159. /******* Logging *******/
  160. // Send a formatted log message internally
  161. func (log Logger) intLogf(lvl level, format string, args ...interface{}) {
  162. skip := true
  163. // Determine if any logging will be done
  164. for _, filt := range log {
  165. if lvl >= filt.Level {
  166. skip = false
  167. break
  168. }
  169. }
  170. if skip {
  171. return
  172. }
  173. // Determine caller func
  174. pc, _, lineno, ok := runtime.Caller(2)
  175. src := ""
  176. if ok {
  177. src = fmt.Sprintf("%s:%d", runtime.FuncForPC(pc).Name(), lineno)
  178. }
  179. msg := format
  180. if len(args) > 0 {
  181. msg = fmt.Sprintf(format, args...)
  182. }
  183. // Make the log record
  184. rec := &LogRecord{
  185. Level: lvl,
  186. Created: time.Now(),
  187. Source: src,
  188. Message: msg,
  189. }
  190. // Dispatch the logs
  191. for _, filt := range log {
  192. if lvl < filt.Level {
  193. continue
  194. }
  195. filt.LogWrite(rec)
  196. }
  197. }
  198. // Send a closure log message internally
  199. func (log Logger) intLogc(lvl level, closure func() string) {
  200. skip := true
  201. // Determine if any logging will be done
  202. for _, filt := range log {
  203. if lvl >= filt.Level {
  204. skip = false
  205. break
  206. }
  207. }
  208. if skip {
  209. return
  210. }
  211. // Determine caller func
  212. pc, _, lineno, ok := runtime.Caller(2)
  213. src := ""
  214. if ok {
  215. src = fmt.Sprintf("%s:%d", runtime.FuncForPC(pc).Name(), lineno)
  216. }
  217. // Make the log record
  218. rec := &LogRecord{
  219. Level: lvl,
  220. Created: time.Now(),
  221. Source: src,
  222. Message: closure(),
  223. }
  224. // Dispatch the logs
  225. for _, filt := range log {
  226. if lvl < filt.Level {
  227. continue
  228. }
  229. filt.LogWrite(rec)
  230. }
  231. }
  232. // Send a log message with manual level, source, and message.
  233. func (log Logger) Log(lvl level, source, message string) {
  234. skip := true
  235. // Determine if any logging will be done
  236. for _, filt := range log {
  237. if lvl >= filt.Level {
  238. skip = false
  239. break
  240. }
  241. }
  242. if skip {
  243. return
  244. }
  245. // Make the log record
  246. rec := &LogRecord{
  247. Level: lvl,
  248. Created: time.Now(),
  249. Source: source,
  250. Message: message,
  251. }
  252. // Dispatch the logs
  253. for _, filt := range log {
  254. if lvl < filt.Level {
  255. continue
  256. }
  257. filt.LogWrite(rec)
  258. }
  259. }
  260. // Logf logs a formatted log message at the given log level, using the caller as
  261. // its source.
  262. func (log Logger) Logf(lvl level, format string, args ...interface{}) {
  263. log.intLogf(lvl, format, args...)
  264. }
  265. // Logc logs a string returned by the closure at the given log level, using the caller as
  266. // its source. If no log message would be written, the closure is never called.
  267. func (log Logger) Logc(lvl level, closure func() string) {
  268. log.intLogc(lvl, closure)
  269. }
  270. // Finest logs a message at the finest log level.
  271. // See Debug for an explanation of the arguments.
  272. func (log Logger) Finest(arg0 interface{}, args ...interface{}) {
  273. const (
  274. lvl = FINEST
  275. )
  276. switch first := arg0.(type) {
  277. case string:
  278. // Use the string as a format string
  279. log.intLogf(lvl, first, args...)
  280. case func() string:
  281. // Log the closure (no other arguments used)
  282. log.intLogc(lvl, first)
  283. default:
  284. // Build a format string so that it will be similar to Sprint
  285. log.intLogf(lvl, fmt.Sprint(arg0)+strings.Repeat(" %v", len(args)), args...)
  286. }
  287. }
  288. // Fine logs a message at the fine log level.
  289. // See Debug for an explanation of the arguments.
  290. func (log Logger) Fine(arg0 interface{}, args ...interface{}) {
  291. const (
  292. lvl = FINE
  293. )
  294. switch first := arg0.(type) {
  295. case string:
  296. // Use the string as a format string
  297. log.intLogf(lvl, first, args...)
  298. case func() string:
  299. // Log the closure (no other arguments used)
  300. log.intLogc(lvl, first)
  301. default:
  302. // Build a format string so that it will be similar to Sprint
  303. log.intLogf(lvl, fmt.Sprint(arg0)+strings.Repeat(" %v", len(args)), args...)
  304. }
  305. }
  306. // Debug is a utility method for debug log messages.
  307. // The behavior of Debug depends on the first argument:
  308. // - arg0 is a string
  309. // When given a string as the first argument, this behaves like Logf but with
  310. // the DEBUG log level: the first argument is interpreted as a format for the
  311. // latter arguments.
  312. // - arg0 is a func()string
  313. // When given a closure of type func()string, this logs the string returned by
  314. // the closure iff it will be logged. The closure runs at most one time.
  315. // - arg0 is interface{}
  316. // When given anything else, the log message will be each of the arguments
  317. // formatted with %v and separated by spaces (ala Sprint).
  318. func (log Logger) Debug(arg0 interface{}, args ...interface{}) {
  319. const (
  320. lvl = DEBUG
  321. )
  322. switch first := arg0.(type) {
  323. case string:
  324. // Use the string as a format string
  325. log.intLogf(lvl, first, args...)
  326. case func() string:
  327. // Log the closure (no other arguments used)
  328. log.intLogc(lvl, first)
  329. default:
  330. // Build a format string so that it will be similar to Sprint
  331. log.intLogf(lvl, fmt.Sprint(arg0)+strings.Repeat(" %v", len(args)), args...)
  332. }
  333. }
  334. // Trace logs a message at the trace log level.
  335. // See Debug for an explanation of the arguments.
  336. func (log Logger) Trace(arg0 interface{}, args ...interface{}) {
  337. const (
  338. lvl = TRACE
  339. )
  340. switch first := arg0.(type) {
  341. case string:
  342. // Use the string as a format string
  343. log.intLogf(lvl, first, args...)
  344. case func() string:
  345. // Log the closure (no other arguments used)
  346. log.intLogc(lvl, first)
  347. default:
  348. // Build a format string so that it will be similar to Sprint
  349. log.intLogf(lvl, fmt.Sprint(arg0)+strings.Repeat(" %v", len(args)), args...)
  350. }
  351. }
  352. // Info logs a message at the info log level.
  353. // See Debug for an explanation of the arguments.
  354. func (log Logger) Info(arg0 interface{}, args ...interface{}) {
  355. const (
  356. lvl = INFO
  357. )
  358. switch first := arg0.(type) {
  359. case string:
  360. // Use the string as a format string
  361. log.intLogf(lvl, first, args...)
  362. case func() string:
  363. // Log the closure (no other arguments used)
  364. log.intLogc(lvl, first)
  365. default:
  366. // Build a format string so that it will be similar to Sprint
  367. log.intLogf(lvl, fmt.Sprint(arg0)+strings.Repeat(" %v", len(args)), args...)
  368. }
  369. }
  370. // Warn logs a message at the warning log level and returns the formatted error.
  371. // At the warning level and higher, there is no performance benefit if the
  372. // message is not actually logged, because all formats are processed and all
  373. // closures are executed to format the error message.
  374. // See Debug for further explanation of the arguments.
  375. func (log Logger) Warn(arg0 interface{}, args ...interface{}) error {
  376. const (
  377. lvl = WARNING
  378. )
  379. var msg string
  380. switch first := arg0.(type) {
  381. case string:
  382. // Use the string as a format string
  383. msg = fmt.Sprintf(first, args...)
  384. case func() string:
  385. // Log the closure (no other arguments used)
  386. msg = first()
  387. default:
  388. // Build a format string so that it will be similar to Sprint
  389. msg = fmt.Sprintf(fmt.Sprint(first)+strings.Repeat(" %v", len(args)), args...)
  390. }
  391. log.intLogf(lvl, msg)
  392. return errors.New(msg)
  393. }
  394. // Error logs a message at the error log level and returns the formatted error,
  395. // See Warn for an explanation of the performance and Debug for an explanation
  396. // of the parameters.
  397. func (log Logger) Error(arg0 interface{}, args ...interface{}) error {
  398. const (
  399. lvl = ERROR
  400. )
  401. var msg string
  402. switch first := arg0.(type) {
  403. case string:
  404. // Use the string as a format string
  405. msg = fmt.Sprintf(first, args...)
  406. case func() string:
  407. // Log the closure (no other arguments used)
  408. msg = first()
  409. default:
  410. // Build a format string so that it will be similar to Sprint
  411. msg = fmt.Sprintf(fmt.Sprint(first)+strings.Repeat(" %v", len(args)), args...)
  412. }
  413. log.intLogf(lvl, msg)
  414. return errors.New(msg)
  415. }
  416. // Critical logs a message at the critical log level and returns the formatted error,
  417. // See Warn for an explanation of the performance and Debug for an explanation
  418. // of the parameters.
  419. func (log Logger) Critical(arg0 interface{}, args ...interface{}) error {
  420. const (
  421. lvl = CRITICAL
  422. )
  423. var msg string
  424. switch first := arg0.(type) {
  425. case string:
  426. // Use the string as a format string
  427. msg = fmt.Sprintf(first, args...)
  428. case func() string:
  429. // Log the closure (no other arguments used)
  430. msg = first()
  431. default:
  432. // Build a format string so that it will be similar to Sprint
  433. msg = fmt.Sprintf(fmt.Sprint(first)+strings.Repeat(" %v", len(args)), args...)
  434. }
  435. log.intLogf(lvl, msg)
  436. return errors.New(msg)
  437. }