netdata/netdata

View on GitHub
src/go/collectors/go.d.plugin/modules/weblog/metrics.go

Summary

Maintainability
A
0 mins
Test Coverage
// SPDX-License-Identifier: GPL-3.0-or-later

package weblog

import (
    "github.com/netdata/netdata/go/go.d.plugin/pkg/metrics"
)

func newWebLogSummary() metrics.Summary {
    return &weblogSummary{metrics.NewSummary()}
}

type weblogSummary struct {
    metrics.Summary
}

// WriteTo redefines metrics.Summary.WriteTo
// TODO: temporary workaround?
func (s weblogSummary) WriteTo(rv map[string]int64, key string, mul, div int) {
    s.Summary.WriteTo(rv, key, mul, div)
    if _, ok := rv[key+"_min"]; !ok {
        rv[key+"_min"] = 0
        rv[key+"_max"] = 0
        rv[key+"_avg"] = 0
    }
}

type (
    metricsData struct {
        Requests     metrics.Counter `stm:"requests"`
        ReqUnmatched metrics.Counter `stm:"req_unmatched"`

        RespCode metrics.CounterVec `stm:"resp_code"`
        Resp1xx  metrics.Counter    `stm:"resp_1xx"`
        Resp2xx  metrics.Counter    `stm:"resp_2xx"`
        Resp3xx  metrics.Counter    `stm:"resp_3xx"`
        Resp4xx  metrics.Counter    `stm:"resp_4xx"`
        Resp5xx  metrics.Counter    `stm:"resp_5xx"`

        ReqSuccess  metrics.Counter `stm:"req_type_success"`
        ReqRedirect metrics.Counter `stm:"req_type_redirect"`
        ReqBad      metrics.Counter `stm:"req_type_bad"`
        ReqError    metrics.Counter `stm:"req_type_error"`

        UniqueIPv4      metrics.UniqueCounter `stm:"uniq_ipv4"`
        UniqueIPv6      metrics.UniqueCounter `stm:"uniq_ipv6"`
        BytesSent       metrics.Counter       `stm:"bytes_sent"`
        BytesReceived   metrics.Counter       `stm:"bytes_received"`
        ReqProcTime     metrics.Summary       `stm:"req_proc_time"`
        ReqProcTimeHist metrics.Histogram     `stm:"req_proc_time_hist"`
        UpsRespTime     metrics.Summary       `stm:"upstream_resp_time"`
        UpsRespTimeHist metrics.Histogram     `stm:"upstream_resp_time_hist"`

        ReqVhost          metrics.CounterVec `stm:"req_vhost"`
        ReqPort           metrics.CounterVec `stm:"req_port"`
        ReqMethod         metrics.CounterVec `stm:"req_method"`
        ReqURLPattern     metrics.CounterVec `stm:"req_url_ptn"`
        ReqVersion        metrics.CounterVec `stm:"req_version"`
        ReqSSLProto       metrics.CounterVec `stm:"req_ssl_proto"`
        ReqSSLCipherSuite metrics.CounterVec `stm:"req_ssl_cipher_suite"`
        ReqHTTPScheme     metrics.Counter    `stm:"req_http_scheme"`
        ReqHTTPSScheme    metrics.Counter    `stm:"req_https_scheme"`
        ReqIPv4           metrics.Counter    `stm:"req_ipv4"`
        ReqIPv6           metrics.Counter    `stm:"req_ipv6"`

        ReqCustomField  map[string]metrics.CounterVec `stm:"custom_field"`
        URLPatternStats map[string]*patternMetrics    `stm:"url_ptn"`

        ReqCustomTimeField    map[string]*customTimeFieldMetrics    `stm:"custom_time_field"`
        ReqCustomNumericField map[string]*customNumericFieldMetrics `stm:"custom_numeric_field"`
    }
    customTimeFieldMetrics struct {
        Time     metrics.Summary   `stm:"time"`
        TimeHist metrics.Histogram `stm:"time_hist"`
    }
    customNumericFieldMetrics struct {
        Summary metrics.Summary `stm:"summary"`

        multiplier int
        divisor    int
    }
    patternMetrics struct {
        RespCode      metrics.CounterVec `stm:"resp_code"`
        ReqMethod     metrics.CounterVec `stm:"req_method"`
        BytesSent     metrics.Counter    `stm:"bytes_sent"`
        BytesReceived metrics.Counter    `stm:"bytes_received"`
        ReqProcTime   metrics.Summary    `stm:"req_proc_time"`
    }
)

