github.com/netdata/go.d.plugin@v0.58.1/modules/haproxy/collect.go (about)

     1  // SPDX-License-Identifier: GPL-3.0-or-later
     2  
     3  package haproxy
     4  
     5  import (
     6  	"errors"
     7  	"strings"
     8  
     9  	"github.com/netdata/go.d.plugin/agent/module"
    10  	"github.com/netdata/go.d.plugin/pkg/prometheus"
    11  )
    12  
    13  const (
    14  	metricBackendSessionsTotal              = "haproxy_backend_sessions_total"
    15  	metricBackendCurrentSessions            = "haproxy_backend_current_sessions"
    16  	metricBackendHTTPResponsesTotal         = "haproxy_backend_http_responses_total"
    17  	metricBackendResponseTimeAverageSeconds = "haproxy_backend_response_time_average_seconds"
    18  	metricBackendCurrentQueue               = "haproxy_backend_current_queue"
    19  	metricBackendQueueTimeAverageSeconds    = "haproxy_backend_queue_time_average_seconds"
    20  	metricBackendBytesInTotal               = "haproxy_backend_bytes_in_total"
    21  	metricBackendBytesOutTotal              = "haproxy_backend_bytes_out_total"
    22  )
    23  
    24  func isHaproxyMetrics(pms prometheus.Series) bool {
    25  	for _, pm := range pms {
    26  		if strings.HasPrefix(pm.Name(), "haproxy_") {
    27  			return true
    28  		}
    29  	}
    30  	return false
    31  }
    32  
    33  func (h *Haproxy) collect() (map[string]int64, error) {
    34  	pms, err := h.prom.ScrapeSeries()
    35  	if err != nil {
    36  		return nil, err
    37  	}
    38  
    39  	if h.validateMetrics && !isHaproxyMetrics(pms) {
    40  		return nil, errors.New("unexpected metrics (not HAProxy)")
    41  	}
    42  	h.validateMetrics = false
    43  
    44  	mx := make(map[string]int64)
    45  	for _, pm := range pms {
    46  		proxy := pm.Labels.Get("proxy")
    47  		if proxy == "" {
    48  			continue
    49  		}
    50  
    51  		if !h.proxies[proxy] {
    52  			h.proxies[proxy] = true
    53  			h.addProxyToCharts(proxy)
    54  		}
    55  
    56  		mx[dimID(pm)] = int64(pm.Value * multiplier(pm))
    57  	}
    58  
    59  	return mx, nil
    60  }
    61  
    62  func (h *Haproxy) addProxyToCharts(proxy string) {
    63  	h.addDimToChart(chartBackendCurrentSessions.ID, &module.Dim{
    64  		ID:   proxyDimID(metricBackendCurrentSessions, proxy),
    65  		Name: proxy,
    66  	})
    67  	h.addDimToChart(chartBackendSessions.ID, &module.Dim{
    68  		ID:   proxyDimID(metricBackendSessionsTotal, proxy),
    69  		Name: proxy,
    70  		Algo: module.Incremental,
    71  	})
    72  
    73  	h.addDimToChart(chartBackendResponseTimeAverage.ID, &module.Dim{
    74  		ID:   proxyDimID(metricBackendResponseTimeAverageSeconds, proxy),
    75  		Name: proxy,
    76  	})
    77  	if err := h.Charts().Add(newChartBackendHTTPResponses(proxy)); err != nil {
    78  		h.Warning(err)
    79  	}
    80  
    81  	h.addDimToChart(chartBackendCurrentQueue.ID, &module.Dim{
    82  		ID:   proxyDimID(metricBackendCurrentQueue, proxy),
    83  		Name: proxy,
    84  	})
    85  	h.addDimToChart(chartBackendQueueTimeAverage.ID, &module.Dim{
    86  		ID:   proxyDimID(metricBackendQueueTimeAverageSeconds, proxy),
    87  		Name: proxy,
    88  	})
    89  
    90  	if err := h.Charts().Add(newChartBackendNetworkIO(proxy)); err != nil {
    91  		h.Warning(err)
    92  	}
    93  }
    94  
    95  func (h *Haproxy) addDimToChart(chartID string, dim *module.Dim) {
    96  	chart := h.Charts().Get(chartID)
    97  	if chart == nil {
    98  		h.Warningf("error on adding '%s' dimension: can not find '%s' chart", dim.ID, chartID)
    99  		return
   100  	}
   101  	if err := chart.AddDim(dim); err != nil {
   102  		h.Warning(err)
   103  		return
   104  	}
   105  	chart.MarkNotCreated()
   106  }
   107  
   108  func multiplier(pm prometheus.SeriesSample) float64 {
   109  	switch pm.Name() {
   110  	case metricBackendResponseTimeAverageSeconds,
   111  		metricBackendQueueTimeAverageSeconds:
   112  		// to milliseconds
   113  		return 1000
   114  	}
   115  	return 1
   116  }
   117  
   118  func dimID(pm prometheus.SeriesSample) string {
   119  	proxy := pm.Labels.Get("proxy")
   120  	if proxy == "" {
   121  		return ""
   122  	}
   123  
   124  	name := cleanMetricName(pm.Name())
   125  	if pm.Name() == metricBackendHTTPResponsesTotal {
   126  		name += "_" + pm.Labels.Get("code")
   127  	}
   128  	return proxyDimID(name, proxy)
   129  }
   130  
   131  func proxyDimID(metric, proxy string) string {
   132  	return cleanMetricName(metric) + "_proxy_" + proxy
   133  }
   134  
   135  func cleanMetricName(name string) string {
   136  	if strings.HasSuffix(name, "_total") {
   137  		return name[:len(name)-6]
   138  	}
   139  	if strings.HasSuffix(name, "_seconds") {
   140  		return name[:len(name)-8]
   141  	}
   142  	return name
   143  }