Rachel A
Rachel A

Reputation: 33

Transform Prometheus Metrics to Json with Golang

I have prometgeus metrics and I want to convert it to json format using golang. I wrote some code but without success.

For example: Prometheus Metric:

# TYPE http_requests_total counter 
http_requests_total{code="200",method="GET"} 28 
http_requests_total{code="200",method="POST"} 3

The JSON I want to convert:

{
    "http_requests_total": [
        {
            "http_requests_total": {
                "code": "200",
                "method": "GET",
                "value": 28
            }
        },
        {
            "http_requests_total": {
                "code": "200",
                "method": "POST",
                "value": 3
            }
        }
    ]
}

Upvotes: 2

Views: 972

Answers (1)

nj_
nj_

Reputation: 2339

I'm assuming you're looking for this to be flexible, i.e. not just handling those specific metrics? If so, the following code should do the trick.

package main

import (
    "encoding/json"
    "fmt"
    "log"
    "os"
    "strings"

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

func main() {
    if err := run(); err != nil {
        log.Fatal(err)
    }
}

func run() error {
    str := `# TYPE http_requests_total counter
http_requests_total{code="200",method="GET"} 28
http_requests_total{code="200",method="POST"} 3
`

    parser := &expfmt.TextParser{}
    families, err := parser.TextToMetricFamilies(strings.NewReader(str))
    if err != nil {
        return fmt.Errorf("failed to parse input: %w", err)
    }

    out := make(map[string][]map[string]map[string]any)

    for key, val := range families {
        family := out[key]

        for _, m := range val.GetMetric() {
            metric := make(map[string]any)
            for _, label := range m.GetLabel() {
                metric[label.GetName()] = label.GetValue()
            }
            switch val.GetType() {
            case dto.MetricType_COUNTER:
                metric["value"] = m.GetCounter().GetValue()
            case dto.MetricType_GAUGE:
                metric["value"] = m.GetGauge().GetValue()
            default:
                return fmt.Errorf("unsupported type: %v", val.GetType())
            }
            family = append(family, map[string]map[string]any{
                val.GetName(): metric,
            })
        }

        out[key] = family
    }

    enc := json.NewEncoder(os.Stdout)
    enc.SetIndent("", "    ")
    if err = enc.Encode(out); err != nil {
        return fmt.Errorf("failed to encode json: %w", err)
    }

    return nil
}

Output:

{
    "http_requests_total": [
        {
            "http_requests_total": {
                "code": "200",
                "method": "GET",
                "value": 28
            }
        },
        {
            "http_requests_total": {
                "code": "200",
                "method": "POST",
                "value": 3
            }
        }
    ]
}

Upvotes: 1

Related Questions