Skip to content

Commit 9af8fdb

Browse files
joshisteDave Syer
authored andcommitted
Expose RichGauges in MetricsEndpoint via PublicMetrics
Fixes spring-projectsgh-1635
1 parent 1f9515c commit 9af8fdb

6 files changed

Lines changed: 216 additions & 14 deletions

File tree

spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/MetricRepositoryAutoConfiguration.java

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,14 @@
2121

2222
import org.springframework.beans.factory.annotation.Autowired;
2323
import org.springframework.beans.factory.annotation.Qualifier;
24+
import org.springframework.boot.actuate.endpoint.PublicMetrics;
25+
import org.springframework.boot.actuate.endpoint.RichGaugeReaderPublicMetrics;
2426
import org.springframework.boot.actuate.metrics.CounterService;
2527
import org.springframework.boot.actuate.metrics.GaugeService;
2628
import org.springframework.boot.actuate.metrics.export.Exporter;
2729
import org.springframework.boot.actuate.metrics.repository.InMemoryMetricRepository;
2830
import org.springframework.boot.actuate.metrics.repository.MetricRepository;
31+
import org.springframework.boot.actuate.metrics.rich.RichGaugeReader;
2932
import org.springframework.boot.actuate.metrics.writer.CodahaleMetricWriter;
3033
import org.springframework.boot.actuate.metrics.writer.CompositeMetricWriter;
3134
import org.springframework.boot.actuate.metrics.writer.DefaultCounterService;
@@ -34,6 +37,7 @@
3437
import org.springframework.boot.actuate.metrics.writer.MetricWriter;
3538
import org.springframework.boot.actuate.metrics.writer.MetricWriterMessageHandler;
3639
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
40+
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
3741
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
3842
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
3943
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;
@@ -69,7 +73,8 @@
6973
* In addition if Codahale's metrics library is on the classpath a {@link MetricRegistry}
7074
* will be created and wired up to the counter and gauge services in addition to the basic
7175
* repository. Users can create Codahale metrics by prefixing their metric names with the
72-
* appropriate type (e.g. "histogram.*", "meter.*").
76+
* appropriate type (e.g. "histogram.*", "meter.*") and sending them to the standard
77+
* <code>GaugeService</code> or <code>CounterService</code>.
7378
* </p>
7479
* <p>
7580
* By default all metric updates go to all {@link MetricWriter} instances in the
@@ -117,6 +122,12 @@ public InMemoryMetricRepository metricRepository() {
117122

118123
}
119124

