github.com/netdata/go.d.plugin@v0.58.1/modules/squidlog/collect.go (about) 1 // SPDX-License-Identifier: GPL-3.0-or-later 2 3 package squidlog 4 5 import ( 6 "io" 7 "runtime" 8 "strconv" 9 "strings" 10 11 "github.com/netdata/go.d.plugin/pkg/logs" 12 "github.com/netdata/go.d.plugin/pkg/stm" 13 14 "github.com/netdata/go.d.plugin/agent/module" 15 ) 16 17 func (s SquidLog) logPanicStackIfAny() { 18 err := recover() 19 if err == nil { 20 return 21 } 22 s.Errorf("[ERROR] %s\n", err) 23 for depth := 0; ; depth++ { 24 _, file, line, ok := runtime.Caller(depth) 25 if !ok { 26 break 27 } 28 s.Errorf("======> %d: %v:%d", depth, file, line) 29 } 30 panic(err) 31 } 32 33 func (s *SquidLog) collect() (map[string]int64, error) { 34 defer s.logPanicStackIfAny() 35 s.mx.reset() 36 37 var mx map[string]int64 38 39 n, err := s.collectLogLines() 40 41 if n > 0 || err == nil { 42 mx = stm.ToMap(s.mx) 43 } 44 return mx, err 45 } 46 47 func (s *SquidLog) collectLogLines() (int, error) { 48 var n int 49 for { 50 s.line.reset() 51 err := s.parser.ReadLine(s.line) 52 if err != nil { 53 if err == io.EOF { 54 return n, nil 55 } 56 if !logs.IsParseError(err) { 57 return n, err 58 } 59 n++ 60 s.collectUnmatched() 61 continue 62 } 63 n++ 64 if s.line.empty() { 65 s.collectUnmatched() 66 } else { 67 s.collectLogLine() 68 } 69 } 70 } 71 72 func (s *SquidLog) collectLogLine() { 73 s.mx.Requests.Inc() 74 s.collectRespTime() 75 s.collectClientAddress() 76 s.collectCacheCode() 77 s.collectHTTPCode() 78 s.collectRespSize() 79 s.collectReqMethod() 80 s.collectHierCode() 81 s.collectServerAddress() 82 s.collectMimeType() 83 } 84 85 func (s *SquidLog) collectUnmatched() { 86 s.mx.Requests.Inc() 87 s.mx.Unmatched.Inc() 88 } 89 90 func (s *SquidLog) collectRespTime() { 91 if !s.line.hasRespTime() { 92 return 93 } 94 s.mx.RespTime.Observe(float64(s.line.respTime)) 95 } 96 97 func (s *SquidLog) collectClientAddress() { 98 if !s.line.hasClientAddress() { 99 return 100 } 101 s.mx.UniqueClients.Insert(s.line.clientAddr) 102 } 103 104 func (s *SquidLog) collectCacheCode() { 105 if !s.line.hasCacheCode() { 106 return 107 } 108 109 c, ok := s.mx.CacheCode.GetP(s.line.cacheCode) 110 if !ok { 111 s.addDimToCacheCodeChart(s.line.cacheCode) 112 } 113 c.Inc() 114 115 tags := strings.Split(s.line.cacheCode, "_") 116 for _, tag := range tags { 117 s.collectCacheCodeTag(tag) 118 } 119 } 120 121 func (s *SquidLog) collectHTTPCode() { 122 if !s.line.hasHTTPCode() { 123 return 124 } 125 126 code := s.line.httpCode 127 switch { 128 case code >= 100 && code < 300, code == 0, code == 304, code == 401: 129 s.mx.ReqSuccess.Inc() 130 case code >= 300 && code < 400: 131 s.mx.ReqRedirect.Inc() 132 case code >= 400 && code < 500: 133 s.mx.ReqBad.Inc() 134 case code >= 500 && code <= 603: 135 s.mx.ReqError.Inc() 136 } 137 138 switch code / 100 { 139 case 0: 140 s.mx.HTTPResp0xx.Inc() 141 case 1: 142 s.mx.HTTPResp1xx.Inc() 143 case 2: 144 s.mx.HTTPResp2xx.Inc() 145 case 3: 146 s.mx.HTTPResp3xx.Inc() 147 case 4: 148 s.mx.HTTPResp4xx.Inc() 149 case 5: 150 s.mx.HTTPResp5xx.Inc() 151 case 6: 152 s.mx.HTTPResp6xx.Inc() 153 } 154 155 codeStr := strconv.Itoa(code) 156 c, ok := s.mx.HTTPRespCode.GetP(codeStr) 157 if !ok { 158 s.addDimToHTTPRespCodesChart(codeStr) 159 } 160 c.Inc() 161 } 162 163 func (s *SquidLog) collectRespSize() { 164 if !s.line.hasRespSize() { 165 return 166 } 167 s.mx.BytesSent.Add(float64(s.line.respSize)) 168 } 169 170 func (s *SquidLog) collectReqMethod() { 171 if !s.line.hasReqMethod() { 172 return 173 } 174 c, ok := s.mx.ReqMethod.GetP(s.line.reqMethod) 175 if !ok { 176 s.addDimToReqMethodChart(s.line.reqMethod) 177 } 178 c.Inc() 179 } 180 181 func (s *SquidLog) collectHierCode() { 182 if !s.line.hasHierCode() { 183 return 184 } 185 c, ok := s.mx.HierCode.GetP(s.line.hierCode) 186 if !ok { 187 s.addDimToHierCodeChart(s.line.hierCode) 188 } 189 c.Inc() 190 } 191 192 func (s *SquidLog) collectServerAddress() { 193 if !s.line.hasServerAddress() { 194 return 195 } 196 c, ok := s.mx.Server.GetP(s.line.serverAddr) 197 if !ok { 198 s.addDimToServerAddressChart(s.line.serverAddr) 199 } 200 c.Inc() 201 } 202 203 func (s *SquidLog) collectMimeType() { 204 if !s.line.hasMimeType() { 205 return 206 } 207 c, ok := s.mx.MimeType.GetP(s.line.mimeType) 208 if !ok { 209 s.addDimToMimeTypeChart(s.line.mimeType) 210 } 211 c.Inc() 212 } 213 214 func (s *SquidLog) collectCacheCodeTag(tag string) { 215 // https://wiki.squid-cache.org/SquidFaq/SquidLogs#Squid_result_codes 216 switch tag { 217 default: 218 case "TCP", "UDP", "NONE": 219 c, ok := s.mx.CacheCodeTransportTag.GetP(tag) 220 if !ok { 221 s.addDimToCacheCodeTransportTagChart(tag) 222 } 223 c.Inc() 224 case "CF", "CLIENT", "IMS", "ASYNC", "SWAPFAIL", "REFRESH", "SHARED", "REPLY": 225 c, ok := s.mx.CacheCodeHandlingTag.GetP(tag) 226 if !ok { 227 s.addDimToCacheCodeHandlingTagChart(tag) 228 } 229 c.Inc() 230 case "NEGATIVE", "STALE", "OFFLINE", "INVALID", "FAIL", "MODIFIED", "UNMODIFIED", "REDIRECT": 231 c, ok := s.mx.CacheCodeObjectTag.GetP(tag) 232 if !ok { 233 s.addDimToCacheCodeObjectTagChart(tag) 234 } 235 c.Inc() 236 case "HIT", "MEM", "MISS", "DENIED", "NOFETCH", "TUNNEL": 237 c, ok := s.mx.CacheCodeLoadSourceTag.GetP(tag) 238 if !ok { 239 s.addDimToCacheCodeLoadSourceTagChart(tag) 240 } 241 c.Inc() 242 case "ABORTED", "TIMEOUT", "IGNORED": 243 c, ok := s.mx.CacheCodeErrorTag.GetP(tag) 244 if !ok { 245 s.addDimToCacheCodeErrorTagChart(tag) 246 } 247 c.Inc() 248 } 249 } 250 251 func (s *SquidLog) addDimToCacheCodeChart(code string) { 252 chartID := cacheCodeChart.ID 253 dimID := pxCacheCode + code 254 s.addDimToChart(chartID, dimID, code) 255 } 256 257 func (s *SquidLog) addDimToCacheCodeTransportTagChart(tag string) { 258 chartID := cacheCodeTransportTagChart.ID 259 dimID := pxTransportTag + tag 260 s.addDimToChart(chartID, dimID, tag) 261 } 262 263 func (s *SquidLog) addDimToCacheCodeHandlingTagChart(tag string) { 264 chartID := cacheCodeHandlingTagChart.ID 265 dimID := pxHandlingTag + tag 266 s.addDimToChart(chartID, dimID, tag) 267 } 268 269 func (s *SquidLog) addDimToCacheCodeObjectTagChart(tag string) { 270 chartID := cacheCodeObjectTagChart.ID 271 dimID := pxObjectTag + tag 272 s.addDimToChart(chartID, dimID, tag) 273 } 274 275 func (s *SquidLog) addDimToCacheCodeLoadSourceTagChart(tag string) { 276 chartID := cacheCodeLoadSourceTagChart.ID 277 dimID := pxSourceTag + tag 278 s.addDimToChart(chartID, dimID, tag) 279 } 280 281 func (s *SquidLog) addDimToCacheCodeErrorTagChart(tag string) { 282 chartID := cacheCodeErrorTagChart.ID 283 dimID := pxErrorTag + tag 284 s.addDimToChart(chartID, dimID, tag) 285 } 286 287 func (s *SquidLog) addDimToHTTPRespCodesChart(tag string) { 288 chartID := httpRespCodesChart.ID 289 dimID := pxHTTPCode + tag 290 s.addDimToChart(chartID, dimID, tag) 291 } 292 293 func (s *SquidLog) addDimToReqMethodChart(method string) { 294 chartID := reqMethodChart.ID 295 dimID := pxReqMethod + method 296 s.addDimToChart(chartID, dimID, method) 297 } 298 299 func (s *SquidLog) addDimToHierCodeChart(code string) { 300 chartID := hierCodeChart.ID 301 dimID := pxHierCode + code 302 dimName := code[5:] // remove "HIER_" 303 s.addDimToChart(chartID, dimID, dimName) 304 } 305 306 func (s *SquidLog) addDimToServerAddressChart(address string) { 307 chartID := serverAddrChart.ID 308 dimID := pxSrvAddr + address 309 s.addDimToChartOrCreateIfNotExist(chartID, dimID, address) 310 } 311 312 func (s *SquidLog) addDimToMimeTypeChart(mimeType string) { 313 chartID := mimeTypeChart.ID 314 dimID := pxMimeType + mimeType 315 s.addDimToChartOrCreateIfNotExist(chartID, dimID, mimeType) 316 } 317 318 func (s *SquidLog) addDimToChart(chartID, dimID, dimName string) { 319 chart := s.Charts().Get(chartID) 320 if chart == nil { 321 s.Warningf("add '%s' dim: couldn't find '%s' chart in charts", dimID, chartID) 322 return 323 } 324 325 dim := &Dim{ID: dimID, Name: dimName, Algo: module.Incremental} 326 327 if err := chart.AddDim(dim); err != nil { 328 s.Warningf("add '%s' dim: %v", dimID, err) 329 return 330 } 331 chart.MarkNotCreated() 332 } 333 334 func (s *SquidLog) addDimToChartOrCreateIfNotExist(chartID, dimID, dimName string) { 335 if s.Charts().Has(chartID) { 336 s.addDimToChart(chartID, dimID, dimName) 337 return 338 } 339 340 chart := newChartByID(chartID) 341 if chart == nil { 342 s.Warningf("add '%s' dim: couldn't create '%s' chart", dimID, chartID) 343 return 344 } 345 if err := s.Charts().Add(chart); err != nil { 346 s.Warning(err) 347 return 348 } 349 s.addDimToChart(chartID, dimID, dimName) 350 } 351 352 func newChartByID(chartID string) *Chart { 353 switch chartID { 354 case serverAddrChart.ID: 355 return serverAddrChart.Copy() 356 case mimeTypeChart.ID: 357 return mimeTypeChart.Copy() 358 } 359 return nil 360 }