func newMetricsData(config Config) *metricsData {
    return &metricsData{
        ReqVhost:              metrics.NewCounterVec(),
        ReqPort:               metrics.NewCounterVec(),
        ReqMethod:             metrics.NewCounterVec(),
        ReqVersion:            metrics.NewCounterVec(),
        RespCode:              metrics.NewCounterVec(),
        ReqSSLProto:           metrics.NewCounterVec(),
        ReqSSLCipherSuite:     metrics.NewCounterVec(),
        ReqProcTime:           newWebLogSummary(),
        ReqProcTimeHist:       metrics.NewHistogram(convHistOptionsToMicroseconds(config.Histogram)),
        UpsRespTime:           newWebLogSummary(),
        UpsRespTimeHist:       metrics.NewHistogram(convHistOptionsToMicroseconds(config.Histogram)),
        UniqueIPv4:            metrics.NewUniqueCounter(true),
        UniqueIPv6:            metrics.NewUniqueCounter(true),
        ReqURLPattern:         newCounterVecFromPatterns(config.URLPatterns),
        ReqCustomField:        newReqCustomField(config.CustomFields),
        URLPatternStats:       newURLPatternStats(config.URLPatterns),
        ReqCustomTimeField:    newReqCustomTimeField(config.CustomTimeFields),
        ReqCustomNumericField: newReqCustomNumericField(config.CustomNumericFields),
    }
}

func (m *metricsData) reset() {
    m.UniqueIPv4.Reset()
    m.UniqueIPv6.Reset()
    m.ReqProcTime.Reset()
    m.UpsRespTime.Reset()
    for _, v := range m.URLPatternStats {
        v.ReqProcTime.Reset()
    }
    for _, v := range m.ReqCustomTimeField {
        v.Time.Reset()
    }
    for _, v := range m.ReqCustomNumericField {
        v.Summary.Reset()
    }
}

func newCounterVecFromPatterns(patterns []userPattern) metrics.CounterVec {
    c := metrics.NewCounterVec()
    for _, p := range patterns {
        _, _ = c.GetP(p.Name)
    }
    return c
}

func newURLPatternStats(patterns []userPattern) map[string]*patternMetrics {
    stats := make(map[string]*patternMetrics)
    for _, p := range patterns {
        stats[p.Name] = &patternMetrics{
            RespCode:    metrics.NewCounterVec(),
            ReqMethod:   metrics.NewCounterVec(),
            ReqProcTime: newWebLogSummary(),
        }
    }
    return stats
}

func newReqCustomField(fields []customField) map[string]metrics.CounterVec {
    cf := make(map[string]metrics.CounterVec)
    for _, f := range fields {
        cf[f.Name] = newCounterVecFromPatterns(f.Patterns)
    }
    return cf
}

func newReqCustomTimeField(fields []customTimeField) map[string]*customTimeFieldMetrics {
    cf := make(map[string]*customTimeFieldMetrics)
    for _, f := range fields {
        cf[f.Name] = &customTimeFieldMetrics{
            Time:     newWebLogSummary(),
            TimeHist: metrics.NewHistogram(convHistOptionsToMicroseconds(f.Histogram)),
        }
    }
    return cf
}

func newReqCustomNumericField(fields []customNumericField) map[string]*customNumericFieldMetrics {
    rv := make(map[string]*customNumericFieldMetrics)
    for _, f := range fields {
        rv[f.Name] = &customNumericFieldMetrics{
            Summary:    newWebLogSummary(),
            multiplier: f.Multiplier,
            divisor:    f.Divisor,
        }
    }
    return rv
}

// convert histogram options to microseconds (second => us)
func convHistOptionsToMicroseconds(histogram []float64) []float64 {
    var buckets []float64
    for _, value := range histogram {
        buckets = append(buckets, value*1e6)
    }
    return buckets
}