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

api: support native histograms in api/v1/metrics #611

Merged
merged 2 commits into from
Mar 20, 2024

Conversation

jan--f
Copy link
Contributor

@jan--f jan--f commented Jan 5, 2024

Another piece for #515.

An example return:

2024-01-05-092950_915x1038

@beorn7 beorn7 self-assigned this Jan 5, 2024
@beorn7 beorn7 self-requested a review January 5, 2024 18:55
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.

This looks perfect.

Could you amend the test in api_test.go so that it exercises a native histogram (or maybe even two, an integer one and a float one).

@beorn7
Copy link
Member

beorn7 commented Jan 10, 2024

A marginally related thing: The protobuf format supports MetricType GAUGE_HISTOGRAM by now, for which we never added support to the PGW. (There can be classic histograms that are gauge histograms.)

It should be easy to add the support for both classic and native histograms, now that you are on it…

@beorn7
Copy link
Member

beorn7 commented Jan 11, 2024

And another thought: IIRC this API is only used for the UI. (There might be users that use it for something else, but I would rather expect them to use the /metrics output directly.) In the UI, I think we should aim for a representation like in the Prometheus UI, which is an explicit description of the individual buckets with absolute population, upper and lower bound. We could argue that we don't need to do this conversion in the UI code because we already have an API exclusively serving the UI, so that API could already render this representation, in the most extreme case just as a string, as created by the histogram's String() method. This would simplify the UI code.

A less extreme approach would be to let the API render the buckets individually, but with upper/lower bound and absolute population (similar to the Prometheus query API). This would still allow a reasonably simple UI code, while the API output would still lend itself to some data processing.

The approach so far in this PR is also fine, but it would mean that the UI would show the "internal" histogram representation (with delta population, schema, spans), or you would need to recreate a lot of histogram logic in the UI code.

@beorn7
Copy link
Member

beorn7 commented Jan 18, 2024

After more thinking:

I keep talking about the UI above, because I have forgotten again that we still don't use the API to render the UI in the PGW (cf. #596).

While we do have a vague plan to eventually use the API to render the UI, the current usage pattern of the API are more relevant for the decision how to format native histograms. However, I'm not sure what those usage patterns are. If users want a representation close to the exposition format or close to the internal representation in the TSDB, the current approach in this PR is a good fit. However, if users use the API to render some kind of UI themselves, a representation closer to what the Prometheus query API is doing would be much better. The latter would also help with that future plan of rendering the PGW UI based on the API response. My gut feeling is we should do the latter, but I could easily be convinced otherwise.

For reference, this is the format in the Prometheus query API: https://prometheus.io/docs/prometheus/latest/querying/api/#native-histograms

@jan--f jan--f force-pushed the api-v1-histogram-support branch 2 times, most recently from 797c3b8 to 6630714 Compare February 16, 2024 13:13
@jan--f
Copy link
Contributor Author

jan--f commented Feb 16, 2024

@beorn7 I added code for human readable histograms.
2024-02-16-140914_924x920

While I fix the tests, I was wondering about a few things:

  • I'm not sure about the naming of the histogram package in pushgateway, happy to rename this to something more sensible.
  • The func GetReadable[Float]Buckets(h *model.Histogram) []string functions could live in prometheus/model/histogram, went with this for expediency.
  • For the api endpoint I needed to add the buckets field (since we're in JSON land). The Prometheus code doesn't have this, as it formats a string directly.

@beorn7
Copy link
Member

beorn7 commented Feb 20, 2024

Thank you very much.

I think the naming or layout of the histogram package is not critical. It can be easily refactored if needed. I think what you did serves its purpose.

However, the string formatting for a whole bucket in GetReadable is rubbing me the wrong way. That would be an entirely new way of an API return. I would prefer to follow what the Prometheus query API is doing, as linked above.

Here is a truncated example from a Prometheus query API response:

            "buckets": [
              [
                1,
                "-0.0000152587890625",
                "-0.00000762939453125",
                "42"
              ],
              [
                1,
                "-0.000003814697265625",
                "-0.0000019073486328125",
                "2"
              ],
              [
                0,
                "9.5367431640625e-07",
                "0.0000019073486328125",
                "145"
              ],
              [
                0,
                "0.000003814697265625",
                "0.00000762939453125",
                "11"
              ],
            ]

I think this is more useful than your "full string" approach because it allows users that are interested in the data (rather than just rendering a UI) to easily access bucket boundaries and bucket counts. (For example, Grafana is using this format to render heatmaps based on Prometheus histograms.) At the same time, it will be very easy to render a UI from that. With a few line of JavaScript or whatever you are using in your UI, you can render what GetReadable is returning now. And if you want to be fancier, you could also render a graphical representation of the histogram etc. (which is hard from the opaque string that GetReadable creates).

You can look at the code that lives over in prometheus/prometheus to see how this is rendered:
https://github.com/prometheus/prometheus/blob/aba007148057c1947122b18b2ad606883cc27220/util/jsonutil/marshal.go#L66-L137

(It's using jsoniter, so not directly re-usable, but it can still serve as inspiration.)

@jan--f
Copy link
Contributor Author

jan--f commented Feb 21, 2024

Ah my apologies, I totally missed that aspect. Will update, thank you!

Signed-off-by: Jan Fajerski <jfajersk@redhat.com>
Signed-off-by: Jan Fajerski <jfajersk@redhat.com>
@jan--f
Copy link
Contributor Author

jan--f commented Mar 15, 2024

Apologies for the long lag yet again.
The API endpoint now returns buckets like the Prometheus query API.

      "test_hist": {
        "time_stamp": "2024-03-15T16:16:28.843966226+01:00",
        "type": "HISTOGRAM",
        "help": "Just a histogram test",
        "metrics": [
          {
            "buckets": [
              [
                0,
                "17.448123722644123",
                "19.027313840043536",
                "139"
              ],
              [
                0,
                "19.027313840043536",
                "20.749432874416154",
                "85"
              ],
              [
                0,
                "20.749432874416154",
                "22.62741699796952",
                "70"
              ],

return ret
}

func GetAPIBuckets(h *model.Histogram) []APIBucket[uint64] {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This and GetAPIFloatBuckets are exported function since I intend to use them for the web ui changes.

@beorn7
Copy link
Member

beorn7 commented Mar 17, 2024

Looks great at first glance. I'll have a detailed look in the coming week.

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.

Looks great, thank you.

@beorn7 beorn7 merged commit aeef148 into prometheus:master Mar 20, 2024
4 checks passed
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.

2 participants