master
go 125 lines 3.27 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 package prometheus
4
5 import (
6 "fmt"
7 "strings"
8
9 "github.com/netdata/netdata/go/plugins/plugin/framework/collectorapi"
10 commonmodel "github.com/prometheus/common/model"
11 )
12
13 const (
14 prioDefault = collectorapi.Priority
15 prioGORuntime = prioDefault + 10
16 )
17
18 // application is the "app" segment of a chart context: the configured Application, else
19 // the job Name. It selects the per-job chart-template namespace ("prometheus" when empty,
20 // else "prometheus.<app>").
21 func (c *Collector) application() string {
22 if c.Application != "" {
23 return c.Application
24 }
25 return c.Name
26 }
27
28 // getChartTitle derives a chart title (description) from the metric HELP, falling back to
29 // the metric name when HELP is absent. It is fed into the metrix instrument meta so
30 // chartengine autogen reproduces the V1 chart title.
31 func getChartTitle(name, help string) string {
32 if help == "" {
33 return fmt.Sprintf("Metric \"%s\"", name)
34 }
35
36 help = strings.ReplaceAll(help, "'", "")
37 help = strings.TrimSuffix(help, ".")
38
39 return help
40 }
41
42 func getChartFamily(name string) (fam string) {
43 if strings.HasPrefix(name, "go_") {
44 return "go"
45 }
46 if strings.HasPrefix(name, "process_") {
47 return "process"
48 }
49 if parts := strings.SplitN(name, "_", 3); len(parts) < 3 {
50 fam = name
51 } else {
52 fam = parts[0] + "_" + parts[1]
53 }
54
55 // remove number suffix if any
56 // load1, load5, load15 => load
57 i := len(fam) - 1
58 for i >= 0 && fam[i] >= '0' && fam[i] <= '9' {
59 i--
60 }
61 if i > 0 {
62 return fam[:i+1]
63 }
64 return fam
65 }
66
67 func getChartUnits(name string) string {
68 // https://prometheus.io/docs/practices/naming/#metric-names
69 // ...must have a single unit (i.e. do not mix seconds with milliseconds, or seconds with bytes).
70 // ...should have a suffix describing the unit, in plural form.
71 // Note that an accumulating count has total as a suffix, in addition to the unit if applicable
72
73 idx := strings.LastIndexByte(name, '_')
74 if idx == -1 {
75 // snmp_exporter: e.g. ifOutUcastPkts, ifOutOctets.
76 if idx = strings.LastIndexFunc(name, func(r rune) bool { return r >= 'A' && r <= 'Z' }); idx != -1 {
77 v := strings.ToLower(name[idx:])
78 switch v {
79 case "pkts":
80 return "packets"
81 case "octets":
82 return "bytes"
83 case "mtu":
84 return "octets"
85 case "speed":
86 return "bits"
87 }
88 return v
89 }
90 return "events"
91 }
92 switch suffix := name[idx:]; suffix {
93 case "_total", "_sum", "_count", "_ratio":
94 return getChartUnits(name[:idx])
95 }
96 switch units := name[idx+1:]; units {
97 case "hertz":
98 return "Hz"
99 default:
100 return units
101 }
102 }
103
104 // instrumentUnit returns the chart unit metrix should carry for a family. V1 appends "/s" to summary
105 // quantile units (except seconds/time). chartengine autogen adds "/s" itself for the incremental
106 // counter/_sum routes but uses the unit as-is for the absolute summary-quantile route, so the writer
107 // must add it for summaries; gauges/counters/histograms pass the base unit.
108 func instrumentUnit(name string, typ commonmodel.MetricType) string {
109 unit := getChartUnits(name)
110 if typ == commonmodel.MetricTypeSummary {
111 switch unit {
112 case "seconds", "time":
113 default:
114 unit += "/s"
115 }
116 }
117 return unit
118 }
119
120 func getChartPriority(name string) int {
121 if strings.HasPrefix(name, "go_") || strings.HasPrefix(name, "process_") {
122 return prioGORuntime
123 }
124 return prioDefault
125 }