Created
September 18, 2025 17:50
-
-
Save Daniel-W-Innes/b1e252f95958b9546c1eee935425dd75 to your computer and use it in GitHub Desktop.
This file contains hidden or 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 ( | |
"encoding/json" | |
"flag" | |
"fmt" | |
"log" | |
"os" | |
"sort" | |
dto "github.com/prometheus/client_model/go" | |
"github.com/prometheus/common/expfmt" | |
) | |
func parseMF(path string) (map[string]*dto.MetricFamily, error) { | |
reader, err := os.Open(path) | |
if err != nil { | |
return nil, err | |
} | |
var parser expfmt.TextParser | |
mf, err := parser.TextToMetricFamilies(reader) | |
if err != nil { | |
return nil, err | |
} | |
return mf, nil | |
} | |
type ( | |
Labels struct { | |
Count uint | |
Set map[string]struct{} | |
} | |
MetricInfo struct { | |
Name string | |
Type string | |
Zeros uint | |
ZerosPercent float64 | |
Count uint | |
CountPercent float64 | |
Labels map[string]Labels | |
} | |
Info struct { | |
TotalCount uint | |
TotalZeros uint | |
Metrics []MetricInfo | |
} | |
) | |
func (m *MetricInfo) AddLabels(labels []*dto.LabelPair) { | |
for _, label := range labels { | |
if label == nil { | |
continue | |
} | |
if l, ok := m.Labels[label.GetName()]; !ok { | |
m.Labels[label.GetName()] = Labels{ | |
Count: 1, | |
Set: map[string]struct{}{label.GetValue(): {}}, | |
} | |
} else if _, exists := l.Set[label.GetValue()]; !exists { | |
l.Set[label.GetValue()] = struct{}{} | |
l.Count++ | |
m.Labels[label.GetName()] = l | |
} | |
} | |
} | |
func (m *MetricInfo) AddCount(mType dto.MetricType, metric *dto.Metric) error { | |
switch mType { | |
case dto.MetricType_COUNTER: | |
if metric.GetCounter().GetValue() == 0 { | |
m.Zeros++ | |
} | |
m.Count++ | |
case dto.MetricType_GAUGE: | |
if metric.GetGauge().GetValue() == 0 { | |
m.Zeros++ | |
} | |
m.Count++ | |
case dto.MetricType_SUMMARY: | |
for _, quantile := range metric.GetSummary().Quantile { | |
if quantile == nil { | |
continue | |
} | |
if quantile.GetValue() == 0 { | |
m.Zeros++ | |
} | |
m.Count++ | |
} | |
case dto.MetricType_HISTOGRAM: | |
for _, bucket := range metric.GetHistogram().Bucket { | |
if bucket == nil { | |
continue | |
} | |
if bucket.GetCumulativeCount() == 0 { | |
m.Zeros++ | |
} | |
m.Count++ | |
} | |
default: | |
return fmt.Errorf("unknown metric type %s for metric %s", mType.String(), m.Name) | |
} | |
return nil | |
} | |
func main() { | |
f := flag.String("f", "", "path to the Prometheus metrics file") | |
flag.Parse() | |
mf, err := parseMF(*f) | |
if err != nil { | |
log.Fatalf("failed to parse metrics file: %v", err) | |
} | |
out := Info{} | |
for k, v := range mf { | |
if v == nil { | |
continue | |
} | |
if len(v.Metric) == 0 { | |
continue | |
} | |
info := MetricInfo{ | |
Name: k, | |
Type: v.GetType().String(), | |
Zeros: 0, | |
Count: 0, | |
Labels: map[string]Labels{}, | |
} | |
for _, m := range v.Metric { | |
if m == nil { | |
continue | |
} | |
info.AddLabels(m.GetLabel()) | |
if err := info.AddCount(v.GetType(), m); err != nil { | |
log.Printf("failed to add counts for metric %s: %v", k, err) | |
continue | |
} | |
} | |
info.ZerosPercent = float64(info.Zeros) / float64(info.Count) * 100 | |
out.TotalCount += info.Count | |
out.TotalZeros += info.Zeros | |
out.Metrics = append(out.Metrics, info) | |
} | |
sort.Slice(out.Metrics, func(i, j int) bool { | |
if out.Metrics[i].Count == out.Metrics[j].Count { | |
return out.Metrics[i].Zeros > out.Metrics[j].Zeros | |
} | |
return out.Metrics[i].Count > out.Metrics[j].Count | |
}) | |
for i := range out.Metrics { | |
out.Metrics[i].CountPercent = float64(out.Metrics[i].Count) / float64(out.TotalCount) * 100 | |
} | |
b, err := json.MarshalIndent(out, "", " ") | |
if err != nil { | |
log.Fatalf("failed to marshal output: %v", err) | |
} | |
if err := os.WriteFile("metrics.json", b, 0o644); err != nil { | |
log.Fatalf("failed to write metrics.json: %v", err) | |
} | |
fmt.Println("Metrics written to metrics.json") | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment