Matteo Scandolo | a428586 | 2020-12-01 18:10:10 -0800 | [diff] [blame] | 1 | /* |
| 2 | Copyright 2019 The logr Authors. |
| 3 | |
| 4 | Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | you may not use this file except in compliance with the License. |
| 6 | You may obtain a copy of the License at |
| 7 | |
| 8 | http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | |
| 10 | Unless required by applicable law or agreed to in writing, software |
| 11 | distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | See the License for the specific language governing permissions and |
| 14 | limitations under the License. |
| 15 | */ |
| 16 | |
| 17 | // Package logr defines abstract interfaces for logging. Packages can depend on |
| 18 | // these interfaces and callers can implement logging in whatever way is |
| 19 | // appropriate. |
| 20 | // |
| 21 | // This design derives from Dave Cheney's blog: |
| 22 | // http://dave.cheney.net/2015/11/05/lets-talk-about-logging |
| 23 | // |
| 24 | // This is a BETA grade API. Until there is a significant 2nd implementation, |
| 25 | // I don't really know how it will change. |
| 26 | // |
| 27 | // The logging specifically makes it non-trivial to use format strings, to encourage |
| 28 | // attaching structured information instead of unstructured format strings. |
| 29 | // |
| 30 | // Usage |
| 31 | // |
| 32 | // Logging is done using a Logger. Loggers can have name prefixes and named |
| 33 | // values attached, so that all log messages logged with that Logger have some |
| 34 | // base context associated. |
| 35 | // |
| 36 | // The term "key" is used to refer to the name associated with a particular |
| 37 | // value, to disambiguate it from the general Logger name. |
| 38 | // |
| 39 | // For instance, suppose we're trying to reconcile the state of an object, and |
| 40 | // we want to log that we've made some decision. |
| 41 | // |
| 42 | // With the traditional log package, we might write: |
| 43 | // log.Printf( |
| 44 | // "decided to set field foo to value %q for object %s/%s", |
| 45 | // targetValue, object.Namespace, object.Name) |
| 46 | // |
| 47 | // With logr's structured logging, we'd write: |
| 48 | // // elsewhere in the file, set up the logger to log with the prefix of "reconcilers", |
| 49 | // // and the named value target-type=Foo, for extra context. |
| 50 | // log := mainLogger.WithName("reconcilers").WithValues("target-type", "Foo") |
| 51 | // |
| 52 | // // later on... |
| 53 | // log.Info("setting field foo on object", "value", targetValue, "object", object) |
| 54 | // |
| 55 | // Depending on our logging implementation, we could then make logging decisions |
| 56 | // based on field values (like only logging such events for objects in a certain |
| 57 | // namespace), or copy the structured information into a structured log store. |
| 58 | // |
| 59 | // For logging errors, Logger has a method called Error. Suppose we wanted to |
| 60 | // log an error while reconciling. With the traditional log package, we might |
| 61 | // write: |
| 62 | // log.Errorf("unable to reconcile object %s/%s: %v", object.Namespace, object.Name, err) |
| 63 | // |
| 64 | // With logr, we'd instead write: |
| 65 | // // assuming the above setup for log |
| 66 | // log.Error(err, "unable to reconcile object", "object", object) |
| 67 | // |
| 68 | // This functions similarly to: |
| 69 | // log.Info("unable to reconcile object", "error", err, "object", object) |
| 70 | // |
| 71 | // However, it ensures that a standard key for the error value ("error") is used |
| 72 | // across all error logging. Furthermore, certain implementations may choose to |
| 73 | // attach additional information (such as stack traces) on calls to Error, so |
| 74 | // it's preferred to use Error to log errors. |
| 75 | // |
| 76 | // Parts of a log line |
| 77 | // |
| 78 | // Each log message from a Logger has four types of context: |
| 79 | // logger name, log verbosity, log message, and the named values. |
| 80 | // |
| 81 | // The Logger name constists of a series of name "segments" added by successive |
| 82 | // calls to WithName. These name segments will be joined in some way by the |
| 83 | // underlying implementation. It is strongly reccomended that name segements |
| 84 | // contain simple identifiers (letters, digits, and hyphen), and do not contain |
| 85 | // characters that could muddle the log output or confuse the joining operation |
| 86 | // (e.g. whitespace, commas, periods, slashes, brackets, quotes, etc). |
| 87 | // |
| 88 | // Log verbosity represents how little a log matters. Level zero, the default, |
| 89 | // matters most. Increasing levels matter less and less. Try to avoid lots of |
| 90 | // different verbosity levels, and instead provide useful keys, logger names, |
| 91 | // and log messages for users to filter on. It's illegal to pass a log level |
| 92 | // below zero. |
| 93 | // |
| 94 | // The log message consists of a constant message attached to the the log line. |
| 95 | // This should generally be a simple description of what's occuring, and should |
| 96 | // never be a format string. |
| 97 | // |
| 98 | // Variable information can then be attached using named values (key/value |
| 99 | // pairs). Keys are arbitrary strings, while values may be any Go value. |
| 100 | // |
| 101 | // Key Naming Conventions |
| 102 | // |
| 103 | // Keys are not strictly required to conform to any specification or regex, but |
| 104 | // it is recommended that they: |
| 105 | // * be human-readable and meaningful (not auto-generated or simple ordinals) |
| 106 | // * be constant (not dependent on input data) |
| 107 | // * contain only printable characters |
| 108 | // * not contain whitespace or punctuation |
| 109 | // |
| 110 | // These guidelines help ensure that log data is processed properly regardless |
| 111 | // of the log implementation. For example, log implementations will try to |
| 112 | // output JSON data or will store data for later database (e.g. SQL) queries. |
| 113 | // |
| 114 | // While users are generally free to use key names of their choice, it's |
| 115 | // generally best to avoid using the following keys, as they're frequently used |
| 116 | // by implementations: |
| 117 | // |
| 118 | // - `"caller"`: the calling information (file/line) of a particular log line. |
| 119 | // - `"error"`: the underlying error value in the `Error` method. |
| 120 | // - `"level"`: the log level. |
| 121 | // - `"logger"`: the name of the associated logger. |
| 122 | // - `"msg"`: the log message. |
| 123 | // - `"stacktrace"`: the stack trace associated with a particular log line or |
| 124 | // error (often from the `Error` message). |
| 125 | // - `"ts"`: the timestamp for a log line. |
| 126 | // |
| 127 | // Implementations are encouraged to make use of these keys to represent the |
| 128 | // above concepts, when neccessary (for example, in a pure-JSON output form, it |
| 129 | // would be necessary to represent at least message and timestamp as ordinary |
| 130 | // named values). |
| 131 | package logr |
| 132 | |
| 133 | // TODO: consider adding back in format strings if they're really needed |
| 134 | // TODO: consider other bits of zap/zapcore functionality like ObjectMarshaller (for arbitrary objects) |
| 135 | // TODO: consider other bits of glog functionality like Flush, InfoDepth, OutputStats |
| 136 | |
| 137 | // Logger represents the ability to log messages, both errors and not. |
| 138 | type Logger interface { |
| 139 | // Enabled tests whether this Logger is enabled. For example, commandline |
| 140 | // flags might be used to set the logging verbosity and disable some info |
| 141 | // logs. |
| 142 | Enabled() bool |
| 143 | |
| 144 | // Info logs a non-error message with the given key/value pairs as context. |
| 145 | // |
| 146 | // The msg argument should be used to add some constant description to |
| 147 | // the log line. The key/value pairs can then be used to add additional |
| 148 | // variable information. The key/value pairs should alternate string |
| 149 | // keys and arbitrary values. |
| 150 | Info(msg string, keysAndValues ...interface{}) |
| 151 | |
| 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 | |
| 162 | // V returns an Logger value for a specific verbosity level, relative to |
| 163 | // this Logger. In other words, V values are additive. V higher verbosity |
| 164 | // level means a log message is less important. It's illegal to pass a log |
| 165 | // level less than zero. |
| 166 | V(level int) Logger |
| 167 | |
| 168 | // WithValues adds some key-value pairs of context to a logger. |
| 169 | // See Info for documentation on how key/value pairs work. |
| 170 | WithValues(keysAndValues ...interface{}) Logger |
| 171 | |
| 172 | // WithName adds a new element to the logger's name. |
| 173 | // Successive calls with WithName continue to append |
| 174 | // suffixes to the logger's name. It's strongly reccomended |
| 175 | // that name segments contain only letters, digits, and hyphens |
| 176 | // (see the package documentation for more information). |
| 177 | WithName(name string) Logger |
| 178 | } |