Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Adding label to golang prometheus collector

Tags:

go

prometheus

I'm trying to figure out how to add a label to a prometheus collector. Any ideas what I'm missing here? I have two files: main.go and collector.go

I used the following link as a guide. https://rsmitty.github.io/Prometheus-Exporters/

I mocked up this example, so I could post it here. I'm ultimately not going to pull "date +%s" for the command. Just can't figure out where to add labels.

For the label I'm trying to add a hostname, so I have a result like:

# HELP cmd_result Shows the cmd result
# TYPE cmd_result gauge
cmd_result{host="my_device_hostname"} 1.919256141363144e-76

I'm also really new to golang, so there is a good chance I'm going about this all wrong! I'm ultimately trying to get prometheus to pull the cmd result on each scrape.

main.go

package main

import (
    "net/http"

    log "github.com/Sirupsen/logrus"
    "github.com/prometheus/client_golang/prometheus"
    "github.com/prometheus/client_golang/prometheus/promhttp"
)

func main() {

    //Create a new instance of the collector and
    //register it with the prometheus client.
    cmd := newCollector()
    prometheus.MustRegister(cmd)

    //This section will start the HTTP server and expose
    //any metrics on the /metrics endpoint.
    http.Handle("/metrics", promhttp.Handler())
    log.Info("Beginning to serve on port :8080")
    log.Fatal(http.ListenAndServe(":8080", nil))
}

collector.go

package main

import (
    "encoding/binary"
    "fmt"
    "math"
    "os/exec"
    "strings"

    "github.com/prometheus/client_golang/prometheus"
)

type cmdCollector struct {
    cmdMetric *prometheus.Desc
}

func newCollector() *cmdCollector {
    return &cmdCollector{
        cmdMetric: prometheus.NewDesc("cmd_result",
            "Shows the cmd result",
            nil, nil,
        ),
    }
}

func (collector *cmdCollector) Describe(ch chan<- *prometheus.Desc) {
    ch <- collector.cmdMetric
}

func (collector *cmdCollector) Collect(ch chan<- prometheus.Metric) {

    var metricValue float64
    command := string("date +%s")
    cmdResult := exeCmd(command)
    metricValue = cmdResult

    ch <- prometheus.MustNewConstMetric(collector.cmdMetric, prometheus.GaugeValue, metricValue)

}

func exeCmd(cmd string) float64 {
    parts := strings.Fields(cmd)
    out, err := exec.Command(parts[0], parts[1]).Output()
    if err != nil {
        fmt.Println("error occured")
        fmt.Printf("%s", err)
    }
    cmdProcessResult := Float64frombytes(out)
    return cmdProcessResult
}

func Float64frombytes(bytes []byte) float64 {
    bits := binary.LittleEndian.Uint64(bytes)
    float := math.Float64frombits(bits)
    return float
}
like image 993
mrquatsch Avatar asked Oct 26 '18 23:10

mrquatsch


People also ask

How do I add labels to Prometheus metrics?

Unfortunately, it is not possible to change the labels on old metrics in Prometheus. The storage is only updated by new scrapes and then it becomes immutable.

What is label in Prometheus?

A label is a certain attribute of a metric. Generally, labels are populated by metric producers (servers in the example above). However, in Prometheus, it's possible to enrich a metric with some static labels based on the producer's identity while recording it on the Prometheus node's side.

Can Prometheus labels have spaces?

Prometheus collector does not handle spaces in label values #1472.


1 Answers

I figured it out. I had to declare the label where I was calling the NewDesc method and then pass the value within the MustNewConstMetric method

Here is my new "newCollector" with the "hostname" label.

func newCollector() *cmdCollector {
    return &cmdCollector{
        cmdMetric: prometheus.NewDesc("cmd_result",
            "Shows the cmd result",
            []string{"hostname"}, nil,
        ),
    }
}

It's worth noting that I'm only adding "variable labels" here. That last 'nil' is for constant labels.

You can add any number of items like so...

[]string{"hostname", "another_label", "and_another_label"}

This is covered here: https://godoc.org/github.com/prometheus/client_golang/prometheus#NewDesc

Next I can add those values when calling the "MustNewConstMetric" method.

ch <- prometheus.MustNewConstMetric(collector.cmdMetric, prometheus.GaugeValue, metricValue, hostname)

The whole block...

func (collector *cmdCollector) Collect(ch chan<- prometheus.Metric) {

    var metricValue float64
    command := string("date +%s")
    cmdResult := exeCmd(command)
    metricValue = cmdResult

    ch <- prometheus.MustNewConstMetric(collector.cmdMetric, prometheus.GaugeValue, metricValue, hostname)

}

If I was passing in multiple labels; such as my example above, it would look more like this...

ch <- prometheus.MustNewConstMetric(collector.cmdMetric, prometheus.GaugeValue, metricValue, hostname, anotherLabel", "andAnotherLabel)

This is covered here: https://godoc.org/github.com/prometheus/client_golang/prometheus#MustNewConstMetric

like image 186
mrquatsch Avatar answered Sep 28 '22 06:09

mrquatsch