Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package org.springframework.boot.actuate.metrics;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
Expand Down Expand Up @@ -82,8 +83,7 @@ public MetricResponse metric(@Selector String requiredMetricName,
@Nullable List<String> tag) {
List<Tag> tags = parseTags(tag);
List<Meter> meters = new ArrayList<>();
collectMeters(meters, this.registry, requiredMetricName, tags);
if (meters.isEmpty()) {
if (!findFirstMatchingMeters(meters, this.registry, requiredMetricName, tags)) {
return null;
}
Map<Statistic, Double> samples = getSamples(meters);
Expand Down Expand Up @@ -112,15 +112,20 @@ private Tag parseTag(String tag) {
return Tag.of(parts[0], parts[1]);
}

private void collectMeters(List<Meter> meters, MeterRegistry registry, String name,
Iterable<Tag> tags) {
private boolean findFirstMatchingMeters(List<Meter> meters, MeterRegistry registry,
Copy link
Contributor

Choose a reason for hiding this comment

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

Rather than modifying a parameter, this method could simply return a Collection.

String name, Iterable<Tag> tags) {
if (registry instanceof CompositeMeterRegistry) {
((CompositeMeterRegistry) registry).getRegistries()
.forEach((member) -> collectMeters(meters, member, name, tags));
return ((CompositeMeterRegistry) registry).getRegistries().stream()
.anyMatch((r) -> findFirstMatchingMeters(meters, r, name, tags));
}
else {
meters.addAll(registry.find(name).tags(tags).meters());
Collection<Meter> meterFound = registry.find(name).tags(tags).meters();
if (meterFound != null && meterFound.size() > 0) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Micrometer guarantees that meterFound is non-null. Could use isEmpty() on second condition.

meters.addAll(meterFound);
return true;
}
}
return false;
}

private Map<Statistic, Double> getSamples(List<Meter> meters) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,55 @@ public void metricValuesAreTheSumOfAllTimeSeriesMatchingTags() {
assertThat(getCount(response)).hasValue(4.0);
}

@Test
public void findFirstMatchingMetersFromNestedRegistries() {
CompositeMeterRegistry composite = new CompositeMeterRegistry();
SimpleMeterRegistry reg1 = new SimpleMeterRegistry();
CompositeMeterRegistry reg2 = new CompositeMeterRegistry();
SimpleMeterRegistry reg3 = new SimpleMeterRegistry();

// 1st level nesting
composite.add(reg1);

// 2st level nesting
reg2.add(reg3);
composite.add(reg2);

// 2nd level registry has metrics
reg3.counter("cache", "result", "hit", "host", "1").increment(2);
reg3.counter("cache", "result", "miss", "host", "1").increment(2);
reg3.counter("cache", "result", "hit", "host", "2").increment(2);

MetricsEndpoint endpoint = new MetricsEndpoint(composite);

MetricsEndpoint.MetricResponse response = endpoint.metric("cache",
Collections.emptyList());
assertThat(response.getName()).isEqualTo("cache");
assertThat(availableTagKeys(response)).containsExactly("result", "host");
assertThat(getCount(response)).hasValue(6.0);

response = endpoint.metric("cache", Collections.singletonList("result:hit"));
assertThat(availableTagKeys(response)).containsExactly("host");
assertThat(getCount(response)).hasValue(4.0);
}

@Test
public void matchingMeterNotFoundInNestedRegistries() {
CompositeMeterRegistry composite = new CompositeMeterRegistry();
CompositeMeterRegistry reg2 = new CompositeMeterRegistry();
SimpleMeterRegistry reg3 = new SimpleMeterRegistry();

// nested registries
reg2.add(reg3);
composite.add(reg2);

MetricsEndpoint endpoint = new MetricsEndpoint(composite);

MetricsEndpoint.MetricResponse response = endpoint.metric("invalid.metric.name",
Collections.emptyList());
assertThat(response).isNull();
}

@Test
public void metricTagValuesAreDeduplicated() {
this.registry.counter("cache", "host", "1", "region", "east", "result", "hit");
Expand Down