logr.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  1. /*
  2. Copyright 2019 The logr 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. // This design derives from Dave Cheney's blog:
  14. // http://dave.cheney.net/2015/11/05/lets-talk-about-logging
  15. //
  16. // This is a BETA grade API. Until there is a significant 2nd implementation,
  17. // I don't really know how it will change.
  18. // Package logr defines abstract interfaces for logging. Packages can depend on
  19. // these interfaces and callers can implement logging in whatever way is
  20. // appropriate.
  21. //
  22. // Usage
  23. //
  24. // Logging is done using a Logger. Loggers can have name prefixes and named
  25. // values attached, so that all log messages logged with that Logger have some
  26. // base context associated.
  27. //
  28. // The term "key" is used to refer to the name associated with a particular
  29. // value, to disambiguate it from the general Logger name.
  30. //
  31. // For instance, suppose we're trying to reconcile the state of an object, and
  32. // we want to log that we've made some decision.
  33. //
  34. // With the traditional log package, we might write:
  35. // log.Printf("decided to set field foo to value %q for object %s/%s",
  36. // targetValue, object.Namespace, object.Name)
  37. //
  38. // With logr's structured logging, we'd write:
  39. // // elsewhere in the file, set up the logger to log with the prefix of
  40. // // "reconcilers", and the named value target-type=Foo, for extra context.
  41. // log := mainLogger.WithName("reconcilers").WithValues("target-type", "Foo")
  42. //
  43. // // later on...
  44. // log.Info("setting foo on object", "value", targetValue, "object", object)
  45. //
  46. // Depending on our logging implementation, we could then make logging decisions
  47. // based on field values (like only logging such events for objects in a certain
  48. // namespace), or copy the structured information into a structured log store.
  49. //
  50. // For logging errors, Logger has a method called Error. Suppose we wanted to
  51. // log an error while reconciling. With the traditional log package, we might
  52. // write:
  53. // log.Errorf("unable to reconcile object %s/%s: %v", object.Namespace, object.Name, err)
  54. //
  55. // With logr, we'd instead write:
  56. // // assuming the above setup for log
  57. // log.Error(err, "unable to reconcile object", "object", object)
  58. //
  59. // This functions similarly to:
  60. // log.Info("unable to reconcile object", "error", err, "object", object)
  61. //
  62. // However, it ensures that a standard key for the error value ("error") is used
  63. // across all error logging. Furthermore, certain implementations may choose to
  64. // attach additional information (such as stack traces) on calls to Error, so
  65. // it's preferred to use Error to log errors.
  66. //
  67. // Parts of a log line
  68. //
  69. // Each log message from a Logger has four types of context:
  70. // logger name, log verbosity, log message, and the named values.
  71. //
  72. // The Logger name consists of a series of name "segments" added by successive
  73. // calls to WithName. These name segments will be joined in some way by the
  74. // underlying implementation. It is strongly recommended that name segments
  75. // contain simple identifiers (letters, digits, and hyphen), and do not contain
  76. // characters that could muddle the log output or confuse the joining operation
  77. // (e.g. whitespace, commas, periods, slashes, brackets, quotes, etc).
  78. //
  79. // Log verbosity represents how little a log matters. Level zero, the default,
  80. // matters most. Increasing levels matter less and less. Try to avoid lots of
  81. // different verbosity levels, and instead provide useful keys, logger names,
  82. // and log messages for users to filter on. It's illegal to pass a log level
  83. // below zero.
  84. //
  85. // The log message consists of a constant message attached to the log line.
  86. // This should generally be a simple description of what's occurring, and should
  87. // never be a format string.
  88. //
  89. // Variable information can then be attached using named values (key/value
  90. // pairs). Keys are arbitrary strings, while values may be any Go value.
  91. //
  92. // Key Naming Conventions
  93. //
  94. // Keys are not strictly required to conform to any specification or regex, but
  95. // it is recommended that they:
  96. // * be human-readable and meaningful (not auto-generated or simple ordinals)
  97. // * be constant (not dependent on input data)
  98. // * contain only printable characters
  99. // * not contain whitespace or punctuation
  100. //
  101. // These guidelines help ensure that log data is processed properly regardless
  102. // of the log implementation. For example, log implementations will try to
  103. // output JSON data or will store data for later database (e.g. SQL) queries.
  104. //
  105. // While users are generally free to use key names of their choice, it's
  106. // generally best to avoid using the following keys, as they're frequently used
  107. // by implementations:
  108. //
  109. // * `"caller"`: the calling information (file/line) of a particular log line.
  110. // * `"error"`: the underlying error value in the `Error` method.
  111. // * `"level"`: the log level.
  112. // * `"logger"`: the name of the associated logger.
  113. // * `"msg"`: the log message.
  114. // * `"stacktrace"`: the stack trace associated with a particular log line or
  115. // error (often from the `Error` message).
  116. // * `"ts"`: the timestamp for a log line.
  117. //
  118. // Implementations are encouraged to make use of these keys to represent the
  119. // above concepts, when necessary (for example, in a pure-JSON output form, it
  120. // would be necessary to represent at least message and timestamp as ordinary
  121. // named values).
  122. //
  123. // Implementations may choose to give callers access to the underlying
  124. // logging implementation. The recommended pattern for this is:
  125. // // Underlier exposes access to the underlying logging implementation.
  126. // // Since callers only have a logr.Logger, they have to know which
  127. // // implementation is in use, so this interface is less of an abstraction
  128. // // and more of way to test type conversion.
  129. // type Underlier interface {
  130. // GetUnderlying() <underlying-type>
  131. // }
  132. package logr
  133. import (
  134. "context"
  135. )
  136. // TODO: consider adding back in format strings if they're really needed
  137. // TODO: consider other bits of zap/zapcore functionality like ObjectMarshaller (for arbitrary objects)
  138. // TODO: consider other bits of glog functionality like Flush, OutputStats
  139. // Logger represents the ability to log messages, both errors and not.
  140. type Logger interface {
  141. // Enabled tests whether this Logger is enabled. For example, commandline
  142. // flags might be used to set the logging verbosity and disable some info
  143. // logs.
  144. Enabled() bool
  145. // Info logs a non-error message with the given key/value pairs as context.
  146. //
  147. // The msg argument should be used to add some constant description to
  148. // the log line. The key/value pairs can then be used to add additional
  149. // variable information. The key/value pairs should alternate string
  150. // keys and arbitrary values.
  151. Info(msg string, keysAndValues ...interface{})
  152. // Error logs an error, with the given message and key/value pairs as context.
  153. // It functions similarly to calling Info with the "error" named value, but may
  154. // have unique behavior, and should be preferred for logging errors (see the
  155. // package documentations for more information).
  156. //
  157. // The msg field should be used to add context to any underlying error,
  158. // while the err field should be used to attach the actual error that
  159. // triggered this log line, if present.
  160. Error(err error, msg string, keysAndValues ...interface{})
  161. // V returns an Logger value for a specific verbosity level, relative to
  162. // this Logger. In other words, V values are additive. V higher verbosity
  163. // level means a log message is less important. It's illegal to pass a log
  164. // level less than zero.
  165. V(level int) Logger
  166. // WithValues adds some key-value pairs of context to a logger.
  167. // See Info for documentation on how key/value pairs work.
  168. WithValues(keysAndValues ...interface{}) Logger
  169. // WithName adds a new element to the logger's name.
  170. // Successive calls with WithName continue to append
  171. // suffixes to the logger's name. It's strongly recommended
  172. // that name segments contain only letters, digits, and hyphens
  173. // (see the package documentation for more information).
  174. WithName(name string) Logger
  175. }
  176. // InfoLogger provides compatibility with code that relies on the v0.1.0
  177. // interface.
  178. //
  179. // Deprecated: InfoLogger is an artifact of early versions of this API. New
  180. // users should never use it and existing users should use Logger instead. This
  181. // will be removed in a future release.
  182. type InfoLogger = Logger
  183. type contextKey struct{}
  184. // FromContext returns a Logger constructed from ctx or nil if no
  185. // logger details are found.
  186. func FromContext(ctx context.Context) Logger {
  187. if v, ok := ctx.Value(contextKey{}).(Logger); ok {
  188. return v
  189. }
  190. return nil
  191. }
  192. // FromContextOrDiscard returns a Logger constructed from ctx or a Logger
  193. // that discards all messages if no logger details are found.
  194. func FromContextOrDiscard(ctx context.Context) Logger {
  195. if v, ok := ctx.Value(contextKey{}).(Logger); ok {
  196. return v
  197. }
  198. return Discard()
  199. }
  200. // NewContext returns a new context derived from ctx that embeds the Logger.
  201. func NewContext(ctx context.Context, l Logger) context.Context {
  202. return context.WithValue(ctx, contextKey{}, l)
  203. }
  204. // CallDepthLogger represents a Logger that knows how to climb the call stack
  205. // to identify the original call site and can offset the depth by a specified
  206. // number of frames. This is useful for users who have helper functions
  207. // between the "real" call site and the actual calls to Logger methods.
  208. // Implementations that log information about the call site (such as file,
  209. // function, or line) would otherwise log information about the intermediate
  210. // helper functions.
  211. //
  212. // This is an optional interface and implementations are not required to
  213. // support it.
  214. type CallDepthLogger interface {
  215. Logger
  216. // WithCallDepth returns a Logger that will offset the call stack by the
  217. // specified number of frames when logging call site information. If depth
  218. // is 0 the attribution should be to the direct caller of this method. If
  219. // depth is 1 the attribution should skip 1 call frame, and so on.
  220. // Successive calls to this are additive.
  221. WithCallDepth(depth int) Logger
  222. }
  223. // WithCallDepth returns a Logger that will offset the call stack by the
  224. // specified number of frames when logging call site information, if possible.
  225. // This is useful for users who have helper functions between the "real" call
  226. // site and the actual calls to Logger methods. If depth is 0 the attribution
  227. // should be to the direct caller of this function. If depth is 1 the
  228. // attribution should skip 1 call frame, and so on. Successive calls to this
  229. // are additive.
  230. //
  231. // If the underlying log implementation supports the CallDepthLogger interface,
  232. // the WithCallDepth method will be called and the result returned. If the
  233. // implementation does not support CallDepthLogger, the original Logger will be
  234. // returned.
  235. //
  236. // Callers which care about whether this was supported or not should test for
  237. // CallDepthLogger support themselves.
  238. func WithCallDepth(logger Logger, depth int) Logger {
  239. if decorator, ok := logger.(CallDepthLogger); ok {
  240. return decorator.WithCallDepth(depth)
  241. }
  242. return logger
  243. }