Skip to content

Commit c77da94

Browse files
authored
Merge pull request #779 from Channyboy/v510-histoDistrSum
MP Config properties for Histogram and Timers to extend and customize output
2 parents 7db53d3 + 7327b44 commit c77da94

17 files changed

+2611
-18
lines changed

api/src/main/java/org/eclipse/microprofile/metrics/Snapshot.java

+62-8
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*
22
**********************************************************************
3-
* Copyright (c) 2017, 2022 Contributors to the Eclipse Foundation
3+
* Copyright (c) 2017, 2023 Contributors to the Eclipse Foundation
44
* 2010-2013 Coda Hale, Yammer.com
55
*
66
* See the NOTICES file(s) distributed with this work for additional
@@ -54,10 +54,18 @@ public abstract class Snapshot {
5454
* Returns an array of {@link PercentileValue} containing the percentiles and associated values of this
5555
* {@link Snapshot} at the moment invocation.
5656
*
57-
* @return an array of {@link PercentileValue}
57+
* @return an array of {@link PercentileValue} if it is available or an empty array if not available
5858
*/
5959
public abstract PercentileValue[] percentileValues();
6060

61+
/**
62+
* Returns an array of {@link HistogramBucket} containing the bucket and associated value of this {@link Snapshot}
63+
* at the moment invocation.
64+
*
65+
* @return an array of {@link HistogramBucket} if it is available or an empty array if not available
66+
*/
67+
public abstract HistogramBucket[] bucketValues();
68+
6169
/**
6270
* Writes the values of the snapshot to the given stream.
6371
*
@@ -67,8 +75,8 @@ public abstract class Snapshot {
6775
public abstract void dump(OutputStream output);
6876

6977
/**
70-
* Represents a percentile and its value at the moment it was sampled from the Snapshot.
71-
* Percentile values of a {@link Timer} are represented in units of nanoseconds.
78+
* Represents a percentile and its value at the moment it was sampled from the Snapshot. Percentile values of a
79+
* {@link Timer} are represented in units of nanoseconds.
7280
*
7381
* See {@link #percentileValue()}
7482
*/
@@ -89,18 +97,18 @@ public PercentileValue(double percentile, double value) {
8997
}
9098

9199
/**
92-
* Returns percentile
100+
* Returns the percentile
93101
*
94-
* @return double percentile
102+
* @return the percentile
95103
*/
96104
public double getPercentile() {
97105
return this.percentile;
98106
}
99107

100108
/**
101-
* Returns value at percentile
109+
* Returns the value at percentile
102110
*
103-
* @return double value at percentile
111+
* @return the value at the percentile
104112
*/
105113
public double getValue() {
106114
return this.value;
@@ -111,4 +119,50 @@ public String toString() {
111119
}
112120

113121
}
122+
123+
/**
124+
* Represents a cumulative histogram bucket at the moment it was sampled from the Snapshot. The bucket of
125+
* {@link Timer} will be represented in nanoseconds.
126+
*
127+
* See {@link #bucketValues()}
128+
*/
129+
public static class HistogramBucket {
130+
private final double bucket;
131+
private final long count;
132+
133+
/**
134+
*
135+
* @param count
136+
* count at this bucket
137+
* @param bucket
138+
* the upper limit value of this bucket
139+
*/
140+
public HistogramBucket(double bucket, long count) {
141+
this.bucket = bucket;
142+
this.count = count;
143+
}
144+
145+
/**
146+
* Returns the count of the bucket
147+
*
148+
* @return the count of the bucket
149+
*/
150+
public long getCount() {
151+
return this.count;
152+
}
153+
154+
/**
155+
* Returns the upper limit value of this bucket
156+
*
157+
* @return the upper limit value of this bucket
158+
*/
159+
public double getBucket() {
160+
return this.bucket;
161+
}
162+
163+
public String toString() {
164+
return "[Bucket: " + (this.bucket) + " with count: " + this.count + "]";
165+
}
166+
167+
}
114168
}

spec/src/main/asciidoc/changelog.adoc

+3-9
Original file line numberDiff line numberDiff line change
@@ -25,19 +25,13 @@
2525
== Changes in 5.1
2626
A full list of changes may be found on the link:https://github.com/eclipse/microprofile-metrics/milestone/16[MicroProfile Metrics 5.1 Milestone]
2727

