Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

resources: for native histograms show String() output in the UI #596

Merged
merged 1 commit into from
May 22, 2024

Conversation

jan--f
Copy link
Contributor

@jan--f jan--f commented Nov 22, 2023

If a histogram has no classic buckets, assume its a native histogram and render the stringyfied version of it.

Fixes: #515

<tr>
<th scope="row">Sample Sum</th>
<td>{{value .GetSampleSum}}</td>
<td>{{.String}}</td>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The problem here is that this is just the string representation of the protobuf, which is not very human-readable.

There should be code somewhere already to convert a protobuf histogram to model.histogram.Histogram or model.histogram.FloatHistogram. Maybe we can utilize it to get a display here that looks similar to what we currently get in the Prometheus UI itself?

I'm in a hurry right now, but I can help you to find this conversion code if you cannot find it easily.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No worries, I'll go dig. Thanks for the pointer.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So the code that does this during scraping is unfortunately too tightly coupled with the parser:
https://github.com/prometheus/prometheus/blob/980e2895a2eebb9664af104e6d4e19932cc74432/model/textparse/protobufparse.go#L173-L214

Maybe you could extract a separate ProtoToHistogram(*dto.Histogram) (*histogram.Histogram, *histogram.FloatHistogram) from that code (to be used there and then in the PGW, too).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or maybe not. In prometheus/prometheus, we use Gogo protobuf, in prometheus/pushgateway, we use the official Go protobuf library. So the dto.Histogram types are actually different.
I would just write the conversion code proto -> histogram.Histogram here in PGW for now. Depending on how long it is and where it is actually used, we can then move it somewhere else if needed.

@beorn7
Copy link
Member

beorn7 commented Apr 11, 2024

Hi @jan--f , with #611 merged, it should just be one more small step to modify this PR to have a (more or less) human-readable histogram representation in the UI. Do you think you can work on this any time soon?

@jan--f
Copy link
Contributor Author

jan--f commented Apr 11, 2024

yes indeed, hoping to have an update next week.

@jan--f
Copy link
Contributor Author

jan--f commented Apr 19, 2024

Ok better late then never I suppose.
2024-04-19-114117_1920x802

Wdyt @beorn7

@beorn7
Copy link
Member

beorn7 commented Apr 23, 2024

Looks great at first glance. I'm on vacation this week, but this is high on my list once I'm back in action.

Copy link
Member

@beorn7 beorn7 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe I'm missing something, but I think this can be simplified, see comments.

go.mod Outdated
@@ -41,3 +41,5 @@ require (
google.golang.org/appengine v1.6.8 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
)

replace github.com/prometheus/prometheus v0.48.1 => ../prometheus
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's probably a leftover from your local dev environment?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed. Apologies... 🤦

Comment on lines 81 to 84
return fmt.Sprintf("{ count:%v sum:%v %s}",
m.GetSampleCountFloat(),
m.GetSampleSum(),
histogram.BucketsAsString[float64](histogram.GetAPIFloatBuckets(fh)))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't return h.String() do the same?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It sure does 👍

Comment on lines 86 to 89
return fmt.Sprintf("{ count:%v sum:%v %s}",
m.GetSampleCount(),
m.GetSampleSum(),
histogram.BucketsAsString[uint64](histogram.GetAPIBuckets(h)))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And here fh.String()?

m.GetSampleCountFloat(),
m.GetSampleSum(),
histogram.BucketsAsString[float64](histogram.GetAPIFloatBuckets(fh)))
} else {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This else isn't really needed, is it? (You return in the if block above.)

Copy link
Contributor Author

@jan--f jan--f May 3, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's the else branch if we have a histogram and not a float histogram.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But since you return in line 81, the current else branch is anyway only taken if h!=nil.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean, don't remove the whole block, just remove the } else { and the closing } below and outdent the content of the block.

@@ -79,6 +80,32 @@ func BucketsAsJson[BC model.BucketCount](buckets []APIBucket[BC]) [][]interface{
return ret
}

func BucketsAsString[BC model.BucketCount](buckets []APIBucket[BC]) string {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As said above, I assume you can use the String method of the model histograms, and then you don't need this helper.

{{- with .Histogram}}
<table class="table table-striped table-bordered">
{{- range .Bucket}}
{{- if le (len .Bucket) 0}}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So there is the case of a "dual histogram", which has both classic buckets and the sparse buckets of a native histogram, so that the scraper can decide what kind of histogram it wants to ingest (possibly even both). In that case, we should probably display both the classic and the native histogram, maybe with a <th scope="row">Native Histogram representation</th>.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see, so would then make sense to format classic histograms if there are classic buckets and native histograms if Schema != nil?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Schema is just an int32, so it never can be nil.

I would render a classic histogram if there are classic buckets, and I would render a native histogram if there are native buckets. The only edge case is if there are no buckets at all, but then the rendering of either isn't much of a difference (just sum and count), so you could pick any one rendering for that.

{{- with .Histogram}}
<table class="table table-striped table-bordered">
{{- range .Bucket}}
{{- if .Schema }}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, I guess this essentially tests if .Schema is 0 or not, which is not what we want. (Schema 0 is a perfectly valid schema for native histograms.) As said in another comment, let's simply test if there are native buckets.

</tr>
{{- end}}
{{- if gt (len .Bucket) 0}}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or if there are neither native nor classic buckets (to handle the case of a bucket-less histogram).

@beorn7
Copy link
Member

beorn7 commented May 15, 2024

Sorry for sprinkling the comments instead of doing them in one review. But I think I have addressed all questions now.

If a histogram has no classic buckets, assume its a native histogram and
render a string version of it like Prometheus currently does.

Signed-off-by: Jan Fajerski <[email protected]>
@jan--f
Copy link
Contributor Author

jan--f commented May 17, 2024

Sorry for sprinkling the comments instead of doing them in one review. But I think I have addressed all questions now.

Not at all, thanks a lot for your patience. I think all comments are addressed now.

Copy link
Member

@beorn7 beorn7 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wonderful. Thanks a lot.

Note that I'll update the commit description to the current state of affairs when merging.

@beorn7 beorn7 merged commit c83c5cc into prometheus:master May 22, 2024
4 checks passed
@SuperQ SuperQ mentioned this pull request Jun 7, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add support for native histograms
2 participants