logger.go 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. package logger
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "io"
  6. "log"
  7. "os"
  8. )
  9. // Logger matches newrelic.Logger to allow implementations to be passed to
  10. // internal packages.
  11. type Logger interface {
  12. Error(msg string, context map[string]interface{})
  13. Warn(msg string, context map[string]interface{})
  14. Info(msg string, context map[string]interface{})
  15. Debug(msg string, context map[string]interface{})
  16. DebugEnabled() bool
  17. }
  18. // ShimLogger implements Logger and does nothing.
  19. type ShimLogger struct {
  20. // IsDebugEnabled is useful as it allows DebugEnabled code paths to be
  21. // tested.
  22. IsDebugEnabled bool
  23. }
  24. // Error allows ShimLogger to implement Logger.
  25. func (s ShimLogger) Error(string, map[string]interface{}) {}
  26. // Warn allows ShimLogger to implement Logger.
  27. func (s ShimLogger) Warn(string, map[string]interface{}) {}
  28. // Info allows ShimLogger to implement Logger.
  29. func (s ShimLogger) Info(string, map[string]interface{}) {}
  30. // Debug allows ShimLogger to implement Logger.
  31. func (s ShimLogger) Debug(string, map[string]interface{}) {}
  32. // DebugEnabled allows ShimLogger to implement Logger.
  33. func (s ShimLogger) DebugEnabled() bool { return s.IsDebugEnabled }
  34. type logFile struct {
  35. l *log.Logger
  36. doDebug bool
  37. }
  38. // New creates a basic Logger.
  39. func New(w io.Writer, doDebug bool) Logger {
  40. return &logFile{
  41. l: log.New(w, logPid, logFlags),
  42. doDebug: doDebug,
  43. }
  44. }
  45. const logFlags = log.Ldate | log.Ltime | log.Lmicroseconds
  46. var (
  47. logPid = fmt.Sprintf("(%d) ", os.Getpid())
  48. )
  49. func (f *logFile) fire(level, msg string, ctx map[string]interface{}) {
  50. js, err := json.Marshal(struct {
  51. Level string `json:"level"`
  52. Event string `json:"msg"`
  53. Context map[string]interface{} `json:"context"`
  54. }{
  55. level,
  56. msg,
  57. ctx,
  58. })
  59. if nil == err {
  60. f.l.Print(string(js))
  61. } else {
  62. f.l.Printf("unable to marshal log entry: %v", err)
  63. }
  64. }
  65. func (f *logFile) Error(msg string, ctx map[string]interface{}) {
  66. f.fire("error", msg, ctx)
  67. }
  68. func (f *logFile) Warn(msg string, ctx map[string]interface{}) {
  69. f.fire("warn", msg, ctx)
  70. }
  71. func (f *logFile) Info(msg string, ctx map[string]interface{}) {
  72. f.fire("info", msg, ctx)
  73. }
  74. func (f *logFile) Debug(msg string, ctx map[string]interface{}) {
  75. if f.doDebug {
  76. f.fire("debug", msg, ctx)
  77. }
  78. }
  79. func (f *logFile) DebugEnabled() bool { return f.doDebug }