Last active
October 20, 2023 08:09
-
-
Save tolleiv/a602ecea838f96599fd3e907d173d52e to your computer and use it in GitHub Desktop.
Small utility to extract used metrics from promql queries
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module prom-stat | |
go 1.21.1 | |
require github.com/prometheus/prometheus v0.47.2 | |
require ( | |
github.com/beorn7/perks v1.0.1 // indirect | |
github.com/cespare/xxhash/v2 v2.2.0 // indirect | |
github.com/dennwc/varint v1.0.0 // indirect | |
github.com/go-kit/log v0.2.1 // indirect | |
github.com/go-logfmt/logfmt v0.6.0 // indirect | |
github.com/gogo/protobuf v1.3.2 // indirect | |
github.com/golang/protobuf v1.5.3 // indirect | |
github.com/grafana/regexp v0.0.0-20221122212121-6b5c0a4cb7fd // indirect | |
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect | |
github.com/pkg/errors v0.9.1 // indirect | |
github.com/prometheus/client_golang v1.16.0 // indirect | |
github.com/prometheus/client_model v0.4.0 // indirect | |
github.com/prometheus/common v0.44.0 // indirect | |
github.com/prometheus/procfs v0.11.0 // indirect | |
go.uber.org/atomic v1.11.0 // indirect | |
golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1 // indirect | |
golang.org/x/sys v0.10.0 // indirect | |
google.golang.org/protobuf v1.31.0 // indirect | |
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"bufio" | |
"fmt" | |
"github.com/prometheus/prometheus/promql/parser" | |
"os" | |
) | |
func main() { | |
metricSet := make(map[string]struct{}) // To remove duplicates | |
scanner := bufio.NewScanner(os.Stdin) | |
for scanner.Scan() { | |
line := scanner.Text() | |
extractMetrics(line, metricSet) | |
} | |
if err := scanner.Err(); err != nil { | |
fmt.Println("Error reading from stdin:", err) | |
} | |
for metric := range metricSet { | |
fmt.Println(metric) | |
} | |
} | |
func extractMetrics(query string, metricSet map[string]struct{}) { | |
expr, err := parser.ParseExpr(query) | |
if err != nil { | |
fmt.Printf("Error parsing query: %s, error: %v\n", query, err) | |
return | |
} | |
parser.Inspect(expr, func(node parser.Node, path []parser.Node) error { | |
switch n := node.(type) { | |
case *parser.VectorSelector: | |
metricSet[n.Name] = struct{}{} | |
} | |
return nil | |
}) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import "testing" | |
func TestExtractMetrics(t *testing.T) { | |
tests := []struct { | |
query string | |
expected []string | |
}{ | |
{ | |
query: `max by (name, exported_namespace, namespace, condition) (certmanager_certificate_ready_status{condition!="True"} == 1)`, | |
expected: []string{"certmanager_certificate_ready_status"}, | |
}, | |
{ | |
query: `min by (cluster, namespace, priority, poddisruptionbudget) (kube_poddisruptionbudget_status_pod_disruptions_allowed) == 0`, | |
expected: []string{"kube_poddisruptionbudget_status_pod_disruptions_allowed"}, | |
}, | |
{ | |
query: `sum by (destination_service_name, destination_service_namespace, priority) (rate(istio_requests_total{reporter="source"}[5m]))`, | |
expected: []string{"istio_requests_total"}, | |
}, | |
{ | |
query: `sum without (app_kubernetes_io_name, kubernetes_namespace, annotation_service_bare_id_priority) (label_replace(label_replace(probe_success < 1, "ingress", "$1", "app_kubernetes_io_name", "(.*)"), "namespace", "$1", "kubernetes_namespace", "(.*)") * on (namespace, ingress) group_left (priority) topk by (namespace, ingress) (1, label_replace(kube_ingress_annotations, "priority", "$1", "annotation_service_bare_id_priority", "(.*)")))`, | |
expected: []string{"probe_success", "kube_ingress_annotations"}, | |
}, | |
// ... add more tests as needed | |
} | |
for _, test := range tests { | |
metricSet := make(map[string]struct{}) | |
extractMetrics(test.query, metricSet) | |
if len(metricSet) != len(test.expected) { | |
t.Errorf("Query: %s, Expected %d metrics, got %d", test.query, len(test.expected), len(metricSet)) | |
continue | |
} | |
for _, exp := range test.expected { | |
if _, exists := metricSet[exp]; !exists { | |
t.Errorf("Query: %s, Expected metric %s not found", test.query, exp) | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment