logger.go 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717
  1. package golog
  2. import (
  3. "fmt"
  4. "io"
  5. "os"
  6. "strings"
  7. "sync"
  8. "github.com/kataras/pio"
  9. )
  10. // Handler is the signature type for logger's handler.
  11. //
  12. // A Handler can be used to intercept the message between a log value
  13. // and the actual print operation, it's called
  14. // when one of the print functions called.
  15. // If it's return value is true then it means that the specific
  16. // handler handled the log by itself therefore no need to
  17. // proceed with the default behavior of printing the log
  18. // to the specified logger's output.
  19. //
  20. // It stops on the handler which returns true firstly.
  21. // The `Log` value holds the level of the print operation as well.
  22. type Handler func(value *Log) (handled bool)
  23. // Logger is our golog.
  24. type Logger struct {
  25. Prefix string
  26. Level Level
  27. TimeFormat string
  28. // Limit stacktrace entries on `Debug` level.
  29. StacktraceLimit int
  30. // if new line should be added on all log functions, even the `F`s.
  31. // It defaults to true.
  32. //
  33. // See `golog#NewLine(newLineChar string)` as well.
  34. //
  35. // Note that this will not override the time and level prefix,
  36. // if you want to customize the log message please read the examples
  37. // or navigate to: https://github.com/kataras/golog/issues/3#issuecomment-355895870.
  38. NewLine bool
  39. mu sync.RWMutex // for logger field changes and printing through pio hijacker.
  40. Printer *pio.Printer
  41. // The per log level raw writers, optionally.
  42. LevelOutput map[Level]io.Writer
  43. formatters map[string]Formatter // available formatters.
  44. formatter Formatter // the current formatter for all logs.
  45. LevelFormatter map[Level]Formatter // per level formatter.
  46. handlers []Handler
  47. once sync.Once
  48. logs sync.Pool
  49. children *loggerMap
  50. }
  51. // New returns a new golog with a default output to `os.Stdout`
  52. // and level to `InfoLevel`.
  53. func New() *Logger {
  54. return &Logger{
  55. Level: InfoLevel,
  56. TimeFormat: "2006/01/02 15:04",
  57. NewLine: true,
  58. Printer: pio.NewPrinter("", os.Stdout).EnableDirectOutput().Hijack(logHijacker).SetSync(true),
  59. LevelOutput: make(map[Level]io.Writer),
  60. formatters: map[string]Formatter{ // the available builtin formatters.
  61. "json": new(JSONFormatter),
  62. },
  63. LevelFormatter: make(map[Level]Formatter),
  64. children: newLoggerMap(),
  65. }
  66. }
  67. // Fields is a map type.
  68. // One or more values of `Fields` type can be passed
  69. // on all Log methods except `Print/Printf/Println` to set the `Log.Fields` field,
  70. // which can be accessed through a custom LogHandler.
  71. type Fields map[string]interface{}
  72. // acquireLog returns a new log fom the pool.
  73. func (l *Logger) acquireLog(level Level, msg string, withPrintln bool, fields Fields) *Log {
  74. log, ok := l.logs.Get().(*Log)
  75. if !ok {
  76. log = &Log{
  77. Logger: l,
  78. }
  79. }
  80. log.NewLine = withPrintln
  81. if l.TimeFormat != "" {
  82. log.Time = Now()
  83. log.Timestamp = log.Time.Unix()
  84. }
  85. log.Level = level
  86. log.Message = msg
  87. log.Fields = fields
  88. log.Stacktrace = log.Stacktrace[:0]
  89. return log
  90. }
  91. // releaseLog Log releases a log instance back to the pool.
  92. func (l *Logger) releaseLog(log *Log) {
  93. l.logs.Put(log)
  94. }
  95. var spaceBytes = []byte(" ")
  96. // we could use marshal inside Log but we don't have access to printer,
  97. // we could also use the .Handle with NopOutput too but
  98. // this way is faster:
  99. var logHijacker = func(ctx *pio.Ctx) {
  100. l, ok := ctx.Value.(*Log)
  101. if !ok {
  102. ctx.Next()
  103. return
  104. }
  105. logger := l.Logger
  106. logger.mu.Lock()
  107. defer logger.mu.Unlock()
  108. w := logger.getOutput(l.Level)
  109. if f := logger.getFormatter(); f != nil {
  110. if f.Format(w, l) {
  111. ctx.Store(nil, pio.ErrHandled)
  112. return
  113. }
  114. }
  115. if l.Level != DisableLevel {
  116. if level, ok := Levels[l.Level]; ok {
  117. pio.WriteRich(w, level.Title, level.ColorCode, level.Style...)
  118. w.Write(spaceBytes)
  119. }
  120. }
  121. if t := l.FormatTime(); t != "" {
  122. fmt.Fprint(w, t)
  123. w.Write(spaceBytes)
  124. }
  125. if prefix := logger.Prefix; len(prefix) > 0 {
  126. fmt.Fprint(w, prefix)
  127. }
  128. fmt.Fprint(w, l.Message)
  129. for k, v := range l.Fields {
  130. fmt.Fprintf(w, " %s=%v", k, v)
  131. }
  132. if logger.NewLine {
  133. fmt.Fprintln(w)
  134. }
  135. ctx.Store(nil, pio.ErrHandled)
  136. }
  137. // NopOutput disables the output.
  138. var NopOutput = pio.NopOutput()
  139. // SetOutput overrides the Logger's Printer's Output with another `io.Writer`.
  140. //
  141. // Returns itself.
  142. func (l *Logger) SetOutput(w io.Writer) *Logger {
  143. l.Printer.SetOutput(w)
  144. return l
  145. }
  146. // AddOutput adds one or more `io.Writer` to the Logger's Printer.
  147. //
  148. // If one of the "writers" is not a terminal-based (i.e File)
  149. // then colors will be disabled for all outputs.
  150. //
  151. // Returns itself.
  152. func (l *Logger) AddOutput(writers ...io.Writer) *Logger {
  153. l.Printer.AddOutput(writers...)
  154. return l
  155. }
  156. // SetPrefix sets a prefix for this "l" Logger.
  157. //
  158. // The prefix is the text that is being presented
  159. // to the output right before the log's message.
  160. //
  161. // Returns itself.
  162. func (l *Logger) SetPrefix(s string) *Logger {
  163. l.mu.Lock()
  164. l.Prefix = s
  165. l.mu.Unlock()
  166. return l
  167. }
  168. // SetTimeFormat sets time format for logs,
  169. // if "s" is empty then time representation will be off.
  170. //
  171. // Returns itself.
  172. func (l *Logger) SetTimeFormat(s string) *Logger {
  173. l.mu.Lock()
  174. l.TimeFormat = s
  175. l.mu.Unlock()
  176. return l
  177. }
  178. // SetStacktraceLimit sets a stacktrace entries limit
  179. // on `Debug` level.
  180. // Zero means all number of stack entries will be logged.
  181. // Negative value disables the stacktrace field.
  182. func (l *Logger) SetStacktraceLimit(limit int) *Logger {
  183. l.mu.Lock()
  184. l.StacktraceLimit = limit
  185. l.mu.Unlock()
  186. return l
  187. }
  188. // DisableNewLine disables the new line suffix on every log function, even the `F`'s,
  189. // the caller should add "\n" to the log message manually after this call.
  190. //
  191. // Returns itself.
  192. func (l *Logger) DisableNewLine() *Logger {
  193. l.mu.Lock()
  194. l.NewLine = false
  195. l.mu.Unlock()
  196. return l
  197. }
  198. // RegisterFormatter registers a Formatter for this logger.
  199. func (l *Logger) RegisterFormatter(f Formatter) *Logger {
  200. l.mu.Lock()
  201. l.formatters[f.String()] = f
  202. l.mu.Unlock()
  203. return l
  204. }
  205. // SetFormat sets a formatter for all logger's logs.
  206. func (l *Logger) SetFormat(formatter string, opts ...interface{}) *Logger {
  207. l.mu.RLock()
  208. f, ok := l.formatters[formatter]
  209. l.mu.RUnlock()
  210. if ok {
  211. l.mu.Lock()
  212. l.formatter = f.Options(opts...)
  213. l.mu.Unlock()
  214. }
  215. return l
  216. }
  217. // SetLevelFormat changes the output format for the given "levelName".
  218. func (l *Logger) SetLevelFormat(levelName string, formatter string, opts ...interface{}) *Logger {
  219. l.mu.RLock()
  220. f, ok := l.formatters[formatter]
  221. l.mu.RUnlock()
  222. if ok {
  223. l.mu.Lock()
  224. l.LevelFormatter[ParseLevel(levelName)] = f.Options(opts...)
  225. l.mu.Unlock()
  226. }
  227. return l
  228. }
  229. func (l *Logger) getFormatter() Formatter {
  230. f, ok := l.LevelFormatter[l.Level]
  231. if !ok {
  232. f = l.formatter
  233. }
  234. if f == nil {
  235. return nil
  236. }
  237. return f
  238. }
  239. // SetLevelOutput sets a destination log output for the specific "levelName".
  240. // For multiple writers use the `io.Multiwriter` wrapper.
  241. func (l *Logger) SetLevelOutput(levelName string, w io.Writer) *Logger {
  242. l.mu.Lock()
  243. l.LevelOutput[ParseLevel(levelName)] = w
  244. l.mu.Unlock()
  245. return l
  246. }
  247. // GetLevelOutput returns the responsible writer for the given "levelName".
  248. // If not a registered writer is set for that level then it returns
  249. // the logger's default printer. It does NOT return nil.
  250. func (l *Logger) GetLevelOutput(levelName string) io.Writer {
  251. l.mu.RLock()
  252. w := l.getOutput(ParseLevel(levelName))
  253. l.mu.RUnlock()
  254. return w
  255. }
  256. func (l *Logger) getOutput(level Level) io.Writer {
  257. w, ok := l.LevelOutput[level]
  258. if !ok {
  259. w = l.Printer
  260. }
  261. return w
  262. }
  263. // SetLevel accepts a string representation of
  264. // a `Level` and returns a `Level` value based on that "levelName".
  265. //
  266. // Available level names are:
  267. // "disable"
  268. // "fatal"
  269. // "error"
  270. // "warn"
  271. // "info"
  272. // "debug"
  273. //
  274. // Alternatively you can use the exported `Level` field, i.e `Level = golog.ErrorLevel`
  275. //
  276. // Returns itself.
  277. func (l *Logger) SetLevel(levelName string) *Logger {
  278. l.mu.Lock()
  279. l.Level = ParseLevel(levelName)
  280. l.mu.Unlock()
  281. return l
  282. }
  283. func (l *Logger) print(level Level, msg string, newLine bool, fields Fields) {
  284. if l.Level >= level {
  285. // newLine passed here in order for handler to know
  286. // if this message derives from Println and Leveled functions
  287. // or by simply, Print.
  288. log := l.acquireLog(level, msg, newLine, fields)
  289. if level == DebugLevel {
  290. log.Stacktrace = GetStacktrace(l.StacktraceLimit)
  291. }
  292. // if not handled by one of the handler
  293. // then print it as usual.
  294. if !l.handled(log) {
  295. if newLine {
  296. l.Printer.Println(log)
  297. } else {
  298. l.Printer.Print(log)
  299. }
  300. }
  301. l.releaseLog(log)
  302. }
  303. // if level was fatal we don't care about the logger's level, we'll exit.
  304. if level == FatalLevel {
  305. os.Exit(1)
  306. }
  307. }
  308. // Print prints a log message without levels and colors.
  309. func (l *Logger) Print(v ...interface{}) {
  310. l.print(DisableLevel, fmt.Sprint(v...), l.NewLine, nil)
  311. }
  312. // Printf formats according to a format specifier and writes to `Printer#Output` without levels and colors.
  313. func (l *Logger) Printf(format string, args ...interface{}) {
  314. l.print(DisableLevel, fmt.Sprintf(format, args...), l.NewLine, nil)
  315. }
  316. // Println prints a log message without levels and colors.
  317. // It adds a new line at the end, it overrides the `NewLine` option.
  318. func (l *Logger) Println(v ...interface{}) {
  319. l.print(DisableLevel, fmt.Sprint(v...), true, nil)
  320. }
  321. func splitArgsFields(values []interface{}) ([]interface{}, Fields) {
  322. var (
  323. args = values[:0]
  324. fields Fields
  325. )
  326. for _, value := range values {
  327. if f, ok := value.(Fields); ok {
  328. if fields == nil {
  329. fields = make(Fields)
  330. }
  331. for k, v := range f {
  332. fields[k] = v
  333. }
  334. continue
  335. }
  336. args = append(args, value) // use it as fmt argument.
  337. }
  338. return args, fields
  339. }
  340. // Log prints a leveled log message to the output.
  341. // This method can be used to use custom log levels if needed.
  342. // It adds a new line in the end.
  343. func (l *Logger) Log(level Level, v ...interface{}) {
  344. if l.Level >= level {
  345. args, fields := splitArgsFields(v)
  346. l.print(level, fmt.Sprint(args...), l.NewLine, fields)
  347. }
  348. }
  349. // Logf prints a leveled log message to the output.
  350. // This method can be used to use custom log levels if needed.
  351. // It adds a new line in the end.
  352. func (l *Logger) Logf(level Level, format string, args ...interface{}) {
  353. if l.Level >= level {
  354. arguments, fields := splitArgsFields(args)
  355. msg := format
  356. if len(arguments) > 0 {
  357. msg = fmt.Sprintf(msg, arguments...)
  358. }
  359. l.print(level, msg, l.NewLine, fields)
  360. }
  361. }
  362. // Fatal `os.Exit(1)` exit no matter the level of the logger.
  363. // If the logger's level is fatal, error, warn, info or debug
  364. // then it will print the log message too.
  365. func (l *Logger) Fatal(v ...interface{}) {
  366. l.Log(FatalLevel, v...)
  367. }
  368. // Fatalf will `os.Exit(1)` no matter the level of the logger.
  369. // If the logger's level is fatal, error, warn, info or debug
  370. // then it will print the log message too.
  371. func (l *Logger) Fatalf(format string, args ...interface{}) {
  372. l.Logf(FatalLevel, format, args...)
  373. }
  374. // Error will print only when logger's Level is error, warn, info or debug.
  375. func (l *Logger) Error(v ...interface{}) {
  376. l.Log(ErrorLevel, v...)
  377. }
  378. // Errorf will print only when logger's Level is error, warn, info or debug.
  379. func (l *Logger) Errorf(format string, args ...interface{}) {
  380. l.Logf(ErrorLevel, format, args...)
  381. }
  382. // Warn will print when logger's Level is warn, info or debug.
  383. func (l *Logger) Warn(v ...interface{}) {
  384. l.Log(WarnLevel, v...)
  385. }
  386. // Warnf will print when logger's Level is warn, info or debug.
  387. func (l *Logger) Warnf(format string, args ...interface{}) {
  388. l.Logf(WarnLevel, format, args...)
  389. }
  390. // Warningf exactly the same as `Warnf`.
  391. // It's here for badger integration:
  392. // https://github.com/dgraph-io/badger/blob/ef28ef36b5923f12ffe3a1702bdfa6b479db6637/logger.go#L25
  393. func (l *Logger) Warningf(format string, args ...interface{}) {
  394. l.Warnf(format, args...)
  395. }
  396. // Info will print when logger's Level is info or debug.
  397. func (l *Logger) Info(v ...interface{}) {
  398. l.Log(InfoLevel, v...)
  399. }
  400. // Infof will print when logger's Level is info or debug.
  401. func (l *Logger) Infof(format string, args ...interface{}) {
  402. l.Logf(InfoLevel, format, args...)
  403. }
  404. // Debug will print when logger's Level is debug.
  405. func (l *Logger) Debug(v ...interface{}) {
  406. l.Log(DebugLevel, v...)
  407. }
  408. // Debugf will print when logger's Level is debug.
  409. func (l *Logger) Debugf(format string, args ...interface{}) {
  410. l.Logf(DebugLevel, format, args...)
  411. }
  412. // Install receives an external logger
  413. // and automatically adapts its print functions.
  414. //
  415. // Install adds a golog handler to support third-party integrations,
  416. // it can be used only once per `golog#Logger` instance.
  417. //
  418. // For example, if you want to print using a logrus
  419. // logger you can do the following:
  420. //
  421. // Install(logrus.StandardLogger())
  422. //
  423. // Or the standard log's Logger:
  424. //
  425. // import "log"
  426. // myLogger := log.New(os.Stdout, "", 0)
  427. // Install(myLogger)
  428. //
  429. // Or even the slog/log's Logger:
  430. //
  431. // import "log/slog"
  432. // myLogger := slog.New(slog.NewJSONHandler(os.Stdout, nil))
  433. // Install(myLogger) OR Install(slog.Default())
  434. //
  435. // Look `golog#Logger.Handle` for more.
  436. func (l *Logger) Install(logger any) {
  437. l.Handle(integrade(logger))
  438. }
  439. // Handle adds a log handler.
  440. //
  441. // Handlers can be used to intercept the message between a log value
  442. // and the actual print operation, it's called
  443. // when one of the print functions called.
  444. // If it's return value is true then it means that the specific
  445. // handler handled the log by itself therefore no need to
  446. // proceed with the default behavior of printing the log
  447. // to the specified logger's output.
  448. //
  449. // It stops on the handler which returns true firstly.
  450. // The `Log` value holds the level of the print operation as well.
  451. func (l *Logger) Handle(handler Handler) {
  452. l.mu.Lock()
  453. l.handlers = append(l.handlers, handler)
  454. l.mu.Unlock()
  455. }
  456. func (l *Logger) handled(value *Log) (handled bool) {
  457. for _, h := range l.handlers {
  458. if h(value) {
  459. return true
  460. }
  461. }
  462. return false
  463. }
  464. // Hijack adds a hijacker to the low-level logger's Printer.
  465. // If you need to implement such as a low-level hijacker manually,
  466. // then you have to make use of the pio library.
  467. func (l *Logger) Hijack(hijacker func(ctx *pio.Ctx)) {
  468. l.Printer.Hijack(hijacker)
  469. }
  470. // Scan scans everything from "r" and prints
  471. // its new contents to the logger's Printer's Output,
  472. // forever or until the returning "cancel" is fired, once.
  473. func (l *Logger) Scan(r io.Reader) (cancel func()) {
  474. l.once.Do(func() {
  475. // add a marshaler once
  476. // in order to handle []byte and string
  477. // as its input.
  478. // Because scan doesn't care about
  479. // logging levels (because of the io.Reader)
  480. // Note: We don't use the `pio.Text` built'n marshaler
  481. // because we want to manage time log too.
  482. l.Printer.MarshalFunc(func(v interface{}) ([]byte, error) {
  483. var line []byte
  484. if b, ok := v.([]byte); ok {
  485. line = b
  486. } else if s, ok := v.(string); ok {
  487. line = []byte(s)
  488. }
  489. if len(line) == 0 {
  490. return nil, pio.ErrMarshalNotResponsible
  491. }
  492. if l.TimeFormat != "" {
  493. formattedTime := Now().Format(l.TimeFormat)
  494. line = append([]byte(formattedTime+" "), line...)
  495. }
  496. return line, nil
  497. })
  498. })
  499. return l.Printer.Scan(r, true)
  500. }
  501. // Clone returns a copy of this "l" Logger.
  502. // This copy is returned as pointer as well.
  503. func (l *Logger) Clone() *Logger {
  504. // copy level output and format maps.
  505. formats := make(map[string]Formatter, len(l.formatters))
  506. for k, v := range l.formatters {
  507. formats[k] = v
  508. }
  509. levelFormat := make(map[Level]Formatter, len(l.LevelFormatter))
  510. for k, v := range l.LevelFormatter {
  511. levelFormat[k] = v
  512. }
  513. levelOutput := make(map[Level]io.Writer, len(l.LevelOutput))
  514. for k, v := range l.LevelOutput {
  515. levelOutput[k] = v
  516. }
  517. return &Logger{
  518. Prefix: l.Prefix,
  519. Level: l.Level,
  520. TimeFormat: l.TimeFormat,
  521. NewLine: l.NewLine,
  522. Printer: l.Printer,
  523. LevelOutput: levelOutput,
  524. formatter: l.formatter,
  525. formatters: formats,
  526. LevelFormatter: levelFormat,
  527. handlers: l.handlers,
  528. children: newLoggerMap(),
  529. mu: sync.RWMutex{},
  530. once: sync.Once{},
  531. }
  532. }
  533. // Child (creates if not exists and) returns a new child
  534. // Logger based on the current logger's fields.
  535. //
  536. // Can be used to separate logs by category.
  537. // If the "key" is string then it's used as prefix,
  538. // which is appended to the current prefix one.
  539. func (l *Logger) Child(key interface{}) *Logger {
  540. return l.children.getOrAdd(key, l)
  541. }
  542. // SetChildPrefix same as `SetPrefix` but it does NOT
  543. // override the existing, instead the given "prefix"
  544. // is appended to the current one. It's useful
  545. // to chian loggers with their own names/prefixes.
  546. // It does add the ": " in the end of "prefix" if it's missing.
  547. // It returns itself.
  548. func (l *Logger) SetChildPrefix(prefix string) *Logger {
  549. if prefix == "" {
  550. return l
  551. }
  552. // if prefix doesn't end with a whitespace, then add it here.
  553. if !strings.HasSuffix(prefix, ": ") {
  554. prefix += ": "
  555. }
  556. l.mu.Lock()
  557. if l.Prefix != "" {
  558. if !strings.HasSuffix(l.Prefix, " ") {
  559. l.Prefix += " "
  560. }
  561. }
  562. l.Prefix += prefix
  563. l.mu.Unlock()
  564. return l
  565. }
  566. // LastChild returns the last registered child Logger.
  567. func (l *Logger) LastChild() *Logger {
  568. return l.children.getLast()
  569. }
  570. type loggerMap struct {
  571. mu sync.RWMutex
  572. Items map[interface{}]*Logger
  573. itemsOrdered map[int]interface{} // registration order of logger and its key.
  574. }
  575. func newLoggerMap() *loggerMap {
  576. return &loggerMap{
  577. Items: make(map[interface{}]*Logger),
  578. itemsOrdered: make(map[int]interface{}),
  579. }
  580. }
  581. func (m *loggerMap) getByIndex(index int) (l *Logger) {
  582. m.mu.RLock()
  583. if key, ok := m.itemsOrdered[index]; ok {
  584. l = m.Items[key]
  585. }
  586. m.mu.RUnlock()
  587. return l
  588. }
  589. func (m *loggerMap) getLast() *Logger {
  590. m.mu.RLock()
  591. n := len(m.Items)
  592. m.mu.RUnlock()
  593. if n == 0 {
  594. return nil
  595. }
  596. return m.getByIndex(n - 1)
  597. }
  598. func (m *loggerMap) getOrAdd(key interface{}, parent *Logger) *Logger {
  599. m.mu.RLock()
  600. logger, ok := m.Items[key]
  601. m.mu.RUnlock()
  602. if ok {
  603. return logger
  604. }
  605. logger = parent.Clone()
  606. childPrefix := ""
  607. switch v := key.(type) {
  608. case string:
  609. childPrefix = v
  610. case fmt.Stringer:
  611. childPrefix = v.String()
  612. }
  613. logger.SetChildPrefix(childPrefix)
  614. m.mu.Lock()
  615. m.itemsOrdered[len(m.Items)] = key
  616. m.Items[key] = logger
  617. m.mu.Unlock()
  618. return logger
  619. }