context.go 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. /*
  2. Copyright The containerd Authors.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. // Package log provides types and functions related to logging, passing
  14. // loggers through a context, and attaching context to the logger.
  15. //
  16. // # Transitional types
  17. //
  18. // This package contains various types that are aliases for types in [logrus].
  19. // These aliases are intended for transitioning away from hard-coding logrus
  20. // as logging implementation. Consumers of this package are encouraged to use
  21. // the type-aliases from this package instead of directly using their logrus
  22. // equivalent.
  23. //
  24. // The intent is to replace these aliases with locally defined types and
  25. // interfaces once all consumers are no longer directly importing logrus
  26. // types.
  27. //
  28. // IMPORTANT: due to the transitional purpose of this package, it is not
  29. // guaranteed for the full logrus API to be provided in the future. As
  30. // outlined, these aliases are provided as a step to transition away from
  31. // a specific implementation which, as a result, exposes the full logrus API.
  32. // While no decisions have been made on the ultimate design and interface
  33. // provided by this package, we do not expect carrying "less common" features.
  34. package log
  35. import (
  36. "context"
  37. "fmt"
  38. "github.com/sirupsen/logrus"
  39. )
  40. // G is a shorthand for [GetLogger].
  41. //
  42. // We may want to define this locally to a package to get package tagged log
  43. // messages.
  44. var G = GetLogger
  45. // L is an alias for the standard logger.
  46. var L = &Entry{
  47. Logger: logrus.StandardLogger(),
  48. // Default is three fields plus a little extra room.
  49. Data: make(Fields, 6),
  50. }
  51. type loggerKey struct{}
  52. // Fields type to pass to "WithFields".
  53. type Fields = map[string]any
  54. // Entry is a logging entry. It contains all the fields passed with
  55. // [Entry.WithFields]. It's finally logged when Trace, Debug, Info, Warn,
  56. // Error, Fatal or Panic is called on it. These objects can be reused and
  57. // passed around as much as you wish to avoid field duplication.
  58. //
  59. // Entry is a transitional type, and currently an alias for [logrus.Entry].
  60. type Entry = logrus.Entry
  61. // RFC3339NanoFixed is [time.RFC3339Nano] with nanoseconds padded using
  62. // zeros to ensure the formatted time is always the same number of
  63. // characters.
  64. const RFC3339NanoFixed = "2006-01-02T15:04:05.000000000Z07:00"
  65. // Level is a logging level.
  66. type Level = logrus.Level
  67. // Supported log levels.
  68. const (
  69. // TraceLevel level. Designates finer-grained informational events
  70. // than [DebugLevel].
  71. TraceLevel Level = logrus.TraceLevel
  72. // DebugLevel level. Usually only enabled when debugging. Very verbose
  73. // logging.
  74. DebugLevel Level = logrus.DebugLevel
  75. // InfoLevel level. General operational entries about what's going on
  76. // inside the application.
  77. InfoLevel Level = logrus.InfoLevel
  78. // WarnLevel level. Non-critical entries that deserve eyes.
  79. WarnLevel Level = logrus.WarnLevel
  80. // ErrorLevel level. Logs errors that should definitely be noted.
  81. // Commonly used for hooks to send errors to an error tracking service.
  82. ErrorLevel Level = logrus.ErrorLevel
  83. // FatalLevel level. Logs and then calls "logger.Exit(1)". It exits
  84. // even if the logging level is set to Panic.
  85. FatalLevel Level = logrus.FatalLevel
  86. // PanicLevel level. This is the highest level of severity. Logs and
  87. // then calls panic with the message passed to Debug, Info, ...
  88. PanicLevel Level = logrus.PanicLevel
  89. )
  90. // SetLevel sets log level globally. It returns an error if the given
  91. // level is not supported.
  92. //
  93. // level can be one of:
  94. //
  95. // - "trace" ([TraceLevel])
  96. // - "debug" ([DebugLevel])
  97. // - "info" ([InfoLevel])
  98. // - "warn" ([WarnLevel])
  99. // - "error" ([ErrorLevel])
  100. // - "fatal" ([FatalLevel])
  101. // - "panic" ([PanicLevel])
  102. func SetLevel(level string) error {
  103. lvl, err := logrus.ParseLevel(level)
  104. if err != nil {
  105. return err
  106. }
  107. L.Logger.SetLevel(lvl)
  108. return nil
  109. }
  110. // GetLevel returns the current log level.
  111. func GetLevel() Level {
  112. return L.Logger.GetLevel()
  113. }
  114. // OutputFormat specifies a log output format.
  115. type OutputFormat string
  116. // Supported log output formats.
  117. const (
  118. // TextFormat represents the text logging format.
  119. TextFormat OutputFormat = "text"
  120. // JSONFormat represents the JSON logging format.
  121. JSONFormat OutputFormat = "json"
  122. )
  123. // SetFormat sets the log output format ([TextFormat] or [JSONFormat]).
  124. func SetFormat(format OutputFormat) error {
  125. switch format {
  126. case TextFormat:
  127. L.Logger.SetFormatter(&logrus.TextFormatter{
  128. TimestampFormat: RFC3339NanoFixed,
  129. FullTimestamp: true,
  130. })
  131. return nil
  132. case JSONFormat:
  133. L.Logger.SetFormatter(&logrus.JSONFormatter{
  134. TimestampFormat: RFC3339NanoFixed,
  135. })
  136. return nil
  137. default:
  138. return fmt.Errorf("unknown log format: %s", format)
  139. }
  140. }
  141. // WithLogger returns a new context with the provided logger. Use in
  142. // combination with logger.WithField(s) for great effect.
  143. func WithLogger(ctx context.Context, logger *Entry) context.Context {
  144. return context.WithValue(ctx, loggerKey{}, logger.WithContext(ctx))
  145. }
  146. // GetLogger retrieves the current logger from the context. If no logger is
  147. // available, the default logger is returned.
  148. func GetLogger(ctx context.Context) *Entry {
  149. if logger := ctx.Value(loggerKey{}); logger != nil {
  150. return logger.(*Entry)
  151. }
  152. return L.WithContext(ctx)
  153. }