summaryrefslogtreecommitdiffstats
path: root/src/go/collectors/go.d.plugin/modules/squidlog/collect.go
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/go/collectors/go.d.plugin/modules/squidlog/collect.go360
1 files changed, 360 insertions, 0 deletions
diff --git a/src/go/collectors/go.d.plugin/modules/squidlog/collect.go b/src/go/collectors/go.d.plugin/modules/squidlog/collect.go
new file mode 100644
index 000000000..e0ebb6eb4
--- /dev/null
+++ b/src/go/collectors/go.d.plugin/modules/squidlog/collect.go
@@ -0,0 +1,360 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+package squidlog
+
+import (
+ "io"
+ "runtime"
+ "strconv"
+ "strings"
+
+ "github.com/netdata/netdata/go/go.d.plugin/pkg/logs"
+ "github.com/netdata/netdata/go/go.d.plugin/pkg/stm"
+
+ "github.com/netdata/netdata/go/go.d.plugin/agent/module"
+)
+
+func (s *SquidLog) logPanicStackIfAny() {
+ err := recover()
+ if err == nil {
+ return
+ }
+ s.Errorf("[ERROR] %s\n", err)
+ for depth := 0; ; depth++ {
+ _, file, line, ok := runtime.Caller(depth)
+ if !ok {
+ break
+ }
+ s.Errorf("======> %d: %v:%d", depth, file, line)
+ }
+ panic(err)
+}
+
+func (s *SquidLog) collect() (map[string]int64, error) {
+ defer s.logPanicStackIfAny()
+ s.mx.reset()
+
+ var mx map[string]int64
+
+ n, err := s.collectLogLines()
+
+ if n > 0 || err == nil {
+ mx = stm.ToMap(s.mx)
+ }
+ return mx, err
+}
+
+func (s *SquidLog) collectLogLines() (int, error) {
+ var n int
+ for {
+ s.line.reset()
+ err := s.parser.ReadLine(s.line)
+ if err != nil {
+ if err == io.EOF {
+ return n, nil
+ }
+ if !logs.IsParseError(err) {
+ return n, err
+ }
+ n++
+ s.collectUnmatched()
+ continue
+ }
+ n++
+ if s.line.empty() {
+ s.collectUnmatched()
+ } else {
+ s.collectLogLine()
+ }
+ }
+}
+
+func (s *SquidLog) collectLogLine() {
+ s.mx.Requests.Inc()
+ s.collectRespTime()
+ s.collectClientAddress()
+ s.collectCacheCode()
+ s.collectHTTPCode()
+ s.collectRespSize()
+ s.collectReqMethod()
+ s.collectHierCode()
+ s.collectServerAddress()
+ s.collectMimeType()
+}
+
+func (s *SquidLog) collectUnmatched() {
+ s.mx.Requests.Inc()
+ s.mx.Unmatched.Inc()
+}
+
+func (s *SquidLog) collectRespTime() {
+ if !s.line.hasRespTime() {
+ return
+ }
+ s.mx.RespTime.Observe(float64(s.line.respTime))
+}
+
+func (s *SquidLog) collectClientAddress() {
+ if !s.line.hasClientAddress() {
+ return
+ }
+ s.mx.UniqueClients.Insert(s.line.clientAddr)
+}
+
+func (s *SquidLog) collectCacheCode() {
+ if !s.line.hasCacheCode() {
+ return
+ }
+
+ c, ok := s.mx.CacheCode.GetP(s.line.cacheCode)
+ if !ok {
+ s.addDimToCacheCodeChart(s.line.cacheCode)
+ }
+ c.Inc()
+
+ tags := strings.Split(s.line.cacheCode, "_")
+ for _, tag := range tags {
+ s.collectCacheCodeTag(tag)
+ }
+}
+
+func (s *SquidLog) collectHTTPCode() {
+ if !s.line.hasHTTPCode() {
+ return
+ }
+
+ code := s.line.httpCode
+ switch {
+ case code >= 100 && code < 300, code == 0, code == 304, code == 401:
+ s.mx.ReqSuccess.Inc()
+ case code >= 300 && code < 400:
+ s.mx.ReqRedirect.Inc()
+ case code >= 400 && code < 500:
+ s.mx.ReqBad.Inc()
+ case code >= 500 && code <= 603:
+ s.mx.ReqError.Inc()
+ }
+
+ switch code / 100 {
+ case 0:
+ s.mx.HTTPResp0xx.Inc()
+ case 1:
+ s.mx.HTTPResp1xx.Inc()
+ case 2:
+ s.mx.HTTPResp2xx.Inc()
+ case 3:
+ s.mx.HTTPResp3xx.Inc()
+ case 4:
+ s.mx.HTTPResp4xx.Inc()
+ case 5:
+ s.mx.HTTPResp5xx.Inc()
+ case 6:
+ s.mx.HTTPResp6xx.Inc()
+ }
+
+ codeStr := strconv.Itoa(code)
+ c, ok := s.mx.HTTPRespCode.GetP(codeStr)
+ if !ok {
+ s.addDimToHTTPRespCodesChart(codeStr)
+ }
+ c.Inc()
+}
+
+func (s *SquidLog) collectRespSize() {
+ if !s.line.hasRespSize() {
+ return
+ }
+ s.mx.BytesSent.Add(float64(s.line.respSize))
+}
+
+func (s *SquidLog) collectReqMethod() {
+ if !s.line.hasReqMethod() {
+ return
+ }
+ c, ok := s.mx.ReqMethod.GetP(s.line.reqMethod)
+ if !ok {
+ s.addDimToReqMethodChart(s.line.reqMethod)
+ }
+ c.Inc()
+}
+
+func (s *SquidLog) collectHierCode() {
+ if !s.line.hasHierCode() {
+ return
+ }
+ c, ok := s.mx.HierCode.GetP(s.line.hierCode)
+ if !ok {
+ s.addDimToHierCodeChart(s.line.hierCode)
+ }
+ c.Inc()
+}
+
+func (s *SquidLog) collectServerAddress() {
+ if !s.line.hasServerAddress() {
+ return
+ }
+ c, ok := s.mx.Server.GetP(s.line.serverAddr)
+ if !ok {
+ s.addDimToServerAddressChart(s.line.serverAddr)
+ }
+ c.Inc()
+}
+
+func (s *SquidLog) collectMimeType() {
+ if !s.line.hasMimeType() {
+ return
+ }
+ c, ok := s.mx.MimeType.GetP(s.line.mimeType)
+ if !ok {
+ s.addDimToMimeTypeChart(s.line.mimeType)
+ }
+ c.Inc()
+}
+
+func (s *SquidLog) collectCacheCodeTag(tag string) {
+ // https://wiki.squid-cache.org/SquidFaq/SquidLogs#Squid_result_codes
+ switch tag {
+ default:
+ case "TCP", "UDP", "NONE":
+ c, ok := s.mx.CacheCodeTransportTag.GetP(tag)
+ if !ok {
+ s.addDimToCacheCodeTransportTagChart(tag)
+ }
+ c.Inc()
+ case "CF", "CLIENT", "IMS", "ASYNC", "SWAPFAIL", "REFRESH", "SHARED", "REPLY":
+ c, ok := s.mx.CacheCodeHandlingTag.GetP(tag)
+ if !ok {
+ s.addDimToCacheCodeHandlingTagChart(tag)
+ }
+ c.Inc()
+ case "NEGATIVE", "STALE", "OFFLINE", "INVALID", "FAIL", "MODIFIED", "UNMODIFIED", "REDIRECT":
+ c, ok := s.mx.CacheCodeObjectTag.GetP(tag)
+ if !ok {
+ s.addDimToCacheCodeObjectTagChart(tag)
+ }
+ c.Inc()
+ case "HIT", "MEM", "MISS", "DENIED", "NOFETCH", "TUNNEL":
+ c, ok := s.mx.CacheCodeLoadSourceTag.GetP(tag)
+ if !ok {
+ s.addDimToCacheCodeLoadSourceTagChart(tag)
+ }
+ c.Inc()
+ case "ABORTED", "TIMEOUT", "IGNORED":
+ c, ok := s.mx.CacheCodeErrorTag.GetP(tag)
+ if !ok {
+ s.addDimToCacheCodeErrorTagChart(tag)
+ }
+ c.Inc()
+ }
+}
+
+func (s *SquidLog) addDimToCacheCodeChart(code string) {
+ chartID := cacheCodeChart.ID
+ dimID := pxCacheCode + code
+ s.addDimToChart(chartID, dimID, code)
+}
+
+func (s *SquidLog) addDimToCacheCodeTransportTagChart(tag string) {
+ chartID := cacheCodeTransportTagChart.ID
+ dimID := pxTransportTag + tag
+ s.addDimToChart(chartID, dimID, tag)
+}
+
+func (s *SquidLog) addDimToCacheCodeHandlingTagChart(tag string) {
+ chartID := cacheCodeHandlingTagChart.ID
+ dimID := pxHandlingTag + tag
+ s.addDimToChart(chartID, dimID, tag)
+}
+
+func (s *SquidLog) addDimToCacheCodeObjectTagChart(tag string) {
+ chartID := cacheCodeObjectTagChart.ID
+ dimID := pxObjectTag + tag
+ s.addDimToChart(chartID, dimID, tag)
+}
+
+func (s *SquidLog) addDimToCacheCodeLoadSourceTagChart(tag string) {
+ chartID := cacheCodeLoadSourceTagChart.ID
+ dimID := pxSourceTag + tag
+ s.addDimToChart(chartID, dimID, tag)
+}
+
+func (s *SquidLog) addDimToCacheCodeErrorTagChart(tag string) {
+ chartID := cacheCodeErrorTagChart.ID
+ dimID := pxErrorTag + tag
+ s.addDimToChart(chartID, dimID, tag)
+}
+
+func (s *SquidLog) addDimToHTTPRespCodesChart(tag string) {
+ chartID := httpRespCodesChart.ID
+ dimID := pxHTTPCode + tag
+ s.addDimToChart(chartID, dimID, tag)
+}
+
+func (s *SquidLog) addDimToReqMethodChart(method string) {
+ chartID := reqMethodChart.ID
+ dimID := pxReqMethod + method
+ s.addDimToChart(chartID, dimID, method)
+}
+
+func (s *SquidLog) addDimToHierCodeChart(code string) {
+ chartID := hierCodeChart.ID
+ dimID := pxHierCode + code
+ dimName := code[5:] // remove "HIER_"
+ s.addDimToChart(chartID, dimID, dimName)
+}
+
+func (s *SquidLog) addDimToServerAddressChart(address string) {
+ chartID := serverAddrChart.ID
+ dimID := pxSrvAddr + address
+ s.addDimToChartOrCreateIfNotExist(chartID, dimID, address)
+}
+
+func (s *SquidLog) addDimToMimeTypeChart(mimeType string) {
+ chartID := mimeTypeChart.ID
+ dimID := pxMimeType + mimeType
+ s.addDimToChartOrCreateIfNotExist(chartID, dimID, mimeType)
+}
+
+func (s *SquidLog) addDimToChart(chartID, dimID, dimName string) {
+ chart := s.Charts().Get(chartID)
+ if chart == nil {
+ s.Warningf("add '%s' dim: couldn't find '%s' chart in charts", dimID, chartID)
+ return
+ }
+
+ dim := &Dim{ID: dimID, Name: dimName, Algo: module.Incremental}
+
+ if err := chart.AddDim(dim); err != nil {
+ s.Warningf("add '%s' dim: %v", dimID, err)
+ return
+ }
+ chart.MarkNotCreated()
+}
+
+func (s *SquidLog) addDimToChartOrCreateIfNotExist(chartID, dimID, dimName string) {
+ if s.Charts().Has(chartID) {
+ s.addDimToChart(chartID, dimID, dimName)
+ return
+ }
+
+ chart := newChartByID(chartID)
+ if chart == nil {
+ s.Warningf("add '%s' dim: couldn't create '%s' chart", dimID, chartID)
+ return
+ }
+ if err := s.Charts().Add(chart); err != nil {
+ s.Warning(err)
+ return
+ }
+ s.addDimToChart(chartID, dimID, dimName)
+}
+
+func newChartByID(chartID string) *Chart {
+ switch chartID {
+ case serverAddrChart.ID:
+ return serverAddrChart.Copy()
+ case mimeTypeChart.ID:
+ return mimeTypeChart.Copy()
+ }
+ return nil
+}