Skip to content

Commit 04aeded

Browse files
authored
Fixed micrometer histograms to be non-cumulative (#3264)
1 parent 2a2f864 commit 04aeded

File tree

4 files changed

+23
-14
lines changed

4 files changed

+23
-14
lines changed

CHANGELOG.asciidoc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,10 @@ Use subheadings with the "=====" level for adding notes for unreleased changes:
3535
===== Features
3636
* Added virtual thread support - {pull}#3239[#3239]
3737
38+
[float]
39+
===== Bug fixes
40+
* Fixed Micrometer histograms to be correctly exported with non-cumulative bucket counts - {pull}3264[#3264]
41+
3842
[[release-notes-1.x]]
3943
=== Java Agent version 1.x
4044

apm-agent-plugins/apm-micrometer-plugin/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
<dependency>
3030
<groupId>io.micrometer</groupId>
3131
<artifactId>micrometer-core</artifactId>
32-
<version>1.11.1</version>
32+
<version>1.11.2</version>
3333
<scope>provided</scope>
3434
</dependency>
3535
<dependency>

apm-agent-plugins/apm-micrometer-plugin/src/main/java/co/elastic/apm/agent/micrometer/MicrometerMeterRegistrySerializer.java

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,12 @@
1919
package co.elastic.apm.agent.micrometer;
2020

2121
import co.elastic.apm.agent.report.serialize.DslJsonSerializer;
22+
import co.elastic.apm.agent.sdk.internal.util.PrivilegedActionUtils;
2223
import co.elastic.apm.agent.sdk.logging.Logger;
2324
import co.elastic.apm.agent.sdk.logging.LoggerFactory;
2425
import co.elastic.apm.agent.sdk.weakconcurrent.WeakConcurrent;
2526
import co.elastic.apm.agent.sdk.weakconcurrent.WeakSet;
2627
import co.elastic.apm.agent.tracer.configuration.MetricsConfiguration;
27-
import co.elastic.apm.agent.sdk.internal.util.PrivilegedActionUtils;
2828
import com.dslplatform.json.DslJson;
2929
import com.dslplatform.json.JsonWriter;
3030
import com.dslplatform.json.NumberConverter;
@@ -258,11 +258,17 @@ private static void serializeHistogram(Meter.Id id, HistogramSnapshot histogramS
258258
jw.writeByte(JsonWriter.QUOTE);
259259
jw.writeByte(JsonWriter.SEMI);
260260
jw.writeByte(JsonWriter.ARRAY_START);
261+
// Micrometer bucket counts are cumulative: E.g. the count at bucket with upper
262+
// boundary X is the total number of observations smaller than X
263+
// including values which have already been counted for smaller buckets.
264+
// Elastic however expects non-cumulative bucket counts
261265
if (bucket.length > 0) {
262266
NumberConverter.serialize((long) bucket[0].count(), jw);
267+
double prevBucketCount = bucket[0].count();
263268
for (int i = 1; i < bucket.length; i++) {
264269
jw.writeByte(JsonWriter.COMMA);
265-
NumberConverter.serialize((long) bucket[i].count(), jw);
270+
NumberConverter.serialize((long) (bucket[i].count() - prevBucketCount), jw);
271+
prevBucketCount = bucket[i].count();
266272
}
267273
}
268274
jw.writeByte(JsonWriter.ARRAY_END);

apm-agent-plugins/apm-micrometer-plugin/src/test/java/co/elastic/apm/agent/micrometer/MicrometerMeterRegistrySerializerTest.java

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -264,8 +264,8 @@ static class TestSummary extends TestMeter {
264264
int sum = 0;
265265
int count = 0;
266266
int under5Count = 0;
267-
int under50Count = 0;
268-
int under95Count = 0;
267+
int from5To50Count = 0;
268+
int from50to95Count = 0;
269269
int[] values = new int[]{22, 55, 66, 98};
270270

271271
@Override
@@ -278,7 +278,8 @@ public void addToMeterRegistry(MeterRegistry registry) {
278278
meter = DistributionSummary
279279
.builder(metername())
280280
.distributionStatisticBufferLength(20)
281-
.serviceLevelObjectives(5,50,95)
281+
.serviceLevelObjectives(5, 50, 95)
282+
.publishPercentileHistogram()
282283
.register(registry);
283284
}
284285

@@ -290,12 +291,10 @@ public void populateValues() {
290291
sum += val;
291292
if (val < 5) {
292293
under5Count++;
293-
}
294-
if (val < 50) {
295-
under50Count++;
296-
}
297-
if (val < 95) {
298-
under95Count++;
294+
} else if (val < 50) {
295+
from5To50Count++;
296+
} else if (val < 95) {
297+
from50to95Count++;
299298
}
300299
}
301300
}
@@ -317,8 +316,8 @@ public void checkSerialization(JsonNode jsonNode) {
317316
assertThat(histoNode2.isArray()).isTrue();
318317
assertThat(histoNode2.size()).isEqualTo(3); //the 3 counts of samples under boundaries of the SLOs 5,50,95
319318
assertThat(histoNode2.get(0).asInt()).isEqualTo(under5Count);
320-
assertThat(histoNode2.get(1).asInt()).isEqualTo(under50Count);
321-
assertThat(histoNode2.get(2).asInt()).isEqualTo(under95Count);
319+
assertThat(histoNode2.get(1).asInt()).isEqualTo(from5To50Count);
320+
assertThat(histoNode2.get(2).asInt()).isEqualTo(from50to95Count);
322321
}
323322
}
324323

0 commit comments

Comments
 (0)