event.go 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. package log
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "log"
  6. "os"
  7. "sort"
  8. "strings"
  9. "time"
  10. )
  11. const (
  12. tagField = "tag"
  13. errorField = "error"
  14. timestampFormat = "2006-01-02T15:04:05.999Z07:00"
  15. )
  16. // Event represents a single log event
  17. type Event struct {
  18. Timestamp string `json:"time"`
  19. Level Level `json:"level"`
  20. Message string `json:"message"`
  21. fields Context
  22. }
  23. // newEvent creates a new log event
  24. func newEvent() *Event {
  25. now := time.Now()
  26. return &Event{
  27. Timestamp: now.Format(timestampFormat),
  28. fields: make(Context),
  29. }
  30. }
  31. // Fatal logs the event as FATAL, and exits the program with exit code 1
  32. func (e *Event) Fatal(message string, v ...any) {
  33. e.Field("exit_code", 1).Log(FatalLevel, message, v...)
  34. fmt.Fprintf(os.Stderr, message+"\n", v...) // Always output error to stderr
  35. os.Exit(1)
  36. }
  37. // Error logs the event with log level error
  38. func (e *Event) Error(message string, v ...any) {
  39. e.Log(ErrorLevel, message, v...)
  40. }
  41. // Warn logs the event with log level warn
  42. func (e *Event) Warn(message string, v ...any) {
  43. e.Log(WarnLevel, message, v...)
  44. }
  45. // Info logs the event with log level info
  46. func (e *Event) Info(message string, v ...any) {
  47. e.Log(InfoLevel, message, v...)
  48. }
  49. // Debug logs the event with log level debug
  50. func (e *Event) Debug(message string, v ...any) {
  51. e.Log(DebugLevel, message, v...)
  52. }
  53. // Trace logs the event with log level trace
  54. func (e *Event) Trace(message string, v ...any) {
  55. e.Log(TraceLevel, message, v...)
  56. }
  57. // Tag adds a "tag" field to the log event
  58. func (e *Event) Tag(tag string) *Event {
  59. e.fields[tagField] = tag
  60. return e
  61. }
  62. // Time sets the time field
  63. func (e *Event) Time(t time.Time) *Event {
  64. e.Timestamp = t.Format(timestampFormat)
  65. return e
  66. }
  67. // Err adds an "error" field to the log event
  68. func (e *Event) Err(err error) *Event {
  69. if c, ok := err.(Contexter); ok {
  70. e.Fields(c.Context())
  71. } else {
  72. e.fields[errorField] = err.Error()
  73. }
  74. return e
  75. }
  76. // Field adds a custom field and value to the log event
  77. func (e *Event) Field(key string, value any) *Event {
  78. e.fields[key] = value
  79. return e
  80. }
  81. // Fields adds a map of fields to the log event
  82. func (e *Event) Fields(fields Context) *Event {
  83. for k, v := range fields {
  84. e.fields[k] = v
  85. }
  86. return e
  87. }
  88. // With adds the fields of the given Contexter structs to the log event by calling their With method
  89. func (e *Event) With(contexts ...Contexter) *Event {
  90. for _, c := range contexts {
  91. e.Fields(c.Context())
  92. }
  93. return e
  94. }
  95. // Log logs a message with the given log level
  96. func (e *Event) Log(l Level, message string, v ...any) {
  97. e.Message = fmt.Sprintf(message, v...)
  98. e.Level = l
  99. if e.shouldPrint() {
  100. if CurrentFormat() == JSONFormat {
  101. log.Println(e.JSON())
  102. } else {
  103. log.Println(e.String())
  104. }
  105. }
  106. }
  107. // Loggable returns true if the given log level is lower or equal to the current log level
  108. func (e *Event) Loggable(l Level) bool {
  109. return e.globalLevelWithOverride() <= l
  110. }
  111. // IsTrace returns true if the current log level is TraceLevel
  112. func (e *Event) IsTrace() bool {
  113. return e.Loggable(TraceLevel)
  114. }
  115. // IsDebug returns true if the current log level is DebugLevel or below
  116. func (e *Event) IsDebug() bool {
  117. return e.Loggable(DebugLevel)
  118. }
  119. // JSON returns the event as a JSON representation
  120. func (e *Event) JSON() string {
  121. b, _ := json.Marshal(e)
  122. s := string(b)
  123. if len(e.fields) > 0 {
  124. b, _ := json.Marshal(e.fields)
  125. s = fmt.Sprintf("{%s,%s}", s[1:len(s)-1], string(b[1:len(b)-1]))
  126. }
  127. return s
  128. }
  129. // String returns the event as a string
  130. func (e *Event) String() string {
  131. if len(e.fields) == 0 {
  132. return fmt.Sprintf("%s %s", e.Level.String(), e.Message)
  133. }
  134. fields := make([]string, 0)
  135. for k, v := range e.fields {
  136. fields = append(fields, fmt.Sprintf("%s=%v", k, v))
  137. }
  138. sort.Strings(fields)
  139. return fmt.Sprintf("%s %s (%s)", e.Level.String(), e.Message, strings.Join(fields, ", "))
  140. }
  141. func (e *Event) shouldPrint() bool {
  142. return e.globalLevelWithOverride() <= e.Level
  143. }
  144. func (e *Event) globalLevelWithOverride() Level {
  145. mu.Lock()
  146. l, ov := level, overrides
  147. mu.Unlock()
  148. for field, override := range ov {
  149. value, exists := e.fields[field]
  150. if exists && value == override.value {
  151. return override.level
  152. }
  153. }
  154. return l
  155. }