Welcome to WuJiGu Developer Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
589 views
in Technique[技术] by (71.8m points)

go - Parsing prometheus metrics from file and updating counters

I've a go application that gets run periodically by a batch. Each run, it should read some prometheus metrics from a file, run its logic, update a success/fail counter, and write metrics back out to a file.

From looking at How to parse Prometheus data as well as the godocs for prometheus, I'm able to read in the file, but I don't know how to update app_processed_total with the value returned by expfmt.ExtractSamples().

This is what I've done so far. Could someone please tell me how should I proceed from here? How can I typecast the Vector I got into a CounterVec?

package main

import (
    "fmt"
    "net/http"
    "strings"
    "time"

    "github.com/prometheus/client_golang/prometheus"
    "github.com/prometheus/client_golang/prometheus/promhttp"
    dto "github.com/prometheus/client_model/go"
    "github.com/prometheus/common/expfmt"
    "github.com/prometheus/common/model"
)

var (
    fileOnDisk     = prometheus.NewRegistry()
    processedTotal = prometheus.NewCounterVec(prometheus.CounterOpts{
        Name: "app_processed_total",
        Help: "Number of times ran",
    }, []string{"status"})
)

func doInit() {
    prometheus.MustRegister(processedTotal)
}

func recordMetrics() {
    go func() {
        for {
            processedTotal.With(prometheus.Labels{"status": "ok"}).Inc()
            time.Sleep(5 * time.Second)
        }
    }()
}

func readExistingMetrics() {
    var parser expfmt.TextParser
    text := `
# HELP app_processed_total Number of times ran
# TYPE app_processed_total counter
app_processed_total{status="ok"} 300
`
    parseText := func() ([]*dto.MetricFamily, error) {
        parsed, err := parser.TextToMetricFamilies(strings.NewReader(text))
        if err != nil {
            return nil, err
        }
        var result []*dto.MetricFamily
        for _, mf := range parsed {
            result = append(result, mf)

        }
        return result, nil
    }

    gatherers := prometheus.Gatherers{
        fileOnDisk,
        prometheus.GathererFunc(parseText),
    }

    gathering, err := gatherers.Gather()
    if err != nil {
        fmt.Println(err)
    }

    fmt.Println("gathering: ", gathering)
    for _, g := range gathering {
        vector, err := expfmt.ExtractSamples(&expfmt.DecodeOptions{
            Timestamp: model.Now(),
        }, g)

        fmt.Println("vector: ", vector)
        if err != nil {
            fmt.Println(err)
        }

        // How can I update processedTotal with this new value?
    }

}

func main() {
    doInit()
    readExistingMetrics()
    recordMetrics()

    http.Handle("/metrics", promhttp.Handler())
    http.ListenAndServe("localhost:2112", nil)
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

I believe you would need to use processedTotal.WithLabelValues("ok").Inc() or something similar to that.

The more complete example is here

func ExampleCounterVec() {
    httpReqs := prometheus.NewCounterVec(
        prometheus.CounterOpts{
            Name: "http_requests_total",
            Help: "How many HTTP requests processed, partitioned by status code and HTTP method.",
        },
        []string{"code", "method"},
    )
    prometheus.MustRegister(httpReqs)

    httpReqs.WithLabelValues("404", "POST").Add(42)

    // If you have to access the same set of labels very frequently, it
    // might be good to retrieve the metric only once and keep a handle to
    // it. But beware of deletion of that metric, see below!
    m := httpReqs.WithLabelValues("200", "GET")
    for i := 0; i < 1000000; i++ {
        m.Inc()
    }
    // Delete a metric from the vector. If you have previously kept a handle
    // to that metric (as above), future updates via that handle will go
    // unseen (even if you re-create a metric with the same label set
    // later).
    httpReqs.DeleteLabelValues("200", "GET")
    // Same thing with the more verbose Labels syntax.
    httpReqs.Delete(prometheus.Labels{"method": "GET", "code": "200"})
}

This is taken from the Promethus examples on Github

To use the value of vector you can do the following:

    vectorFloat, err := strconv.ParseFloat(vector[0].Value.String(), 64)
    if err != nil {
        panic(err)
    }

    processedTotal.WithLabelValues("ok").Add(vectorFloat)

This is assuming you will only ever get a single vector value in your response. The value of the vector is stored as a string but you can convert it to a float with the strconv.ParseFloat method.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to WuJiGu Developer Q&A Community for programmer and developer-Open, Learning and Share
...