diff --git a/api/src/main/java/org/eclipse/microprofile/metrics/Histogram.java b/api/src/main/java/org/eclipse/microprofile/metrics/Histogram.java index 9316fbf7..444cc5ab 100644 --- a/api/src/main/java/org/eclipse/microprofile/metrics/Histogram.java +++ b/api/src/main/java/org/eclipse/microprofile/metrics/Histogram.java @@ -52,6 +52,13 @@ public interface Histogram extends Metric, Sampling, Counting { @Override long getCount(); + /** + * Returns the sum of values recorded. + * + * @return the sum of values recorded + */ + long getSum(); + @Override Snapshot getSnapshot(); } diff --git a/spec/src/main/asciidoc/changelog.adoc b/spec/src/main/asciidoc/changelog.adoc index 6a349caa..129b7dc3 100644 --- a/spec/src/main/asciidoc/changelog.adoc +++ b/spec/src/main/asciidoc/changelog.adoc @@ -66,12 +66,18 @@ *** Added `Timer.getElapsedTime()` which returns `java.time.Duration` ** Removed `MetadataBuilder.withOptional*` methods ** Global tags and `_app` tag are no longer handled automatically by the `MetricID` class, the implementation is expected to add them by itself, for example during metric export +** Added the `Histogram.getSum()` which returns `long` (https://github.com/eclipse/microprofile-metrics/issues/597[#597]) + === Functional Changes ** Simple Timer metrics now track the highest and lowest recorded timing duration of the previous completed minute (https://github.com/eclipse/microprofile-metrics/issues/523[#523]) -** Timer now exposes total elapsed time duration as a metric value (https://github.com/eclipse/microprofile-metrics/issues/524[#524]) +** Timer now exposes total elapsed time duration as a metric value. (https://github.com/eclipse/microprofile-metrics/issues/524[#524]) ** Clarified that the existing REST metric `REST.request` will not monitor and track a REST request to a REST endpoint if an unmapped exception occurs. ** Introduced a new base REST metric `REST.request.unmappedException.total` that counts the occurrences of unmapped exceptions for each REST endpoint (https://github.com/eclipse/microprofile-metrics/issues/533[#533]) +** Histogram now exposes the total sum of recorded values as a `sum` value (https://github.com/eclipse/microprofile-metrics/issues/597[#597]) +*** In JSON format it is exposed as a `sum` value +*** In OpenMetrics format it is exposed as a `sum` value under the `summary` type +** Timer now exposes the `elapsedTime` metric value as `sum` under the `summary` type in OpenMetrics format (https://github.com/eclipse/microprofile-metrics/issues/597[#597]) === Specification Changes ** Removed the concept of reusability @@ -81,6 +87,10 @@ but the type is implied by the name of the registration method that is being called. ** Clarified that the existing REST metric `REST.request` will not monitor and track a REST request to a REST endpoint if an unmapped exception occurs ** Introduced a new base REST metric `REST.request.unmappedException.total` that counts the occurrences of unmapped exceptions for each REST endpoint (https://github.com/eclipse/microprofile-metrics/issues/533[#533]) +** Histogram now exposes the total sum of recorded values as a `sum` value (https://github.com/eclipse/microprofile-metrics/issues/597[#597]) +*** In JSON format it is exposed as a `sum` value +*** In OpenMetrics format it is exposed as a `sum` value under the `summary` type +** Timer now exposes the `elapsedTime` metric value as `sum` under the `summary` type in OpenMetrics format (https://github.com/eclipse/microprofile-metrics/issues/597[#597]) === TCK enhancement ** Improved TCK - Use newly introduced `MetricRegistry` methods to retrieve single metrics and avoid use of the `getMetrics()` and `getMetadata()` methods diff --git a/spec/src/main/asciidoc/rest-endpoints.adoc b/spec/src/main/asciidoc/rest-endpoints.adoc index 8fb8de85..8c69cb93 100644 --- a/spec/src/main/asciidoc/rest-endpoints.adoc +++ b/spec/src/main/asciidoc/rest-endpoints.adoc @@ -234,6 +234,7 @@ The JSON node is named ``. The JSON leafs are named `[';'`. The JSON leafs are named `[';'`. The JSON leafs are named `[';'` | Gauge | `getSnapshot().getMean()` | ^1^ | `stddev_` | Gauge | `getSnapshot().getStdDev()` | ^1^ | `_count`^2^ | Summary | `getCount()` | N/A +| `_sum`^2^ | Summary | `getSum()` | ^1^ | `{quantile="0.5"}`^2^ | Summary | `getSnapshot().getMedian()` | ^1^ | `{quantile="0.75"}`^2^ | Summary | `getSnapshot().get75thPercentile()` | ^1^ | `{quantile="0.95"}`^2^ | Summary | `getSnapshot().get95thPercentile()` | ^1^ @@ -677,7 +681,7 @@ The `quantile` OpenMetrics label is merged with the metric's tags. ^1^ The implementation is expected to convert the result returned by the `Histogram` into the base unit (if known). The `` represents the base metric unit and is named according to <>. -^2^ The `summary` type is a complex metric type for OpenMetrics which consists of the count and multiple quantile values. +^2^ The `summary` type is a complex metric type for OpenMetrics which consists of the count, sum and multiple quantile values. .Example OpenMetrics text format for a Histogram with unit bytes. [source, ruby] @@ -693,6 +697,7 @@ application_file_sizes_stddev_bytes 1054.7343037063602 # TYPE application_file_sizes_bytes summary # HELP application_file_sizes_bytes Users file size application_file_sizes_bytes_count 2037 +application_file_sizes_bytes_sum 48123 application_file_sizes_bytes{quantile="0.5"} 4201 application_file_sizes_bytes{quantile="0.75"} 6175 application_file_sizes_bytes{quantile="0.95"} 13560 @@ -719,12 +724,12 @@ The `quantile` OpenMetrics label is merged with the metric's tags. | `one_min_rate_per_second` | Gauge | `getOneMinuteRate()` | PER_SECOND | `five_min_rate_per_second` | Gauge | `getFiveMinuteRate()` | PER_SECOND | `fifteen_min_rate_per_second` | Gauge | `getFifteenMinuteRate()` | PER_SECOND -| `elapsedTime_seconds` | Gauge | `getElapsedTime()` | SECONDS^1^ | `min_seconds` | Gauge | `getSnapshot().getMin()` | SECONDS^1^ | `max_seconds` | Gauge | `getSnapshot().getMax()` | SECONDS^1^ | `mean_seconds` | Gauge | `getSnapshot().getMean()` | SECONDS^1^ | `stddev_seconds` | Gauge | `getSnapshot().getStdDev()` | SECONDS^1^ | `seconds_count`^2^ | Summary | `getCount()` | N/A +| `seconds_sum`^2^ | Summary | `getElapsedTime()` | SECONDS^1^ | `seconds{quantile="0.5"}`^2^ | Summary | `getSnapshot().getMedian()` | SECONDS^1^ | `seconds{quantile="0.75"}`^2^ | Summary | `getSnapshot().get75thPercentile()` | SECONDS^1^ | `seconds{quantile="0.95"}`^2^ | Summary | `getSnapshot().get95thPercentile()` | SECONDS^1^ @@ -748,8 +753,6 @@ application_response_time_one_min_rate_per_second 2.794076465421066E-14 application_response_time_five_min_rate_per_second 4.800392614619373E-4 # TYPE application_response_time_fifteen_min_rate_per_second gauge application_response_time_fifteen_min_rate_per_second 0.01063191047532505 -# TYPE application_response_time_elapsedTime_seconds gauge -application_response_time_elapsedTime_seconds 0.023 # TYPE application_response_time_mean_seconds gauge application_response_time_mean_seconds 0.000415041 # TYPE application_response_time_max_seconds gauge @@ -761,6 +764,7 @@ application_response_time_stddev_seconds 0.000652907 # TYPE application_response_time_seconds summary # HELP application_response_time_seconds Server response time for /index.html application_response_time_seconds_count 80 +application_response_time_seconds_sum 0.023 application_response_time_seconds{quantile="0.5"} 0.0002933240 application_response_time_seconds{quantile="0.75"} 0.000344914 application_response_time_seconds{quantile="0.95"} 0.000543647 diff --git a/tck/api/src/main/java/org/eclipse/microprofile/metrics/tck/metrics/HistogramFieldBeanTest.java b/tck/api/src/main/java/org/eclipse/microprofile/metrics/tck/metrics/HistogramFieldBeanTest.java index fd8ed7b3..5ea6066e 100644 --- a/tck/api/src/main/java/org/eclipse/microprofile/metrics/tck/metrics/HistogramFieldBeanTest.java +++ b/tck/api/src/main/java/org/eclipse/microprofile/metrics/tck/metrics/HistogramFieldBeanTest.java @@ -87,6 +87,7 @@ public void updateHistogramField() { long value = Math.round(Math.random() * Long.MAX_VALUE); bean.update(value); assertThat("Histogram count is incorrect", histogram.getCount(), is(equalTo(1L))); + assertThat("Histogram sum is incorrect", histogram.getSum(), is(equalTo(value))); assertThat("Histogram size is incorrect", histogram.getSnapshot().size(), is(equalTo(1))); assertThat("Histogram min value is incorrect", histogram.getSnapshot().getMin(), is(equalTo(value))); assertThat("Histogram max value is incorrect", histogram.getSnapshot().getMax(), is(equalTo(value))); diff --git a/tck/api/src/main/java/org/eclipse/microprofile/metrics/tck/metrics/HistogramTest.java b/tck/api/src/main/java/org/eclipse/microprofile/metrics/tck/metrics/HistogramTest.java index 6c10c3c3..1c182268 100644 --- a/tck/api/src/main/java/org/eclipse/microprofile/metrics/tck/metrics/HistogramTest.java +++ b/tck/api/src/main/java/org/eclipse/microprofile/metrics/tck/metrics/HistogramTest.java @@ -123,6 +123,12 @@ public void testCount() throws Exception { Assert.assertEquals(200, histogramLong.getCount()); } + @Test + public void testSum() throws Exception { + Assert.assertEquals(10127, histogramInt.getSum()); + Assert.assertEquals(101270, histogramLong.getSum()); + } + @Test public void testSnapshotValues() throws Exception { Assert.assertArrayEquals( diff --git a/tck/rest/src/main/java/org/eclipse/microprofile/metrics/test/MpMetricTest.java b/tck/rest/src/main/java/org/eclipse/microprofile/metrics/test/MpMetricTest.java index 078b91b5..cc865107 100644 --- a/tck/rest/src/main/java/org/eclipse/microprofile/metrics/test/MpMetricTest.java +++ b/tck/rest/src/main/java/org/eclipse/microprofile/metrics/test/MpMetricTest.java @@ -528,6 +528,7 @@ public void testApplicationMetricsJSON() { .body("'org.eclipse.microprofile.metrics.test.MetricAppBean.gaugeMeB;tier=integration'", equalTo(7777777)) .body("'metricTest.test1.histogram'.'count;tier=integration'", equalTo(1000)) + .body("'metricTest.test1.histogram'.'sum;tier=integration'", equalTo(499500)) .body("'metricTest.test1.histogram'.'max;tier=integration'", equalTo(999)) .body("'metricTest.test1.histogram'.'mean;tier=integration'", closeTo(499.5)) .body("'metricTest.test1.histogram'.'min;tier=integration'", equalTo(0)) @@ -691,11 +692,11 @@ public void testApplicationTimerUnitOpenMetrics() { .and() .body(containsString("# TYPE application_" + prefix + "seconds summary")) .body(containsString(prefix + "seconds_count")) + .body(containsString(prefix + "seconds_sum")) .body(containsString(prefix + "rate_per_second")) .body(containsString(prefix + "one_min_rate_per_second")) .body(containsString(prefix + "five_min_rate_per_second")) .body(containsString(prefix + "fifteen_min_rate_per_second")) - .body(containsString(prefix + "elapsedTime")) .body(containsString(prefix + "mean_seconds")) .body(containsString(prefix + "min_seconds")) .body(containsString(prefix + "max_seconds")) @@ -725,6 +726,7 @@ public void testApplicationHistogramUnitBytesOpenMetrics() { resp.then().statusCode(200) .and() .body(containsString(prefix + "bytes_count")) + .body(containsString(prefix + "bytes_sum")) .body(containsString("# TYPE application_" + prefix + "bytes summary")) .body(containsString(prefix + "mean_bytes")) .body(containsString(prefix + "min_bytes")) @@ -755,6 +757,7 @@ public void testApplicationHistogramUnitNoneOpenMetrics() { resp.then().statusCode(200) .and() .body(containsString(prefix + "_count")) + .body(containsString(prefix + "_sum")) .body(containsString("# TYPE application_" + prefix + " summary")) .body(containsString(prefix + "_mean")) .body(containsString(prefix + "_min"))