github.com/facebookincubator/go-belt@v0.0.0-20230703220935-39cd348f1a38/tool/logger/types/logger.go (about) 1 // Copyright 2022 Meta Platforms, Inc. and affiliates. 2 // 3 // Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 4 // 5 // 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 6 // 7 // 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 8 // 9 // 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 10 // 11 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 12 13 // Copyright (c) Facebook, Inc. and its affiliates. 14 // 15 // This source code is licensed under the MIT license found in the 16 // LICENSE file in the root directory of this source tree. 17 18 // Package types of logger unifies different types of loggers into 19 // interfaces Logger. For example it allows to upgrade simple fmt.Printf 20 // to be a fully functional Logger. Therefore multiple wrappers are implemented 21 // here to provide different functions which could be missing in some loggers. 22 package types 23 24 import ( 25 "github.com/facebookincubator/go-belt" 26 "github.com/facebookincubator/go-belt/pkg/field" 27 ) 28 29 // Logger is an abstract generic structured logger. It is supposed 30 // to be one of the belt.Tools provided by the Belt. And therefore interface 31 // supposed to be used by end users of the `logger` package, so it already 32 // contains syntax sugar. 33 // 34 // All methods are thread-safe. 35 // 36 // For an optimized interface with the same functionality use interface CompactLogger. 37 type Logger interface { 38 belt.Tool 39 40 // Logf logs an unstructured message. Though, of course, all 41 // contextual structured fields will also be logged. 42 // 43 // This method exists mostly for convenience, for people who 44 // has not got used to proper structured logging, yet. 45 // See `LogFields` and `Log`. If one have variables they want to 46 // log, it is better for scalable observability to log them 47 // as structured values, instead of injecting them into a 48 // non-structured string. 49 Logf(level Level, format string, args ...any) 50 51 // LogFields logs structured fields with a explanation message. 52 // 53 // Anything that implements field.AbstractFields might be used 54 // as a collection of fields to be logged. 55 // 56 // Examples: 57 // 58 // l.LogFields(logger.LevelDebug, "new_request", field.Fields{{Key: "user_id", Value: userID}, {Key: "group_id", Value: groupID}}) 59 // l.LogFields(logger.LevelInfo, "affected entries", field.Field{Key: "mysql_affected", Value: affectedRows}) 60 // l.LogFields(logger.LevelError, "unable to fetch user info", request) // where `request` implements field.AbstractFields 61 // 62 // Sometimes it is inconvenient to manually describe each field, 63 // and for such cases see method `Log`. 64 LogFields(level Level, message string, fields field.AbstractFields) 65 66 // Log extracts structured fields from provided values, joins 67 // the rest into an unstructured message and logs the result. 68 // 69 // This function provides convenience (relatively to LogFields) 70 // at cost of a bit of performance. 71 // 72 // There are few ways to extract structured fields, which are 73 // applied for each value from `values` (in descending priority order): 74 // 1. If a `value` is an `*Entry` then the Entry is used (with its fields). 75 // This works only if this is the only argument. Otherwise it is 76 // threated as a simple structure (see point #3). 77 // 2. If a `value` implements field.AbstractFields then ForEachField method 78 // is used (so it is become similar to LogFields). 79 // 3. If a `value` is a structure (or a pointer to a structure) then 80 // fields of the structure are interpreted as structured fields 81 // to be logged (see explanation below). 82 // 4. If a `value` is a map then fields a constructed out of this map. 83 // 84 // Structured arguments are processed effectively the same 85 // as they would have through a sequence of WithField/WithFields. 86 // 87 // Everything that does not fit into any of the rules above is just 88 // joined into an unstructured message (and works the same way 89 // as `message` in LogFields). 90 // 91 // How structures are parsed: 92 // Structures are parsed recursively. Each field name of the path in a tree 93 // of structures is added to the resulting field name (for example in "struct{A struct{B int}}" 94 // the field name will be `A.B`). 95 // To enforce another name use tag `log` (for example "struct{A int `log:"anotherName"`}"), 96 // to prevent a field from logging use tag `log:"-"`. 97 // 98 // Examples: 99 // 100 // user, err := getUser() 101 // if err != nil { 102 // l.Log(logger.LevelError, err) 103 // return err 104 // } 105 // l.Log(logger.LevelDebug, "current user", user) // fields of structure "user" will be logged 106 // l.Log(logger.LevelDebug, map[string]any{"user_id": user.ID, "group_id", user.GroupID}) 107 // l.Log(logger.LevelDebug, field.Fields{{Key: "user_id", Value: user.ID}, {Key: "group_id", Value: user.GroupID}}) 108 // l.Log(logger.LevelDebug, "current user ID is ", user.ID, " and group ID is ", user.GroupID) // will result into message "current user ID is 1234 and group ID is 5678". 109 Log(level Level, values ...any) 110 111 // Emitter returns the Emitter (see the description of interface "Emitter"). 112 Emitter() Emitter 113 114 // Level returns the current logging level (see description of "Level"). 115 Level() Level 116 117 // TraceFields is just a shorthand for LogFields(logger.LevelTrace, ...) 118 TraceFields(message string, fields field.AbstractFields) 119 120 // DebugFields is just a shorthand for LogFields(logger.LevelDebug, ...) 121 DebugFields(message string, fields field.AbstractFields) 122 123 // InfoFields is just a shorthand for LogFields(logger.LevelInfo, ...) 124 InfoFields(message string, fields field.AbstractFields) 125 126 // WarnFields is just a shorthand for LogFields(logger.LevelWarn, ...) 127 WarnFields(message string, fields field.AbstractFields) 128 129 // ErrorFields is just a shorthand for LogFields(logger.LevelError, ...) 130 ErrorFields(message string, fields field.AbstractFields) 131 132 // PanicFields is just a shorthand for LogFields(logger.LevelPanic, ...) 133 // 134 // Be aware: Panic level also triggers a `panic`. 135 PanicFields(message string, fields field.AbstractFields) 136 137 // FatalFields is just a shorthand for LogFields(logger.LevelFatal, ...) 138 // 139 // Be aware: Panic level also triggers an `os.Exit`. 140 FatalFields(message string, fields field.AbstractFields) 141 142 // Trace is just a shorthand for Log(logger.LevelTrace, ...) 143 Trace(values ...any) 144 145 // Debug is just a shorthand for Log(logger.LevelDebug, ...) 146 Debug(values ...any) 147 148 // Info is just a shorthand for Log(logger.LevelInfo, ...) 149 Info(values ...any) 150 151 // Warn is just a shorthand for Log(logger.LevelWarn, ...) 152 Warn(values ...any) 153 154 // Error is just a shorthand for Log(logger.LevelError, ...) 155 Error(values ...any) 156 157 // Panic is just a shorthand for Log(logger.LevelPanic, ...) 158 // 159 // Be aware: Panic level also triggers a `panic`. 160 Panic(values ...any) 161 162 // Fatal is just a shorthand for Log(logger.LevelFatal, ...) 163 // 164 // Be aware: Fatal level also triggers an `os.Exit`. 165 Fatal(values ...any) 166 167 // Tracef is just a shorthand for Logf(logger.LevelTrace, ...) 168 Tracef(format string, args ...any) 169 170 // Debugf is just a shorthand for Logf(logger.LevelDebug, ...) 171 Debugf(format string, args ...any) 172 173 // Infof is just a shorthand for Logf(logger.LevelInfo, ...) 174 Infof(format string, args ...any) 175 176 // Warnf is just a shorthand for Logf(logger.LevelWarn, ...) 177 Warnf(format string, args ...any) 178 179 // Errorf is just a shorthand for Logf(logger.LevelError, ...) 180 Errorf(format string, args ...any) 181 182 // Panicf is just a shorthand for Logf(logger.LevelPanic, ...) 183 // 184 // Be aware: Panic level also triggers a `panic`. 185 Panicf(format string, args ...any) 186 187 // Fatalf is just a shorthand for Logf(logger.LevelFatal, ...) 188 // 189 // Be aware: Fatal level also triggers an `os.Exit`. 190 Fatalf(format string, args ...any) 191 192 // WithLevel returns a logger with logger level set to the given argument. 193 // 194 // See also the description of type "Level". 195 WithLevel(Level) Logger 196 197 // WithPreHooks returns a Logger which includes/appends pre-hooks from the arguments. 198 // 199 // See also description of "PreHook". 200 // 201 // Special case: to reset hooks use `WithPreHooks()` (without any arguments). 202 WithPreHooks(...PreHook) Logger 203 204 // WithHooks returns a Logger which includes/appends hooks from the arguments. 205 // 206 // See also description of "Hook". 207 // 208 // Special case: to reset hooks use `WithHooks()` (without any arguments). 209 WithHooks(...Hook) Logger 210 211 // WithField returns the logger with the added field (used for structured logging). 212 WithField(key string, value any, props ...field.Property) Logger 213 214 // WithFields returns the logger with the added fields (used for structured logging) 215 WithFields(fields field.AbstractFields) Logger 216 217 // WithMessagePrefix adds a string to all messages logged through the derived logger. 218 WithMessagePrefix(prefix string) Logger 219 220 // WithEntryProperties adds props to EntryProperties of each emitted Entry. 221 // This could be used only for enabling implementation-specific behavior. 222 WithEntryProperties(props ...EntryProperty) Logger 223 } 224 225 // Emitter is a log entry sender. It is not obligated to provide 226 // functionality for logging levels, hooks, contextual fields or 227 // any other fancy stuff, and it just sends what is was told to. 228 // 229 // Note: 230 // Some specific Emitter implementations may support filtering of 231 // messages based on log level or/and add structured fields 232 // internally or do other stuff. But it is expected that even 233 // if a Emitter actually supports that kind of functionality, 234 // it will still be by default configured in a way like 235 // it has no such functionality (thus maximal logging level, no contextual 236 // fields and so on). 237 // However, if a Emitter is returned from a Logger, then it may (or may not) 238 // inherit properties of Logger (like logging level or structured fields). 239 // The undefined behavior here is left intentionally to provide more flexibility 240 // to Logger implementations to achieve better performance. It is considered 241 // than any Emitter managed by a Logger may have any configuration 242 // the Logger may consider the optimal one at any moment. 243 // 244 // All methods are thread-safe. 245 type Emitter interface { 246 Flusher 247 248 // Emit just logs the provided Entry. It does not modify it. 249 // 250 // If it is reasonably possible then the implementation of Emitter 251 // should not panic or os.Exit even if the Level is Fatal or Panic. 252 // Otherwise for example it prevents from logging a problem through other 253 // Emitters if there are multiple of them. 254 Emit(entry *Entry) 255 } 256 257 // Emitters is a set of Emitter-s. 258 // 259 // Only the last Emitter is allowed to panic or/and os.Exit (on Level-s Fatal and Panic). 260 // Do not use a set of Emitters if this rule is not satisfied. Check guarantees these 261 // provided by specific a Emitter implementation. 262 type Emitters []Emitter 263 264 var _ Emitter = (Emitters)(nil) 265 266 // Flush implements Emitter. 267 func (s Emitters) Flush() { 268 for _, l := range s { 269 l.Flush() 270 } 271 } 272 273 // Emit implements Emitter. 274 func (s Emitters) Emit(entry *Entry) { 275 for _, l := range s { 276 l.Emit(entry) 277 } 278 } 279 280 // Flusher defines a method to flush all buffers. 281 type Flusher interface { 282 // Flush forces to flush all buffers. 283 Flush() 284 }