125+
@Bean
126+
@ConditionalOnBean(RichGaugeReader.class)
127+
public PublicMetrics richGaugePublicMetrics(RichGaugeReader richGaugeReader) {
128+
return new RichGaugeReaderPublicMetrics(richGaugeReader);
129+
}
130+
120131
@Configuration
121132
@ConditionalOnClass(MessageChannel.class)
122133
static class MetricsChannelConfiguration {
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
/*
2+
* Copyright 2012-2014 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.actuate.endpoint;
18+
19+
import java.util.ArrayList;
20+
import java.util.Collection;
21+
import java.util.List;
22+
23+
import org.springframework.boot.actuate.metrics.Metric;
24+
import org.springframework.boot.actuate.metrics.rich.RichGauge;
25+
import org.springframework.boot.actuate.metrics.rich.RichGaugeReader;
26+
import org.springframework.util.Assert;
27+
28+
/**
29+
* {@link PublicMetrics} exposed from a {@link RichGaugeReader}.
30+
*
31+
* @author Johannes Stelzer
32+
* @since 1.2
33+
*/
34+
public class RichGaugeReaderPublicMetrics implements PublicMetrics {
35+
36+
private final RichGaugeReader richGaugeReader;
37+
38+
public RichGaugeReaderPublicMetrics(RichGaugeReader richGaugeReader) {
39+
Assert.notNull(richGaugeReader, "RichGaugeReader must not be null");
40+
this.richGaugeReader = richGaugeReader;
41+
}
42+
43+
@Override
44+
public Collection<Metric<?>> metrics() {
45+
List<Metric<?>> result = new ArrayList<Metric<?>>();
46+
for (RichGauge richGauge : this.richGaugeReader.findAll()) {
47+
result.addAll(convert(richGauge));
48+
}
49+
return result;
50+
}
51+
52+
private List<Metric<?>> convert(RichGauge richGauge) {
53+
List<Metric<?>> result = new ArrayList<Metric<?>>(6);
54+
55+
result.add(new Metric<Double>(richGauge.getName() + RichGauge.AVG, richGauge
56+
.getAverage()));
57+
result.add(new Metric<Double>(richGauge.getName() + RichGauge.VAL, richGauge.getValue()));
58+
result.add(new Metric<Double>(richGauge.getName() + RichGauge.MIN, richGauge.getMin()));
59+
result.add(new Metric<Double>(richGauge.getName() + RichGauge.MAX, richGauge.getMax()));
60+
result.add(new Metric<Double>(richGauge.getName() + RichGauge.ALPHA, richGauge
61+
.getAlpha()));
62+
result.add(new Metric<Long>(richGauge.getName() + RichGauge.COUNT, richGauge.getCount()));
63+
64+
return result;
65+
}
66+
67+
}

spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/rich/MultiMetricRichGaugeReader.java

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,6 @@
3333
*/
3434
public class MultiMetricRichGaugeReader implements RichGaugeReader {
3535

36-
private static final String COUNT = ".count";
37-
private static final String MAX = ".max";
38-
private static final String MIN = ".min";
39-
private static final String AVG = ".avg";
40-
private static final String ALPHA = ".alpha";
41-
private static final String VAL = ".val";
42-
4336
private final MultiMetricRepository repository;
4437

4538
public MultiMetricRichGaugeReader(MultiMetricRepository repository) {
@@ -56,22 +49,22 @@ public RichGauge findOne(String name) {
5649
double max = 0.;
5750
long count = 0;
5851
for (Metric<?> metric : metrics) {
59-
if (metric.getName().endsWith(VAL)) {
52+
if (metric.getName().endsWith(RichGauge.VAL)) {
6053
value = metric.getValue().doubleValue();
6154
}
62-
else if (metric.getName().endsWith(ALPHA)) {
55+
else if (metric.getName().endsWith(RichGauge.ALPHA)) {
6356
alpha = metric.getValue().doubleValue();
6457
}
65-
else if (metric.getName().endsWith(AVG)) {
58+
else if (metric.getName().endsWith(RichGauge.AVG)) {
6659
average = metric.getValue().doubleValue();
6760
}
68-
else if (metric.getName().endsWith(MIN)) {
61+
else if (metric.getName().endsWith(RichGauge.MIN)) {
6962
min = metric.getValue().doubleValue();
7063
}
71-
else if (metric.getName().endsWith(MAX)) {
64+
else if (metric.getName().endsWith(RichGauge.MAX)) {
7265
max = metric.getValue().doubleValue();
7366
}
74-
else if (metric.getName().endsWith(COUNT)) {
67+
else if (metric.getName().endsWith(RichGauge.COUNT)) {
7568
count = metric.getValue().longValue();
7669
}
7770
}

spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/rich/RichGauge.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,13 @@
3131
*/
3232
public final class RichGauge {
3333

34+
public static final String COUNT = ".count";
35+
public static final String MAX = ".max";
36+
public static final String MIN = ".min";
37+
public static final String AVG = ".avg";
38+
public static final String ALPHA = ".alpha";
39+
public static final String VAL = ".val";
40+
3441
private final String name;
3542

3643
private double value;

spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/MetricRepositoryAutoConfigurationTests.java

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,18 @@
1616

1717
package org.springframework.boot.actuate.autoconfigure;
1818

19+
import java.util.Collection;
20+
import java.util.Collections;
1921
import java.util.concurrent.Executor;
2022

2123
import org.junit.Test;
24+
import org.springframework.boot.actuate.endpoint.RichGaugeReaderPublicMetrics;
2225
import org.springframework.boot.actuate.metrics.CounterService;
2326
import org.springframework.boot.actuate.metrics.GaugeService;
2427
import org.springframework.boot.actuate.metrics.Metric;
2528
import org.springframework.boot.actuate.metrics.reader.MetricReader;
29+
import org.springframework.boot.actuate.metrics.rich.RichGauge;
30+
import org.springframework.boot.actuate.metrics.rich.RichGaugeReader;
2631
import org.springframework.boot.actuate.metrics.writer.DefaultCounterService;
2732
import org.springframework.boot.actuate.metrics.writer.DefaultGaugeService;
2833
import org.springframework.boot.actuate.metrics.writer.MetricWriter;
@@ -41,9 +46,11 @@
4146
import static org.junit.Assert.assertNotNull;
4247
import static org.junit.Assert.assertThat;
4348
import static org.junit.Assert.assertTrue;
49+
import static org.junit.Assert.fail;
4450
import static org.mockito.Matchers.any;
4551
import static org.mockito.Mockito.mock;
4652
import static org.mockito.Mockito.verify;
53+
import static org.mockito.Mockito.when;
4754

4855
/**
4956
* Tests for {@link MetricRepositoryAutoConfiguration}.
@@ -115,6 +122,44 @@ public void skipsIfBeansExist() throws Exception {
115122
context.close();
116123
}
117124

125+
@Test
126+
public void richGaugePublicMetrics() {
127+
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(
128+
RichGaugeReaderConfig.class, MetricRepositoryAutoConfiguration.class);
129+
130+
RichGaugeReader richGaugeReader = context.getBean(RichGaugeReader.class);
131+
assertNotNull(richGaugeReader);
132+
when(richGaugeReader.findAll()).thenReturn(
133+
Collections.singletonList(new RichGauge("bar", 3.7d)));
134+
135+
RichGaugeReaderPublicMetrics publicMetrics = context
136+
.getBean(RichGaugeReaderPublicMetrics.class);
137+
assertNotNull(publicMetrics);
138+
139+
Collection<Metric<?>> metrics = publicMetrics.metrics();
140+
assertNotNull(metrics);
141+
assertEquals(metrics.size(), 6);
142+
143+
assertHasMetric(metrics, new Metric<Double>("bar.val", 3.7d));
144+
assertHasMetric(metrics, new Metric<Double>("bar.avg", 3.7d));
145+
assertHasMetric(metrics, new Metric<Double>("bar.min", 3.7d));
146+
assertHasMetric(metrics, new Metric<Double>("bar.max", 3.7d));
147+
assertHasMetric(metrics, new Metric<Double>("bar.alpha", -1.d));
148+
assertHasMetric(metrics, new Metric<Long>("bar.count", 1L));
149+
150+
context.close();
151+
}
152+
153+
private void assertHasMetric(Collection<Metric<?>> metrics, Metric<?> metric) {
154+
for (Metric<?> m : metrics) {
155+
if (m.getValue().equals(metric.getValue())
156+
&& m.getName().equals(metric.getName())) {
157+
return;
158+
}
159+
}
160+
fail("Metric " + metric.toString() + " not found in " + metrics.toString());
161+
}
162+
118163
@Configuration
119164
public static class SyncTaskExecutorConfiguration {
120165

@@ -149,4 +194,12 @@ public CounterService counterService() {
149194
}
150195

151196
}
197+
198+
@Configuration
199+
static class RichGaugeReaderConfig {
200+
@Bean
201+
public RichGaugeReader richGaugeReader() {
202+
return mock(RichGaugeReader.class);
203+
}
204+
}
152205
}
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
/*
2+
* Copyright 2012-2014 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.actuate.endpoint;
18+
19+
import java.util.Date;
20+
import java.util.HashMap;
21+
import java.util.Map;
22+
23+
import org.junit.Test;
24+
import org.springframework.boot.actuate.metrics.Metric;
25+
import org.springframework.boot.actuate.metrics.rich.InMemoryRichGaugeRepository;
26+
27+
import static org.hamcrest.Matchers.equalTo;
28+
import static org.junit.Assert.assertThat;
29+
import static org.junit.Assert.assertTrue;
30+
31+
/**
32+
* Tests for {@link RichGaugeReaderPublicMetrics}.
33+
*
34+
* @author Johannes Stelzer
35+
*/
36+
public class RichGaugeReaderPublicMetricsTests {
37+
38+
@Test
39+
public void testMetrics() throws Exception {
40+
InMemoryRichGaugeRepository repository = new InMemoryRichGaugeRepository();
41+
42+
repository.set(new Metric<Double>("a", 0.d, new Date()));
43+
repository.set(new Metric<Double>("a", 0.5d, new Date()));
44+
45+
RichGaugeReaderPublicMetrics metrics = new RichGaugeReaderPublicMetrics(
46+
repository);
47+
48+
Map<String, Metric<?>> results = new HashMap<String, Metric<?>>();
49+
for (Metric<?> metric : metrics.metrics()) {
50+
results.put(metric.getName(), metric);
51+
}
52+
assertTrue(results.containsKey("a.val"));
53+
assertThat(results.get("a.val").getValue().doubleValue(), equalTo(0.5d));
54+
55+
assertTrue(results.containsKey("a.avg"));
56+
assertThat(results.get("a.avg").getValue().doubleValue(), equalTo(0.25d));
57+
58+
assertTrue(results.containsKey("a.min"));
59+
assertThat(results.get("a.min").getValue().doubleValue(), equalTo(0.0d));
60+
61+
assertTrue(results.containsKey("a.max"));
62+
assertThat(results.get("a.max").getValue().doubleValue(), equalTo(0.5d));
63+
64+
assertTrue(results.containsKey("a.count"));
65+
assertThat(results.get("a.count").getValue().longValue(), equalTo(2L));
66+
67+
assertTrue(results.containsKey("a.alpha"));
68+
assertThat(results.get("a.alpha").getValue().doubleValue(), equalTo(-1.d));
69+
}
70+
71+
}

0 commit comments

Comments
 (0)