github.com/qioalice/ekago/v3@v3.3.2-0.20221202205325-5c262d586ee4/ekalog/logger.go (about) 1 // Copyright © 2020. All rights reserved. 2 // Author: Ilya Stroy. 3 // Contacts: iyuryevich@pm.me, https://github.com/qioalice 4 // License: https://opensource.org/licenses/MIT 5 6 package ekalog 7 8 import ( 9 "fmt" 10 "time" 11 12 "github.com/qioalice/ekago/v3/internal/ekaclike" 13 "github.com/qioalice/ekago/v3/internal/ekaletter" 14 ) 15 16 type ( 17 // Logger is used to generate and write log messages. 18 // 19 // You can instantiate as many your own loggers with different behaviour, 20 // different Integrator, as you want. 21 // But also you can just use package level logger, modify it and configure it 22 // the same way as any instantiated Logger object. 23 // 24 // Inheritance. 25 // 26 // Remember! 27 // No one func or method does not change the current object. 28 // They always creates and returns a copy of the current object with applied 29 // your changes except in cases in which the opposite is not explicitly indicated. 30 // 31 // Of course you can chain all setters and then call log message generator, like this: 32 // 33 // WithString("key", "value").Warn("It's dangerous!") 34 // 35 // But in that case, after finishing execution of second line, 36 // 'log' variable won't contain added field "key". 37 // Want a different behaviour and want to have Logger with these fields? 38 // No problem, save generated Logger object: 39 // 40 // log := WithString("key", "value") 41 // log.Warn("It's dangerous!") 42 // 43 // Because of all finishers (methods that actually writes a log message, e.g: 44 // Debug, Debugf, Debugw, Warn, Warnf, Warnw, etc...) also returns a Logger 45 // object that is used to generate log Entry, you can save it too, and finally 46 // it's the same as in the example above: 47 // 48 // log := log.WithString("key", "value").Warn("It's dangerous!") 49 // 50 // but it's strongly not recommended to do so, because it made code less clear. 51 Logger struct { 52 53 // integrator is the way how Entry will be encoded and what encoded Entry 54 // will be written to. 55 integrator Integrator 56 57 // entry is _WHAT_ log message is. 58 // entry is it's stacktrace, caller info, timestamp, level, message, group, 59 // flags, etc. 60 entry *Entry 61 } 62 ) 63 64 // ------------------------------ COMMON METHODS ------------------------------ // 65 // ---------------------------------------------------------------------------- // 66 67 // IsValid reports whether current Logger is valid. 68 // Nil safe. 69 // 70 // It returns false if Logger is nil or has not been initialized properly 71 // (instantiated manually instead of Logger's constructors calling). 72 func (l *Logger) IsValid() bool { 73 74 // Integrator and Entry (if they're not nil) can not be invalid (internally) 75 // because they are created only by internal functions and they're private. 76 // So 3 nil checks are enough here and of course check ptr equal. 77 78 return l != nil && l.integrator != nil && l.entry != nil && l == l.entry.l 79 } 80 81 // Copy returns a copy of the current Logger. Does nothing for 'nopLogger'. 82 // 83 // Copy is useful when you need to build your Entry step-by-step, 84 // adding fields, messages, etc. 85 func (l *Logger) Copy() (copy *Logger) { 86 l.assert() 87 if l == nopLogger { 88 return nopLogger 89 } 90 return l.derive() 91 } 92 93 // Sync forces to flush all Integrator buffers of current Logger 94 // and makes sure all pending Entry are written. 95 // Nil safe. 96 // 97 // Requirements: 98 // - Logger != nil, panic otherwise; 99 // - Logger is initialized properly and has registered Integrator, panic otherwise. 100 func (l *Logger) Sync() error { 101 l.assert() 102 if l == nopLogger { 103 return nil 104 } 105 return l.integrator.Sync() 106 } 107 108 // --------------------------- FIELDS ADDING METHODS -------------------------- // 109 // ---------------------------------------------------------------------------- // 110 111 // Methods below are code-generated. 112 113 // With adds presented ekaletter.LetterField to the current Logger if it's addable. 114 // With DO NOT makes a copy of current Logger and adds field in-place. 115 // If you need to construct an logger with your own fields that will be used later, 116 // you need to call Copy() manually before. 117 func (l *Logger) With(f ekaletter.LetterField) *Logger { 118 return l.addField(f) 119 } 120 121 func (l *Logger) WithBool(key string, value bool) *Logger { 122 return l.addField(ekaletter.FBool(key, value)) 123 } 124 func (l *Logger) WithInt(key string, value int) *Logger { 125 return l.addField(ekaletter.FInt(key, value)) 126 } 127 func (l *Logger) WithInt8(key string, value int8) *Logger { 128 return l.addField(ekaletter.FInt8(key, value)) 129 } 130 func (l *Logger) WithInt16(key string, value int16) *Logger { 131 return l.addField(ekaletter.FInt16(key, value)) 132 } 133 func (l *Logger) WithInt32(key string, value int32) *Logger { 134 return l.addField(ekaletter.FInt32(key, value)) 135 } 136 func (l *Logger) WithInt64(key string, value int64) *Logger { 137 return l.addField(ekaletter.FInt64(key, value)) 138 } 139 func (l *Logger) WithUint(key string, value uint) *Logger { 140 return l.addField(ekaletter.FUint(key, value)) 141 } 142 func (l *Logger) WithUint8(key string, value uint8) *Logger { 143 return l.addField(ekaletter.FUint8(key, value)) 144 } 145 func (l *Logger) WithUint16(key string, value uint16) *Logger { 146 return l.addField(ekaletter.FUint16(key, value)) 147 } 148 func (l *Logger) WithUint32(key string, value uint32) *Logger { 149 return l.addField(ekaletter.FUint32(key, value)) 150 } 151 func (l *Logger) WithUint64(key string, value uint64) *Logger { 152 return l.addField(ekaletter.FUint64(key, value)) 153 } 154 func (l *Logger) WithUintptr(key string, value uintptr) *Logger { 155 return l.addField(ekaletter.FUintptr(key, value)) 156 } 157 func (l *Logger) WithFloat32(key string, value float32) *Logger { 158 return l.addField(ekaletter.FFloat32(key, value)) 159 } 160 func (l *Logger) WithFloat64(key string, value float64) *Logger { 161 return l.addField(ekaletter.FFloat64(key, value)) 162 } 163 func (l *Logger) WithComplex64(key string, value complex64) *Logger { 164 return l.addField(ekaletter.FComplex64(key, value)) 165 } 166 func (l *Logger) WithComplex128(key string, value complex128) *Logger { 167 return l.addField(ekaletter.FComplex128(key, value)) 168 } 169 func (l *Logger) WithString(key string, value string) *Logger { 170 return l.addField(ekaletter.FString(key, value)) 171 } 172 func (l *Logger) WithStringFromBytes(key string, value []byte) *Logger { 173 return l.addField(ekaletter.FStringFromBytes(key, value)) 174 } 175 func (l *Logger) WithBoolp(key string, value *bool) *Logger { 176 return l.addField(ekaletter.FBoolp(key, value)) 177 } 178 func (l *Logger) WithIntp(key string, value *int) *Logger { 179 return l.addField(ekaletter.FIntp(key, value)) 180 } 181 func (l *Logger) WithInt8p(key string, value *int8) *Logger { 182 return l.addField(ekaletter.FInt8p(key, value)) 183 } 184 func (l *Logger) WithInt16p(key string, value *int16) *Logger { 185 return l.addField(ekaletter.FInt16p(key, value)) 186 } 187 func (l *Logger) WithInt32p(key string, value *int32) *Logger { 188 return l.addField(ekaletter.FInt32p(key, value)) 189 } 190 func (l *Logger) WithInt64p(key string, value *int64) *Logger { 191 return l.addField(ekaletter.FInt64p(key, value)) 192 } 193 func (l *Logger) WithUintp(key string, value *uint) *Logger { 194 return l.addField(ekaletter.FUintp(key, value)) 195 } 196 func (l *Logger) WithUint8p(key string, value *uint8) *Logger { 197 return l.addField(ekaletter.FUint8p(key, value)) 198 } 199 func (l *Logger) WithUint16p(key string, value *uint16) *Logger { 200 return l.addField(ekaletter.FUint16p(key, value)) 201 } 202 func (l *Logger) WithUint32p(key string, value *uint32) *Logger { 203 return l.addField(ekaletter.FUint32p(key, value)) 204 } 205 func (l *Logger) WithUint64p(key string, value *uint64) *Logger { 206 return l.addField(ekaletter.FUint64p(key, value)) 207 } 208 func (l *Logger) WithFloat32p(key string, value *float32) *Logger { 209 return l.addField(ekaletter.FFloat32p(key, value)) 210 } 211 func (l *Logger) WithFloat64p(key string, value *float64) *Logger { 212 return l.addField(ekaletter.FFloat64p(key, value)) 213 } 214 func (l *Logger) WithStringp(key string, value *string) *Logger { 215 return l.addField(ekaletter.FStringp(key, value)) 216 } 217 func (l *Logger) WithType(key string, value any) *Logger { 218 return l.addField(ekaletter.FType(key, value)) 219 } 220 func (l *Logger) WithStringer(key string, value fmt.Stringer) *Logger { 221 return l.addField(ekaletter.FStringer(key, value)) 222 } 223 func (l *Logger) WithAddr(key string, value any) *Logger { 224 return l.addField(ekaletter.FAddr(key, value)) 225 } 226 func (l *Logger) WithUnixFromStd(key string, value time.Time) *Logger { 227 return l.addField(ekaletter.FUnixFromStd(key, value)) 228 } 229 func (l *Logger) WithUnixNanoFromStd(key string, value time.Time) *Logger { 230 return l.addField(ekaletter.FUnixNanoFromStd(key, value)) 231 } 232 func (l *Logger) WithUnix(key string, value int64) *Logger { 233 return l.addField(ekaletter.FUnix(key, value)) 234 } 235 func (l *Logger) WithUnixNano(key string, value int64) *Logger { 236 return l.addField(ekaletter.FUnixNano(key, value)) 237 } 238 func (l *Logger) WithDuration(key string, value time.Duration) *Logger { 239 return l.addField(ekaletter.FDuration(key, value)) 240 } 241 func (l *Logger) WithArray(key string, value any) *Logger { 242 return l.addField(ekaletter.FArray(key, value)) 243 } 244 func (l *Logger) WithObject(key string, value any) *Logger { 245 return l.addField(ekaletter.FObject(key, value)) 246 } 247 func (l *Logger) WithMap(key string, value any) *Logger { 248 return l.addField(ekaletter.FMap(key, value)) 249 } 250 func (l *Logger) WithExtractedMap(key string, value map[string]any) *Logger { 251 return l.addField(ekaletter.FExtractedMap(key, value)) 252 } 253 func (l *Logger) WithAny(key string, value any) *Logger { 254 return l.addField(ekaletter.FAny(key, value)) 255 } 256 func (l *Logger) WithMany(fields ...ekaletter.LetterField) *Logger { 257 return l.addFields(fields) 258 } 259 func (l *Logger) WithManyAny(fields ...any) *Logger { 260 return l.addFieldsParse(fields) 261 } 262 263 // ------------------------ CONDITIONAL LOGGING METHODS ----------------------- // 264 // ---------------------------------------------------------------------------- // 265 266 // If returns current Logger if cond is true, otherwise nop Logger is returned. 267 // Thus it's useful to chaining methods - next methods in chaining will be done 268 // only if cond is true. 269 // 270 // Requirements: 271 // - Logger is not nil, panic otherwise. 272 func (l *Logger) If(cond bool) *Logger { 273 l.assert() 274 if cond { 275 return l 276 } else { 277 return nopLogger 278 } 279 } 280 281 // ------------------------------ UTILITY METHODS ----------------------------- // 282 // ---------------------------------------------------------------------------- // 283 284 // ReplaceIntegrator replaces Integrator for the current Logger object 285 // to the passed one. 286 // 287 // Requirements: 288 // - Logger is not nil, panic otherwise; 289 // - Integrator is not nil (even typed nil), panic otherwise; 290 // - If Integrator is CommonIntegrator 291 // it must not be registered with some Logger before, panic otherwise; 292 // - If Integrator is CommonIntegrator 293 // it must have at least 1 registered io.Writer, panic otherwise. 294 // 295 // WARNING. 296 // Replacing Integrator will drop all pre-encoded ekaletter.LetterField fields 297 // that are might be added already to the current Integrator. 298 func (l *Logger) ReplaceIntegrator(newIntegrator Integrator) { 299 l.assert() 300 if l == nopLogger { 301 return 302 } 303 if ekaclike.TakeRealAddr(newIntegrator) == nil { 304 panic("Failed to change Integrator. New Integrator is nil.") 305 } 306 if ci, ok := newIntegrator.(*CommonIntegrator); ok { 307 ci.build() 308 } 309 baseLogger.setIntegrator(newIntegrator) 310 }