github.com/qlik-oss/gopherciser@v0.18.6/logger/entry.go (about) 1 package logger 2 3 import ( 4 "fmt" 5 "strconv" 6 "sync" 7 "time" 8 9 "github.com/qlik-oss/gopherciser/atomichandlers" 10 "github.com/qlik-oss/gopherciser/helpers" 11 ) 12 13 type ( 14 // SessionEntry log fields living of entire session 15 SessionEntry struct { 16 User string 17 Thread uint64 18 Session uint64 19 SessionName string 20 AppName string 21 AppGUID string 22 } 23 24 // ActionEntry log fields living during action 25 ActionEntry struct { 26 Action string 27 Label string 28 ActionID uint64 29 ObjectType string 30 } 31 32 // EphemeralEntry log fields living during log entry only 33 ephemeralEntry struct { 34 ResponseTime int64 35 Success bool 36 Warnings uint64 37 Errors uint64 38 Stack error 39 Sent uint64 40 Received uint64 41 Details string 42 InfoType string 43 RequestsSent uint64 44 } 45 46 //LogEntry entry used for logging 47 LogEntry struct { 48 logger *Log 49 Session *SessionEntry 50 Action *ActionEntry 51 // logging interceptor return false to break. 52 interceptors map[LogLevel]func(msg *LogEntry) bool 53 mu sync.Mutex 54 } 55 ) 56 57 var tickCounter = atomichandlers.AtomicCounter{} 58 59 // NewLogEntry new instance of LogEntry 60 func NewLogEntry(log *Log) *LogEntry { 61 return &LogEntry{ 62 logger: log, 63 } 64 } 65 66 // ShallowCopy log entry, creates new log entry with pointers to exact same data, but with a new mutex 67 func (entry *LogEntry) ShallowCopy() *LogEntry { 68 newLogEntry := NewLogEntry(entry.logger) 69 newLogEntry.interceptors = entry.interceptors 70 return newLogEntry 71 } 72 73 // Logf write formatted log entry to log 74 func (entry *LogEntry) Logf(level LogLevel, format string, args ...interface{}) { 75 if entry == nil { 76 return 77 } 78 79 entry.log(level, fmt.Sprintf(format, args...), nil) 80 } 81 82 // Log write log entry to log 83 func (entry *LogEntry) Log(level LogLevel, args ...interface{}) { 84 if entry == nil { 85 return 86 } 87 88 entry.log(level, fmt.Sprint(args...), nil) 89 } 90 91 // LogTrafficMetric log traffic metric entry 92 func (entry *LogEntry) LogTrafficMetric(responseTime int64, sent, received uint64, requestID int, method, params, trafficType, msg string) { 93 if entry == nil || entry.logger == nil || !entry.logger.Settings.Metrics { 94 return 95 } 96 97 separator := rune('\u001e') // 30 is RS (Record Separator) 98 var reqIDString string 99 100 if requestID != -1 { 101 reqIDString = strconv.Itoa(requestID) 102 } 103 104 buf := helpers.NewBuffer() 105 buf.WriteString(trafficType) 106 buf.WriteRune(separator) 107 buf.WriteString(reqIDString) 108 buf.WriteRune(separator) 109 buf.WriteString(method) 110 buf.WriteRune(separator) 111 buf.WriteString(params) 112 113 var details string 114 if buf.Error == nil { 115 details = buf.String() 116 } 117 118 entry.log(MetricsLevel, msg, &ephemeralEntry{ 119 ResponseTime: responseTime, 120 Sent: sent, 121 Received: received, 122 Details: details, 123 }) 124 } 125 126 // LogDetail log message with detail 127 func (entry *LogEntry) LogDetail(level LogLevel, msg, detail string) { 128 if entry == nil { 129 return 130 } 131 132 entry.log(level, msg, &ephemeralEntry{ 133 Details: detail, 134 }) 135 } 136 137 // LogResult log result entry 138 func (entry *LogEntry) LogResult(success bool, warnings, errors, sent, received, requests uint64, responsetime int64, details string) { 139 if entry == nil { 140 return 141 } 142 143 entry.log(ResultLevel, "", &ephemeralEntry{ 144 Success: success, 145 Warnings: warnings, 146 Errors: errors, 147 Sent: sent, 148 Received: received, 149 RequestsSent: requests, 150 ResponseTime: responsetime, 151 Details: details, 152 }) 153 } 154 155 // LogInfo log info entry 156 func (entry *LogEntry) LogInfo(infoType, msg string) { 157 if entry == nil { 158 return 159 } 160 161 entry.log(InfoLevel, msg, &ephemeralEntry{ 162 InfoType: infoType, 163 }) 164 } 165 166 // LogErrorReport log warning and error count 167 func (entry *LogEntry) LogErrorReport(reportType string, errors, warnings uint64) { 168 if entry == nil { 169 return 170 } 171 172 entry.Action = nil 173 entry.log(InfoLevel, fmt.Sprintf("%d", errors+warnings), &ephemeralEntry{ 174 InfoType: reportType, 175 Errors: errors, 176 Warnings: warnings, 177 }) 178 } 179 180 // LogError log error entry 181 func (entry *LogEntry) LogError(err error) { 182 if entry == nil { 183 return 184 } 185 186 entry.log(ErrorLevel, fmt.Sprintf("%s", err), &ephemeralEntry{ 187 Stack: err, 188 }) 189 } 190 191 // LogErrorWithMsg log error entry with message 192 func (entry *LogEntry) LogErrorWithMsg(msg string, err error) { 193 if entry == nil { 194 return 195 } 196 entry.log(ErrorLevel, msg, &ephemeralEntry{ 197 Stack: err, 198 }) 199 } 200 201 // LogDebug log debug entry with message 202 func (entry *LogEntry) LogDebug(msg string) { 203 if !entry.ShouldLogDebug() { 204 return 205 } 206 entry.log(DebugLevel, msg, nil) 207 } 208 209 // LogDebugf log debug entry with message 210 func (entry *LogEntry) LogDebugf(format string, args ...interface{}) { 211 if !entry.ShouldLogDebug() { 212 return 213 } 214 entry.log(DebugLevel, fmt.Sprintf(format, args...), nil) 215 } 216 217 func (entry *LogEntry) LogRegression(id string, data interface{}, meta map[string]interface{}) error { 218 return entry.logger.regressionLogger.Log(id, data, meta) 219 } 220 221 func (entry *LogEntry) log(level LogLevel, msg string, eph *ephemeralEntry) { 222 if entry == nil { 223 return 224 } 225 226 entry.mu.Lock() 227 defer entry.mu.Unlock() 228 229 m := message{ 230 Level: level, 231 Time: time.Now(), 232 Message: msg, 233 Tick: tickCounter.Inc(), 234 } 235 236 var s SessionEntry 237 if entry.Session != nil { 238 s = *entry.Session 239 } else { 240 s = SessionEntry{} 241 } 242 243 var a ActionEntry 244 if entry.Action != nil { 245 a = *entry.Action 246 } else { 247 a = ActionEntry{} 248 } 249 250 if eph == nil { 251 eph = &ephemeralEntry{} 252 } 253 254 chanMsg := &LogChanMsg{m, s, a, eph} 255 256 if entry.interceptors[level] != nil { 257 if !entry.interceptors[level](entry) { 258 return 259 } 260 } 261 262 go entry.queueWrite(chanMsg) 263 } 264 265 func (entry *LogEntry) queueWrite(msg *LogChanMsg) { 266 if entry == nil || entry.logger == nil { 267 return 268 } 269 270 entry.logger.logChan <- msg 271 } 272 273 // SetSessionEntry set new session entry 274 func (entry *LogEntry) SetSessionEntry(s *SessionEntry) { 275 if entry == nil { 276 return 277 } 278 279 entry.mu.Lock() 280 defer entry.mu.Unlock() 281 282 entry.Session = s 283 } 284 285 // SetActionEntry set new session entry 286 func (entry *LogEntry) SetActionEntry(a *ActionEntry) { 287 if entry == nil { 288 return 289 } 290 291 entry.mu.Lock() 292 defer entry.mu.Unlock() 293 294 entry.Action = a 295 } 296 297 // AddInterceptor to log entry, return false to avoid logging 298 func (entry *LogEntry) AddInterceptor(level LogLevel, f func(msg *LogEntry) bool) { 299 if entry == nil { 300 return 301 } 302 303 if entry.interceptors == nil { 304 entry.interceptors = make(map[LogLevel]func(msg *LogEntry) bool) 305 } 306 307 entry.interceptors[level] = f 308 } 309 310 // ShouldLogTraffic should traffic be logged 311 func (entry *LogEntry) ShouldLogTraffic() bool { 312 if entry == nil || entry.logger == nil { 313 return false 314 } 315 return entry.logger.Settings.Traffic 316 } 317 318 // ShouldLogTrafficMetrics should traffic metrics be logged 319 func (entry *LogEntry) ShouldLogTrafficMetrics() bool { 320 if entry == nil || entry.logger == nil { 321 return false 322 } 323 return entry.logger.Settings.Metrics 324 } 325 326 // ShouldLogDebug should debug info be logged 327 func (entry *LogEntry) ShouldLogDebug() bool { 328 if entry == nil || entry.logger == nil { 329 return false 330 } 331 return entry.logger.Settings.Debug 332 } 333 334 // ShouldLogRegression should regression data be logged 335 func (entry *LogEntry) ShouldLogRegression() bool { 336 return entry != nil && entry.logger != nil && entry.logger.Settings.Regression 337 }