event.go 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  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. timeTakenField = "time_taken_ms"
  15. exitCodeField = "exit_code"
  16. timestampFormat = "2006-01-02T15:04:05.999Z07:00"
  17. )
  18. // Event represents a single log event
  19. type Event struct {
  20. Timestamp string `json:"time"`
  21. Level Level `json:"level"`
  22. Message string `json:"message"`
  23. time time.Time
  24. contexters []Contexter
  25. fields Context
  26. }
  27. // newEvent creates a new log event
  28. //
  29. // We delay allocations and processing for efficiency, because most log events
  30. // are never actually rendered, so we don't format the time, or allocate a fields map.
  31. func newEvent() *Event {
  32. return &Event{
  33. time: time.Now(),
  34. }
  35. }
  36. // Fatal logs the event as FATAL, and exits the program with exit code 1
  37. func (e *Event) Fatal(message string, v ...any) {
  38. e.Field(exitCodeField, 1).maybeLog(FatalLevel, message, v...)
  39. fmt.Fprintf(os.Stderr, message+"\n", v...) // Always output error to stderr
  40. os.Exit(1)
  41. }
  42. // Error logs the event with log level error
  43. func (e *Event) Error(message string, v ...any) {
  44. e.maybeLog(ErrorLevel, message, v...)
  45. }
  46. // Warn logs the event with log level warn
  47. func (e *Event) Warn(message string, v ...any) {
  48. e.maybeLog(WarnLevel, message, v...)
  49. }
  50. // Info logs the event with log level info
  51. func (e *Event) Info(message string, v ...any) {
  52. e.maybeLog(InfoLevel, message, v...)
  53. }
  54. // Debug logs the event with log level debug
  55. func (e *Event) Debug(message string, v ...any) {
  56. e.maybeLog(DebugLevel, message, v...)
  57. }
  58. // Trace logs the event with log level trace
  59. func (e *Event) Trace(message string, v ...any) {
  60. e.maybeLog(TraceLevel, message, v...)
  61. }
  62. // Tag adds a "tag" field to the log event
  63. func (e *Event) Tag(tag string) *Event {
  64. return e.Field(tagField, tag)
  65. }
  66. // Time sets the time field
  67. func (e *Event) Time(t time.Time) *Event {
  68. e.time = t
  69. return e
  70. }
  71. // Timing runs f and records the time if took to execute it in "time_taken_ms"
  72. func (e *Event) Timing(f func()) *Event {
  73. start := time.Now()
  74. f()
  75. return e.Field(timeTakenField, time.Since(start).Milliseconds())
  76. }
  77. // Err adds an "error" field to the log event
  78. func (e *Event) Err(err error) *Event {
  79. if err == nil {
  80. return e
  81. } else if c, ok := err.(Contexter); ok {
  82. return e.With(c)
  83. }
  84. return e.Field(errorField, err.Error())
  85. }
  86. // Field adds a custom field and value to the log event
  87. func (e *Event) Field(key string, value any) *Event {
  88. if e.fields == nil {
  89. e.fields = make(Context)
  90. }
  91. e.fields[key] = value
  92. return e
  93. }
  94. // Fields adds a map of fields to the log event
  95. func (e *Event) Fields(fields Context) *Event {
  96. if e.fields == nil {
  97. e.fields = make(Context)
  98. }
  99. for k, v := range fields {
  100. e.fields[k] = v
  101. }
  102. return e
  103. }
  104. // With adds the fields of the given Contexter structs to the log event by calling their With method
  105. func (e *Event) With(contexts ...Contexter) *Event {
  106. if e.contexters == nil {
  107. e.contexters = contexts
  108. } else {
  109. e.contexters = append(e.contexters, contexts...)
  110. }
  111. return e
  112. }
  113. // maybeLog logs the event to the defined output. The event is only logged, if
  114. // either the global log level is >= l, or if the log level in one of the overrides matches
  115. // the level.
  116. //
  117. // If no overrides are defined (default), the Contexter array is not applied unless the event
  118. // is actually logged. If overrides are defined, then Contexters have to be applied in any case
  119. // to determine if they match. This is super complicated, but required for efficiency.
  120. func (e *Event) maybeLog(l Level, message string, v ...any) {
  121. appliedContexters := e.maybeApplyContexters()
  122. if !e.shouldLog(l) {
  123. return
  124. }
  125. e.Message = fmt.Sprintf(message, v...)
  126. e.Level = l
  127. e.Timestamp = e.time.Format(timestampFormat)
  128. if !appliedContexters {
  129. e.applyContexters()
  130. }
  131. if CurrentFormat() == JSONFormat {
  132. log.Println(e.JSON())
  133. } else {
  134. log.Println(e.String())
  135. }
  136. }
  137. // Loggable returns true if the given log level is lower or equal to the current log level
  138. func (e *Event) Loggable(l Level) bool {
  139. return e.globalLevelWithOverride() <= l
  140. }
  141. // IsTrace returns true if the current log level is TraceLevel
  142. func (e *Event) IsTrace() bool {
  143. return e.Loggable(TraceLevel)
  144. }
  145. // IsDebug returns true if the current log level is DebugLevel or below
  146. func (e *Event) IsDebug() bool {
  147. return e.Loggable(DebugLevel)
  148. }
  149. // JSON returns the event as a JSON representation
  150. func (e *Event) JSON() string {
  151. b, _ := json.Marshal(e)
  152. s := string(b)
  153. if len(e.fields) > 0 {
  154. b, _ := json.Marshal(e.fields)
  155. s = fmt.Sprintf("{%s,%s}", s[1:len(s)-1], string(b[1:len(b)-1]))
  156. }
  157. return s
  158. }
  159. // String returns the event as a string
  160. func (e *Event) String() string {
  161. if len(e.fields) == 0 {
  162. return fmt.Sprintf("%s %s", e.Level.String(), e.Message)
  163. }
  164. fields := make([]string, 0)
  165. for k, v := range e.fields {
  166. fields = append(fields, fmt.Sprintf("%s=%v", k, v))
  167. }
  168. sort.Strings(fields)
  169. return fmt.Sprintf("%s %s (%s)", e.Level.String(), e.Message, strings.Join(fields, ", "))
  170. }
  171. func (e *Event) shouldLog(l Level) bool {
  172. return e.globalLevelWithOverride() <= l
  173. }
  174. func (e *Event) globalLevelWithOverride() Level {
  175. mu.RLock()
  176. l, ov := level, overrides
  177. mu.RUnlock()
  178. if e.fields == nil {
  179. return l
  180. }
  181. for field, override := range ov {
  182. value, exists := e.fields[field]
  183. if exists {
  184. if override.value == "" || override.value == value || override.value == fmt.Sprintf("%v", value) {
  185. return override.level
  186. }
  187. }
  188. }
  189. return l
  190. }
  191. func (e *Event) maybeApplyContexters() bool {
  192. mu.RLock()
  193. hasOverrides := len(overrides) > 0
  194. mu.RUnlock()
  195. if hasOverrides {
  196. e.applyContexters()
  197. }
  198. return hasOverrides // = applied
  199. }
  200. func (e *Event) applyContexters() {
  201. for _, c := range e.contexters {
  202. e.Fields(c.Context())
  203. }
  204. }