From 4a68a11be6d61b462c58bebdb7d066ea9c92e82f Mon Sep 17 00:00:00 2001 From: beorn7 Date: Wed, 10 Jul 2024 22:02:40 +0200 Subject: [PATCH 1/2] Invert detection logic for native histograms As it turns out, `makeBuckets` always returns at least the +Inf bucket. So a native histogram will never be rendered. The canonical way of marking a native histogram, even one without any observations yet, is to have at least one span. With this commit, a native histogram is rendered if there is at least one span. Otherwise, a classic histogram is rendered. Signed-off-by: beorn7 --- prom2json.go | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/prom2json.go b/prom2json.go index 62cbc6db..35d1155c 100644 --- a/prom2json.go +++ b/prom2json.go @@ -108,22 +108,24 @@ func getValue(m *dto.Metric) float64 { } func makeHistogram(m *dto.Metric) Histogram { + dtoH := m.GetHistogram() hist := Histogram{ Labels: makeLabels(m), TimestampMs: makeTimestamp(m), - Count: fmt.Sprint(m.GetHistogram().GetSampleCount()), - Sum: fmt.Sprint(m.GetHistogram().GetSampleSum()), + Count: fmt.Sprint(dtoH.GetSampleCount()), + Sum: fmt.Sprint(dtoH.GetSampleSum()), } - if b := makeBuckets(m); len(b) > 0 { - hist.Buckets = b - } else { - h, fh := histogram.NewModelHistogram(m.GetHistogram()) + // A native histogram is marked by at least one span. + if len(dtoH.GetNegativeSpan())+len(dtoH.GetPositiveSpan()) > 0 { + h, fh := histogram.NewModelHistogram(dtoH) if h == nil { // float histogram hist.Buckets = histogram.BucketsAsJson[float64](histogram.GetAPIFloatBuckets(fh)) } else { hist.Buckets = histogram.BucketsAsJson[uint64](histogram.GetAPIBuckets(h)) } + } else { + hist.Buckets = makeBuckets(m) } return hist } From 472bd393eb41f5b784f81af3cf1d65fcd7873df2 Mon Sep 17 00:00:00 2001 From: beorn7 Date: Wed, 10 Jul 2024 22:12:30 +0200 Subject: [PATCH 2/2] Improve histogram documentation Signed-off-by: beorn7 --- README.md | 43 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 39 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 35639b1a..dbb60a3a 100644 --- a/README.md +++ b/README.md @@ -82,9 +82,11 @@ Example input from stdin: Note that all numbers are encoded as strings. Some parsers want it that way. Also, Prometheus allows sample values like `NaN` or `+Inf`, which cannot be encoded as JSON numbers. -Native histograms are formated similarly as [the query -API](https://prometheus.io/docs/prometheus/latest/querying/api/#native-histograms) -would return. + +A histogram is formatted as a native histogram if it has at least one span. It +is then formatted in a similar way as [the Prometehus query +API](https://prometheus.io/docs/prometheus/latest/querying/api/#native-histograms) +does it. ```json [ @@ -136,7 +138,7 @@ would return. { "name": "http_request_duration_seconds", "type": "HISTOGRAM", - "help": "More HTTP request latencies in seconds.", + "help": "This is a native histogram.", "metrics": [ { "labels": { @@ -166,6 +168,39 @@ would return. "sum": "29969.50000000001" } ] + }, + { + "name": "some_weird_normal_distribution", + "type": "HISTOGRAM", + "help": "This is a classic histogram.", + "metrics": [ + { + "buckets": { + "-0.0001899999999999998": "17", + "-0.0002899999999999998": "6", + "-0.0003899999999999998": "2", + "-0.0004899999999999998": "2", + "-0.0005899999999999998": "0", + "-0.0006899999999999999": "0", + "-0.0007899999999999999": "0", + "-0.00089": "0", + "-0.00099": "0", + "-8.999999999999979e-05": "33", + "0.00011000000000000022": "75", + "0.00021000000000000023": "92", + "0.0003100000000000002": "100", + "0.0004100000000000002": "103", + "0.0005100000000000003": "105", + "0.0006100000000000003": "106", + "0.0007100000000000003": "107", + "0.0008100000000000004": "107", + "0.0009100000000000004": "107", + "1.0000000000000216e-05": "50" + }, + "count": "107", + "sum": "0.001792103516591124" + } + ] } ] ```