summaryrefslogtreecommitdiffstats
path: root/src/go/collectors/go.d.plugin/modules/prometheus/charts.go
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/go/collectors/go.d.plugin/modules/prometheus/charts.go302
1 files changed, 302 insertions, 0 deletions
diff --git a/src/go/collectors/go.d.plugin/modules/prometheus/charts.go b/src/go/collectors/go.d.plugin/modules/prometheus/charts.go
new file mode 100644
index 000000000..61e8031d7
--- /dev/null
+++ b/src/go/collectors/go.d.plugin/modules/prometheus/charts.go
@@ -0,0 +1,302 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+package prometheus
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/netdata/netdata/go/go.d.plugin/agent/module"
+ "github.com/netdata/netdata/go/go.d.plugin/pkg/prometheus"
+
+ "github.com/prometheus/prometheus/model/labels"
+)
+
+const (
+ prioDefault = module.Priority
+ prioGORuntime = prioDefault + 10
+)
+
+func (p *Prometheus) addGaugeChart(id, name, help string, labels labels.Labels) {
+ units := getChartUnits(name)
+
+ cType := module.Line
+ if strings.HasSuffix(units, "bytes") {
+ cType = module.Area
+ }
+
+ chart := &module.Chart{
+ ID: id,
+ Title: getChartTitle(name, help),
+ Units: units,
+ Fam: getChartFamily(name),
+ Ctx: getChartContext(p.application(), name),
+ Type: cType,
+ Priority: getChartPriority(name),
+ Dims: module.Dims{
+ {ID: id, Name: name, Div: precision},
+ },
+ }
+
+ for _, lbl := range labels {
+ chart.Labels = append(chart.Labels,
+ module.Label{Key: lbl.Name, Value: lbl.Value},
+ )
+ }
+
+ if err := p.Charts().Add(chart); err != nil {
+ p.Warning(err)
+ return
+ }
+
+ p.cache.addChart(id, chart)
+}
+
+func (p *Prometheus) addCounterChart(id, name, help string, labels labels.Labels) {
+ units := getChartUnits(name)
+
+ switch units {
+ case "seconds", "time":
+ default:
+ units += "/s"
+ }
+
+ cType := module.Line
+ if strings.HasSuffix(units, "bytes/s") {
+ cType = module.Area
+ }
+
+ chart := &module.Chart{
+ ID: id,
+ Title: getChartTitle(name, help),
+ Units: units,
+ Fam: getChartFamily(name),
+ Ctx: getChartContext(p.application(), name),
+ Type: cType,
+ Priority: getChartPriority(name),
+ Dims: module.Dims{
+ {ID: id, Name: name, Algo: module.Incremental, Div: precision},
+ },
+ }
+ for _, lbl := range labels {
+ chart.Labels = append(chart.Labels,
+ module.Label{Key: lbl.Name, Value: lbl.Value},
+ )
+ }
+
+ if err := p.Charts().Add(chart); err != nil {
+ p.Warning(err)
+ return
+ }
+
+ p.cache.addChart(id, chart)
+}
+
+func (p *Prometheus) addSummaryCharts(id, name, help string, labels labels.Labels, quantiles []prometheus.Quantile) {
+ units := getChartUnits(name)
+
+ switch units {
+ case "seconds", "time":
+ default:
+ units += "/s"
+ }
+
+ charts := module.Charts{
+ {
+ ID: id,
+ Title: getChartTitle(name, help),
+ Units: units,
+ Fam: getChartFamily(name),
+ Ctx: getChartContext(p.application(), name),
+ Priority: getChartPriority(name),
+ Dims: func() (dims module.Dims) {
+ for _, v := range quantiles {
+ s := formatFloat(v.Quantile())
+ dims = append(dims, &module.Dim{
+ ID: fmt.Sprintf("%s_quantile=%s", id, s),
+ Name: fmt.Sprintf("quantile_%s", s),
+ Div: precision * precision,
+ })
+ }
+ return dims
+ }(),
+ },
+ {
+ ID: id + "_sum",
+ Title: getChartTitle(name, help),
+ Units: units,
+ Fam: getChartFamily(name),
+ Ctx: getChartContext(p.application(), name) + "_sum",
+ Priority: getChartPriority(name),
+ Dims: module.Dims{
+ {ID: id + "_sum", Name: name + "_sum", Algo: module.Incremental, Div: precision},
+ },
+ },
+ {
+ ID: id + "_count",
+ Title: getChartTitle(name, help),
+ Units: "events/s",
+ Fam: getChartFamily(name),
+ Ctx: getChartContext(p.application(), name) + "_count",
+ Priority: getChartPriority(name),
+ Dims: module.Dims{
+ {ID: id + "_count", Name: name + "_count", Algo: module.Incremental},
+ },
+ },
+ }
+
+ for _, chart := range charts {
+ for _, lbl := range labels {
+ chart.Labels = append(chart.Labels, module.Label{Key: lbl.Name, Value: lbl.Value})
+ }
+ if err := p.Charts().Add(chart); err != nil {
+ p.Warning(err)
+ continue
+ }
+ p.cache.addChart(id, chart)
+ }
+}
+
+func (p *Prometheus) addHistogramCharts(id, name, help string, labels labels.Labels, buckets []prometheus.Bucket) {
+ units := getChartUnits(name)
+
+ switch units {
+ case "seconds", "time":
+ default:
+ units += "/s"
+ }
+
+ charts := module.Charts{
+ {
+ ID: id,
+ Title: getChartTitle(name, help),
+ Units: "observations/s",
+ Fam: getChartFamily(name),
+ Ctx: getChartContext(p.application(), name),
+ Priority: getChartPriority(name),
+ Dims: func() (dims module.Dims) {
+ for _, v := range buckets {
+ s := formatFloat(v.UpperBound())
+ dims = append(dims, &module.Dim{
+ ID: fmt.Sprintf("%s_bucket=%s", id, s),
+ Name: fmt.Sprintf("bucket_%s", s),
+ Algo: module.Incremental,
+ })
+ }
+ return dims
+ }(),
+ },
+ {
+ ID: id + "_sum",
+ Title: getChartTitle(name, help),
+ Units: units,
+ Fam: getChartFamily(name),
+ Ctx: getChartContext(p.application(), name) + "_sum",
+ Priority: getChartPriority(name),
+ Dims: module.Dims{
+ {ID: id + "_sum", Name: name + "_sum", Algo: module.Incremental, Div: precision},
+ },
+ },
+ {
+ ID: id + "_count",
+ Title: getChartTitle(name, help),
+ Units: "events/s",
+ Fam: getChartFamily(name),
+ Ctx: getChartContext(p.application(), name) + "_count",
+ Priority: getChartPriority(name),
+ Dims: module.Dims{
+ {ID: id + "_count", Name: name + "_count", Algo: module.Incremental},
+ },
+ },
+ }
+
+ for _, chart := range charts {
+ for _, lbl := range labels {
+ chart.Labels = append(chart.Labels, module.Label{Key: lbl.Name, Value: lbl.Value})
+ }
+ if err := p.Charts().Add(chart); err != nil {
+ p.Warning(err)
+ continue
+ }
+ p.cache.addChart(id, chart)
+ }
+}
+
+func (p *Prometheus) application() string {
+ if p.Application != "" {
+ return p.Application
+ }
+ return p.Name
+}
+
+func getChartTitle(name, help string) string {
+ if help == "" {
+ return fmt.Sprintf("Metric \"%s\"", name)
+ }
+
+ help = strings.Replace(help, "'", "", -1)
+ help = strings.TrimSuffix(help, ".")
+
+ return help
+}
+
+func getChartContext(app, name string) string {
+ if app == "" {
+ return fmt.Sprintf("prometheus.%s", name)
+ }
+ return fmt.Sprintf("prometheus.%s.%s", app, name)
+}
+
+func getChartFamily(metric string) (fam string) {
+ if strings.HasPrefix(metric, "go_") {
+ return "go"
+ }
+ if strings.HasPrefix(metric, "process_") {
+ return "process"
+ }
+ if parts := strings.SplitN(metric, "_", 3); len(parts) < 3 {
+ fam = metric
+ } else {
+ fam = parts[0] + "_" + parts[1]
+ }
+
+ // remove number suffix if any
+ // load1, load5, load15 => load
+ i := len(fam) - 1
+ for i >= 0 && fam[i] >= '0' && fam[i] <= '9' {
+ i--
+ }
+ if i > 0 {
+ return fam[:i+1]
+ }
+ return fam
+}
+
+func getChartUnits(metric string) string {
+ // https://prometheus.io/docs/practices/naming/#metric-names
+ // ...must have a single unit (i.e. do not mix seconds with milliseconds, or seconds with bytes).
+ // ...should have a suffix describing the unit, in plural form.
+ // Note that an accumulating count has total as a suffix, in addition to the unit if applicable
+
+ idx := strings.LastIndexByte(metric, '_')
+ if idx == -1 {
+ return "events"
+ }
+ switch suffix := metric[idx:]; suffix {
+ case "_total", "_sum", "_count":
+ return getChartUnits(metric[:idx])
+ }
+ switch units := metric[idx+1:]; units {
+ case "hertz":
+ return "Hz"
+ default:
+ return units
+ }
+}
+
+func getChartPriority(name string) int {
+ if strings.HasPrefix(name, "go_") || strings.HasPrefix(name, "process_") {
+ return prioGORuntime
+ }
+ return prioDefault
+}