28-
=== Other changes
29-
30-
* Include new recommendation for multi-application deployments to use a `mp.metrics.defaultAppName` property (https://github.com/eclipse/microprofile-metrics/issues/766[766])
31-
32-
[[release_notes_5_1]]
33-
== Changes in 5.1
34-
A full list of changes may be found on the link:https://github.com/eclipse/microprofile-metrics/milestone/16[MicroProfile Metrics 5.1 Milestone]
35-
3628
=== Functional Changes
37-
29+
* Introduced MP Config properties that customize how Histogram and Timer metrics track and output statistics for percentiles and histogram-buckets. (https://github.com/eclipse/microprofile-metrics/issues/691[691])(https://github.com/eclipse/microprofile-metrics/issues/676[676])(https://github.com/eclipse/microprofile-metrics/issues/675[675])(https://github.com/eclipse/microprofile-metrics/issues/674[674])(https://github.com/eclipse/microprofile-metrics/issues/587[587])
3830
* @RegistryScope is now a qualifier (https://github.com/eclipse/microprofile-metrics/issues/749[749])
3931

32+
=== Other changes
4033

34+
* Include new recommendation for multi-application deployments to use a `mp.metrics.defaultAppName` property (https://github.com/eclipse/microprofile-metrics/issues/766[766])
4135

4236
[[release_notes_5_0]]
4337
== Changes in 5.0
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,220 @@
1+
//
2+
// Copyright (c) 2023 Contributors to the Eclipse Foundation
3+
//
4+
// See the NOTICE file(s) distributed with this work for additional
5+
// information regarding copyright ownership.
6+
//
7+
// Licensed under the Apache License, Version 2.0 (the "License");
8+
// you may not use this file except in compliance with the License.
9+
// You may obtain a copy of the License at
10+
//
11+
// http://www.apache.org/licenses/LICENSE-2.0
12+
//
13+
// Unless required by applicable law or agreed to in writing, software
14+
// distributed under the License is distributed on an "AS IS" BASIS,
15+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
// See the License for the specific language governing permissions and
17+
// limitations under the License.
18+
//
19+
20+
[[histogram-timer-config]]
21+
== Configuration for Histogram and Timers
22+
23+
This section defines MicroProfile Config properties that extend the ability of the histogram and timer metrics to track and output additional statistics. This includes customizing the percentile output as well as enabling and customizing histogram-bucket values. These MicroProfile config properties can be defined at the server level or at the application level through the `META-INF/microprofile-config.properties` file within the application archive.
24+
25+
[[percentile-configuration]]
26+
=== Percentile customization for histograms and timers
27+
28+
The percentiles that are tracked and are output can be overridden and customized by using the MicroProfile Config property `mp.metrics.distribution.percentiles`. The property follows these rules:
29+
30+
* The property accepts a semi-colon separated set of values that consist of a metric name followed by an equals sign (`=`) and comma separated percentile values _(See <<percentiles-examples,examples>> below)_.
31+
* The asterisk (`*`) can be used as a wildcard at the end of the metric name.
32+
* The percentile values are float values between 0.0 and 1.0 inclusively. Invalid values will be ignored.
33+
* Setting the property with a metric name but no percentile values disables percentile output for that metric.
34+
* Setting the property without any value disables percentiles for all histogram and timer metrics.
35+
* Values defined later take precedence over values before (i.e., right to left precedence).
36+
37+
[[percentiles-examples]]
38+
.MicroProfile Config `mp.metrics.distribution.percentiles` property examples
39+
----
40+
//alpha.histogram will publish the 30th and 40th percentile and alpha.timer will publish the 50th and 80th percentile
41+
mp.metrics.distribution.percentiles=alpha.histogram=0.3,0.4;alpha.timer=0.5,0.8
42+
43+
//any timer or histogram that match alpha.* will publish the 60th percentile
44+
mp.metrics.distribution.percentiles=alpha.*=0.6
45+
46+
//any timer or histogram that match alpha.* will publish the 60th percentile and alpha.test.histogram which will only publish the 40th percentile due to precedence
47+
mp.metrics.distribution.percentiles=alpha.*=0.6;alpha.test.histogram=0.4
48+
49+
//disables percentiles for all histogram and timer metrics
50+
mp.metrics.distribution.percentiles=*=
51+
52+
//disables percentiles for all histogram and timer metrics
53+
mp.metrics.distribution.percentiles=
54+
----
55+
56+
NOTE: Histograms and Timers that do not match the metric name definitions of the `mp.metrics.distribution.percentiles` property will output the default 50th, 75th, 95th, 99th and 99.9th percentiles.
57+
58+
=== Defining histogram-buckets for histograms and timers
59+
60+
The MicroProfile Metrics runtime offers MicroProfile Config properties to enable and explicitly set (cumulative) histogram-buckets for histograms and timers.
61+
The property `mp.metrics.distribution.timer.buckets` applies to timer metrics and the property `mp.metrics.distribution.histogram.buckets` applies to histograms. These two properties follow these rules unless explicitly describing a specific property:
62+
63+
* The property accepts a semi-colon separated set of values that consist of a metric name followed by an equals sign (`=`) and comma separated bucket values:
64+
** `mp.metrics.distribution.histogram.buckets` accepts a comma separated list of float and integer values greater than 0 _(See <<histogram-bucket-sample,examples>> below)_.
65+
** `mp.metrics.distribution.timer.buckets` accepts a comma separated list of integers with an appended time unit (valid time units are `ms` for milliseconds, `s` for seconds, `m` for minutes and `h` for hours). Float values will not be accepted. Values with no time unit default to milliseconds. _(See <<timer-buckets-sample,examples>> below)_
66+
* The asterisk (`*`) can be used as a wildcard at the end of the metric name.
67+
* Defining a metric name with no bucket values or invalid values provides no effect.
68+
* Values defined later take precedence over values before (i.e., right to left precedence).
69+
70+
NOTE: When customizing histogram-bucket values for the histogram and timer metrics, the metrics included in the Prometheus output will automatically switch from a `summary` type to the `histogram` type. Any percentile values that are also outputted will belong under the `histogram` type. The Prometheus output will also automatically include a `+Inf` bucket to capture all values. This will be demonstrated in the <<histogram-bucket-output, histogram sample output>> and <<timer-buckets-output, timer sample output>>. The metric output for the buckets will also be appended with `_bucket`, and a tag `le` is used to denote the bucket value.
71+
72+
[[histogram-bucket-sample]]
73+
.MicroProfile Config `mp.metrics.distribution.histogram.buckets` property examples
74+
----
75+
//alpha.histogram will publish histogram-buckets with maximum values of 10.0, 50.0 and 100.0 while the beta.histogram will publish histogram buckets with maximum values of 30.0, 50 and 123.
76+
mp.metrics.distribution.histogram.buckets=alpha.histogram=10.0,50.0,100.0;beta.histogram=30.0,50.0,123
77+
78+
//any histogram that matches with `beta.*` will publish histogram buckets with maximum values of 50.0 and 100.0 except the beta.test.histogram which will publish a bucket with a maximum value of 100.0 due to precedence.
79+
mp.metrics.distribution.histogram.buckets=beta.*=50.0,100.0;beta.test.histogram=100.0
80+
81+
----
82+
83+
NOTE: Histograms that do not match any of the metric names defined by the `mp.metrics.distribution.histogram.buckets` property will output no buckets.
84+
85+
The following is a sample output of the `alpha.histogram` defined in the first `mp.metrics.distribution.histogram.buckets` definition above.
86+
87+
[[histogram-bucket-output]]
88+
.Sample alpha.histogram Prometheus output
89+
----
90+
# HELP alpha_histogram_cookies
91+
# TYPE alpha_histogram_cookies histogram <1>
92+
alpha_histogram_cookies{mp_scope="application",quantile="0.5",} 9.25 <2>
93+
alpha_histogram_cookies{mp_scope="application",quantile="0.75",} 51.75 <2>
94+
alpha_histogram_cookies{mp_scope="application",quantile="0.95",} 51.75 <2>
95+
alpha_histogram_cookies{mp_scope="application",quantile="0.98",} 51.75 <2>
96+
alpha_histogram_cookies{mp_scope="application",quantile="0.99",} 51.75 <2>
97+
alpha_histogram_cookies{mp_scope="application",quantile="0.999",} 51.75 <2>
98+
alpha_histogram_cookies_bucket{mp_scope="application",le="10.0",} 2.0 <3>
99+
alpha_histogram_cookies_bucket{mp_scope="application",le="50.0",} 3.0 <3>
100+
alpha_histogram_cookies_bucket{mp_scope="application",le="100.0",} 3.0 <3>
101+
alpha_histogram_cookies_bucket{mp_scope="application",le="+Inf",} 3.0 <3><4>
102+
alpha_histogram_cookies_count{mp_scope="application",} 3.0
103+
alpha_histogram_cookies_sum{mp_scope="application",} 64.0
104+
# HELP alpha_histogram_cookies_max
105+
# TYPE alpha_histogram_cookies_max gauge
106+
alpha_histogram_cookies_max{mp_scope="application",} 50.0
107+
----
108+
<1> The Prometheus metric type is `histogram`
109+
110+
<2> percentiles are part of the `histogram` type instead of `summary`
111+
112+
<3> histogram buckets
113+
114+
<4> The `+Inf` bucket is included in the output
115+
116+
117+
118+
[[timer-buckets-sample]]
119+
.MicroProfile Config `mp.metrics.distribution.timer.buckets` property examples
120+
----
121+
//alpha.timer will publish histogram-buckets with maximum values of 500 milliseconds, 2 seconds, and 3 minutes while the beta.timer will publish histogram buckets with maximum values of 10 seconds, 2 minutes and 5 hours. Timer metrics that do not match will not have any histogram buckets.
122+
mp.metrics.distribution.timer.buckets=alpha.timer=500ms,2s,3m;beta.timer=10s,2m,5h
123+
124+
//any timer that matches with `alpha.*` will publish histogram buckets with maximum values of 50 seconds and 100 seconds while the alpha.test.timer which will publish a bucket with a maximum value 100 milliseconds due to precedence. Timer metrics that do not match will not have any histogram buckets.
125+
mp.metrics.distribution.timer.buckets=alpha.*=50s,100s;alpha.test.timer=100
126+
127+
----
128+
129+
NOTE: Timers that do not match any of the metric names defined by the `mp.metrics.distribution.timer.buckets` property will output no buckets.
130+
131+
NOTE: The time units defined by the property will be converted to second based buckets for the Prometheus output as timers are based in seconds.
132+
133+
The following is a sample output of the `alpha.timer` defined in the first `mp.metrics.distribution.timer.buckets` definition above.
134+
135+
[[timer-buckets-output]]
136+
.Sample alpha.timer Prometheus output
137+
----
138+
# HELP alpha_timer_seconds_max
139+
# TYPE alpha_timer_seconds_max gauge
140+
alpha_timer_seconds_max{mp_scope="application"} 5.633
141+
# HELP alpha_timer_seconds
142+
# TYPE alpha_timer_seconds histogram <1>
143+
alpha_timer_seconds{mp_scope="application", quantile="0.5",} 0.67108864 <2>
144+
alpha_timer_seconds{quantile="0.75",} 5.603590144 <2>
145+
alpha_timer_seconds{mp_scope="application", quantile="0.95",} 5.603590144 <2>
146+
alpha_timer_seconds{mp_scope="application", quantile="0.98",} 5.603590144 <2>
147+
alpha_timer_seconds{mp_scope="application", quantile="0.99",} 5.603590144 <2>
148+
alpha_timer_seconds{mp_scope="application", quantile="0.999",} 5.603590144 <2>
149+
alpha_timer_seconds_bucket{mp_scope="application", le="0.5",} 0.0 <3><5>
150+
alpha_timer_seconds_bucket{mp_scope="application", le="2.0",} 1.0 <3><5>
151+
alpha_timer_seconds_bucket{mp_scope="application", le="180.0",} 2.0 <3><5>
152+
alpha_timer_seconds_bucket{mp_scope="application", le="+Inf",} 2.0 <3><4>
153+
alpha_timer_seconds_count{mp_scope="application"} 2.0
154+
alpha_timer_seconds_sum{mp_scope="application"} 6.333
155+
----
156+
157+
<1> The Prometheus metric type is `histogram`
158+
159+
<2> percentiles are part of the `histogram` type instead of `summary`
160+
161+
<3> histogram buckets
162+
163+
<4> The `+Inf` bucket is included in the output
164+
165+
<5> bucket values converted to seconds
166+
167+
=== (Optional) Enabling a default set of histogram-buckets for histograms and timers
168+
169+
Vendors may choose to optionally provide the `mp.metrics.distribution.percentiles-histogram.enabled` property. This will enable a matching histogram or timer metric to output a default set of bucket values defined by the vendor. The property follows these rules:
170+
171+
* The property accepts a semi-colon separated set of values that consist of a metric name followed by an equals sign (`=`) and either `true` or `false` (see <<default-buckets-sample,example>> below).
172+
* The asterisk (`*`) can be used as a wildcard at the end of the metric name.
173+
* Defining a metric name with no values or invalid values has no effect.
174+
* Values defined later take precedence over values before (i.e., right to left precedence).
175+
176+
[[default-buckets-sample]]
177+
.MicroProfile Config `mp.metrics.distribution.percentiles-histogram.enabled` property examples
178+
----
179+
//vendor will provide default buckets for the alpha.timer
180+
mp.metrics.distribution.percentiles-histogram.enabled=alpha.timer=true;alpha.histogram=false
181+
----
182+
183+
NOTE: The `mp.metrics.distribution.percentiles-histogram.enabled` property does not affect any buckets defined by the `mp.metrics.distribution.histogram.buckets` or `mp.metrics.distribution.timer.buckets` properties. A `false` value for `mp.metrics.distribution.percentiles-histogram.enabled` will not disable any custom buckets defined by `mp.metrics.distribution.histogram.buckets` or `mp.metrics.distribution.timer.buckets` for any matching histogram or timer.
184+
185+
It is recommended that if the vendor provides support for the `mp.metrics.distribution.percentiles-histogram.enabled` property, then the following properties be supported as well:
186+
187+
* `mp.metrics.distribution.histogram.min-value`
188+
* `mp.metrics.distribution.histogram.max-value`
189+
* `mp.metrics.distribution.timer.min-value`
190+
* `mp.metrics.distribution.timer.max-value`
191+
192+
The number of default buckets and maximum value of each of those default buckets may vary between vendor implementations. These properties are used to set a minimum and maximum limit for the default buckets provided when `mp.metrics.distribution.percentiles-histogram.enabled` has enabled default buckets for the matching metric. The properties share the following rules and explicit rules are outlined for specific properties:
193+
194+
* The property accepts a semi-colon separated set of values that define a metric name followed by an equals sign (`=`) and a value:
195+
** `mp.metrics.distribution.histogram.*` properties accept float or integer values greater than 0 _(See <<min-max-sample,examples>> below)_.
196+
** `mp.metrics.distribution.timer.*` accepts an integer value with an appended time unit (valid time units are `ms` for milliseconds, `s` for seconds, `m` for minutes and `h` for hours). Float values will not be accepted. Values with no time unit will default to milliseconds. _(See <<min-max-sample,examples>> below)_
197+
* The asterisk (`*`) can be used as a wildcard at the end of the metric name.
198+
* Defining a metric name with no value or an invalid value provides no effect.
199+
* Values defined later take precedence over values before (i.e., right to left precedence).
200+
201+
202+
203+
204+
[[min-max-sample]]
205+
.MicroProfile Config histogram/timer min/max property examples
206+
----
207+
//any histogram matching alpha.* will not have any buckets in the output that are below 300 except alpha.histogram which has a lower bound of 400 due to precedence
208+
mp.metrics.distribution.histogram.min-value=alpha.*=300;alpha.histogram=400
209+
210+
//any histogram matching alpha.* will not have any buckets in the output that are above 500 except alpha.histogram which has a upper bound of 400 due to precedence
211+
mp.metrics.distribution.histogram.max-value=alpha.*=500;alpha.histogram=400
212+
213+
//any timer matching alpha.* will not have any buckets in the output that are above 1 second except alpha.timer which has a upper bound of 0.5 seconds due to precedence
214+
mp.metrics.distribution.timer.max-value=alpha.*=1s;alpha.timer=500ms
215+
216+
//any timer matching alpha.* will not have any buckets in the output that are below 0.4 seconds except alpha.timer which has a lower bound of 0.5 seconds due to precedence
217+
mp.metrics.distribution.timer.min-value=alpha.*=400ms;alpha.timer=500ms
218+
----
219+
220+
NOTE: The use of the min and max properties do not apply to the buckets defined through `mp.metrics.distribution.timer.buckets` and `mp.metrics.distribution.histogram.buckets` properties.

spec/src/main/asciidoc/microprofile-metrics-spec.asciidoc

+2
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@ include::base-metrics.adoc[]
5757

5858
include::app-programming-model.adoc[]
5959

60+
include::histogram-timer-config.adoc[]
61+
6062
include::micrometer-backends.adoc[]
6163

6264
include::appendix.adoc[]

0 commit comments

Comments
 (0)