diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/MetricRepositoryAutoConfiguration.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/MetricRepositoryAutoConfiguration.java
index be86563129..041386d047 100644
--- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/MetricRepositoryAutoConfiguration.java
+++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/MetricRepositoryAutoConfiguration.java
@@ -21,11 +21,14 @@ import java.util.concurrent.Executor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.boot.actuate.endpoint.PublicMetrics;
+import org.springframework.boot.actuate.endpoint.RichGaugeReaderPublicMetrics;
import org.springframework.boot.actuate.metrics.CounterService;
import org.springframework.boot.actuate.metrics.GaugeService;
import org.springframework.boot.actuate.metrics.export.Exporter;
import org.springframework.boot.actuate.metrics.repository.InMemoryMetricRepository;
import org.springframework.boot.actuate.metrics.repository.MetricRepository;
+import org.springframework.boot.actuate.metrics.rich.RichGaugeReader;
import org.springframework.boot.actuate.metrics.writer.CodahaleMetricWriter;
import org.springframework.boot.actuate.metrics.writer.CompositeMetricWriter;
import org.springframework.boot.actuate.metrics.writer.DefaultCounterService;
@@ -34,6 +37,7 @@ import org.springframework.boot.actuate.metrics.writer.MessageChannelMetricWrite
import org.springframework.boot.actuate.metrics.writer.MetricWriter;
import org.springframework.boot.actuate.metrics.writer.MetricWriterMessageHandler;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;
@@ -69,7 +73,8 @@ import com.codahale.metrics.MetricRegistry;
* In addition if Codahale's metrics library is on the classpath a {@link MetricRegistry}
* will be created and wired up to the counter and gauge services in addition to the basic
* repository. Users can create Codahale metrics by prefixing their metric names with the
- * appropriate type (e.g. "histogram.*", "meter.*").
+ * appropriate type (e.g. "histogram.*", "meter.*") and sending them to the standard
+ * GaugeService
or CounterService
.
*
*
* By default all metric updates go to all {@link MetricWriter} instances in the
@@ -117,6 +122,12 @@ public class MetricRepositoryAutoConfiguration {
}
+ @Bean
+ @ConditionalOnBean(RichGaugeReader.class)
+ public PublicMetrics richGaugePublicMetrics(RichGaugeReader richGaugeReader) {
+ return new RichGaugeReaderPublicMetrics(richGaugeReader);
+ }
+
@Configuration
@ConditionalOnClass(MessageChannel.class)
static class MetricsChannelConfiguration {
diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/RichGaugeReaderPublicMetrics.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/RichGaugeReaderPublicMetrics.java
new file mode 100644
index 0000000000..a644e2926d
--- /dev/null
+++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/RichGaugeReaderPublicMetrics.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2012-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.boot.actuate.endpoint;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import org.springframework.boot.actuate.metrics.Metric;
+import org.springframework.boot.actuate.metrics.rich.RichGauge;
+import org.springframework.boot.actuate.metrics.rich.RichGaugeReader;
+import org.springframework.util.Assert;
+
+/**
+ * {@link PublicMetrics} exposed from a {@link RichGaugeReader}.
+ *
+ * @author Johannes Stelzer
+ * @since 1.2
+ */
+public class RichGaugeReaderPublicMetrics implements PublicMetrics {
+
+ private final RichGaugeReader richGaugeReader;
+
+ public RichGaugeReaderPublicMetrics(RichGaugeReader richGaugeReader) {
+ Assert.notNull(richGaugeReader, "RichGaugeReader must not be null");
+ this.richGaugeReader = richGaugeReader;
+ }
+
+ @Override
+ public Collection> metrics() {
+ List> result = new ArrayList>();
+ for (RichGauge richGauge : this.richGaugeReader.findAll()) {
+ result.addAll(convert(richGauge));
+ }
+ return result;
+ }
+
+ private List> convert(RichGauge richGauge) {
+ List> result = new ArrayList>(6);
+
+ result.add(new Metric(richGauge.getName() + RichGauge.AVG, richGauge
+ .getAverage()));
+ result.add(new Metric(richGauge.getName() + RichGauge.VAL, richGauge.getValue()));
+ result.add(new Metric(richGauge.getName() + RichGauge.MIN, richGauge.getMin()));
+ result.add(new Metric(richGauge.getName() + RichGauge.MAX, richGauge.getMax()));
+ result.add(new Metric(richGauge.getName() + RichGauge.ALPHA, richGauge
+ .getAlpha()));
+ result.add(new Metric(richGauge.getName() + RichGauge.COUNT, richGauge.getCount()));
+
+ return result;
+ }
+
+}
diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/rich/MultiMetricRichGaugeReader.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/rich/MultiMetricRichGaugeReader.java
index 047d5fc2c3..40d4dbf19c 100644
--- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/rich/MultiMetricRichGaugeReader.java
+++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/rich/MultiMetricRichGaugeReader.java
@@ -33,13 +33,6 @@ import org.springframework.boot.actuate.metrics.repository.MultiMetricRepository
*/
public class MultiMetricRichGaugeReader implements RichGaugeReader {
- private static final String COUNT = ".count";
- private static final String MAX = ".max";
- private static final String MIN = ".min";
- private static final String AVG = ".avg";
- private static final String ALPHA = ".alpha";
- private static final String VAL = ".val";
-
private final MultiMetricRepository repository;
public MultiMetricRichGaugeReader(MultiMetricRepository repository) {
@@ -56,22 +49,22 @@ public class MultiMetricRichGaugeReader implements RichGaugeReader {
double max = 0.;
long count = 0;
for (Metric> metric : metrics) {
- if (metric.getName().endsWith(VAL)) {
+ if (metric.getName().endsWith(RichGauge.VAL)) {
value = metric.getValue().doubleValue();
}
- else if (metric.getName().endsWith(ALPHA)) {
+ else if (metric.getName().endsWith(RichGauge.ALPHA)) {
alpha = metric.getValue().doubleValue();
}
- else if (metric.getName().endsWith(AVG)) {
+ else if (metric.getName().endsWith(RichGauge.AVG)) {
average = metric.getValue().doubleValue();
}
- else if (metric.getName().endsWith(MIN)) {
+ else if (metric.getName().endsWith(RichGauge.MIN)) {
min = metric.getValue().doubleValue();
}
- else if (metric.getName().endsWith(MAX)) {
+ else if (metric.getName().endsWith(RichGauge.MAX)) {
max = metric.getValue().doubleValue();
}
- else if (metric.getName().endsWith(COUNT)) {
+ else if (metric.getName().endsWith(RichGauge.COUNT)) {
count = metric.getValue().longValue();
}
}
diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/rich/RichGauge.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/rich/RichGauge.java
index 6ba418e332..c5677fd8e3 100644
--- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/rich/RichGauge.java
+++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/rich/RichGauge.java
@@ -31,6 +31,13 @@ import org.springframework.util.Assert;
*/
public final class RichGauge {
+ public static final String COUNT = ".count";
+ public static final String MAX = ".max";
+ public static final String MIN = ".min";
+ public static final String AVG = ".avg";
+ public static final String ALPHA = ".alpha";
+ public static final String VAL = ".val";
+
private final String name;
private double value;
diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/MetricRepositoryAutoConfigurationTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/MetricRepositoryAutoConfigurationTests.java
index 4cba627a57..59c848f376 100644
--- a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/MetricRepositoryAutoConfigurationTests.java
+++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/MetricRepositoryAutoConfigurationTests.java
@@ -16,13 +16,18 @@
package org.springframework.boot.actuate.autoconfigure;
+import java.util.Collection;
+import java.util.Collections;
import java.util.concurrent.Executor;
import org.junit.Test;
+import org.springframework.boot.actuate.endpoint.RichGaugeReaderPublicMetrics;
import org.springframework.boot.actuate.metrics.CounterService;
import org.springframework.boot.actuate.metrics.GaugeService;
import org.springframework.boot.actuate.metrics.Metric;
import org.springframework.boot.actuate.metrics.reader.MetricReader;
+import org.springframework.boot.actuate.metrics.rich.RichGauge;
+import org.springframework.boot.actuate.metrics.rich.RichGaugeReader;
import org.springframework.boot.actuate.metrics.writer.DefaultCounterService;
import org.springframework.boot.actuate.metrics.writer.DefaultGaugeService;
import org.springframework.boot.actuate.metrics.writer.MetricWriter;
@@ -41,9 +46,11 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
/**
* Tests for {@link MetricRepositoryAutoConfiguration}.
@@ -115,6 +122,44 @@ public class MetricRepositoryAutoConfigurationTests {
context.close();
}
+ @Test
+ public void richGaugePublicMetrics() {
+ AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(
+ RichGaugeReaderConfig.class, MetricRepositoryAutoConfiguration.class);
+
+ RichGaugeReader richGaugeReader = context.getBean(RichGaugeReader.class);
+ assertNotNull(richGaugeReader);
+ when(richGaugeReader.findAll()).thenReturn(
+ Collections.singletonList(new RichGauge("bar", 3.7d)));
+
+ RichGaugeReaderPublicMetrics publicMetrics = context
+ .getBean(RichGaugeReaderPublicMetrics.class);
+ assertNotNull(publicMetrics);
+
+ Collection> metrics = publicMetrics.metrics();
+ assertNotNull(metrics);
+ assertEquals(metrics.size(), 6);
+
+ assertHasMetric(metrics, new Metric("bar.val", 3.7d));
+ assertHasMetric(metrics, new Metric("bar.avg", 3.7d));
+ assertHasMetric(metrics, new Metric("bar.min", 3.7d));
+ assertHasMetric(metrics, new Metric("bar.max", 3.7d));
+ assertHasMetric(metrics, new Metric("bar.alpha", -1.d));
+ assertHasMetric(metrics, new Metric("bar.count", 1L));
+
+ context.close();
+ }
+
+ private void assertHasMetric(Collection> metrics, Metric> metric) {
+ for (Metric> m : metrics) {
+ if (m.getValue().equals(metric.getValue())
+ && m.getName().equals(metric.getName())) {
+ return;
+ }
+ }
+ fail("Metric " + metric.toString() + " not found in " + metrics.toString());
+ }
+
@Configuration
public static class SyncTaskExecutorConfiguration {
@@ -149,4 +194,12 @@ public class MetricRepositoryAutoConfigurationTests {
}
}
+
+ @Configuration
+ static class RichGaugeReaderConfig {
+ @Bean
+ public RichGaugeReader richGaugeReader() {
+ return mock(RichGaugeReader.class);
+ }
+ }
}
diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/RichGaugeReaderPublicMetricsTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/RichGaugeReaderPublicMetricsTests.java
new file mode 100644
index 0000000000..d21bdd3bbf
--- /dev/null
+++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/RichGaugeReaderPublicMetricsTests.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2012-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.boot.actuate.endpoint;
+
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.junit.Test;
+import org.springframework.boot.actuate.metrics.Metric;
+import org.springframework.boot.actuate.metrics.rich.InMemoryRichGaugeRepository;
+
+import static org.hamcrest.Matchers.equalTo;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Tests for {@link RichGaugeReaderPublicMetrics}.
+ *
+ * @author Johannes Stelzer
+ */
+public class RichGaugeReaderPublicMetricsTests {
+
+ @Test
+ public void testMetrics() throws Exception {
+ InMemoryRichGaugeRepository repository = new InMemoryRichGaugeRepository();
+
+ repository.set(new Metric("a", 0.d, new Date()));
+ repository.set(new Metric("a", 0.5d, new Date()));
+
+ RichGaugeReaderPublicMetrics metrics = new RichGaugeReaderPublicMetrics(
+ repository);
+
+ Map> results = new HashMap>();
+ for (Metric> metric : metrics.metrics()) {
+ results.put(metric.getName(), metric);
+ }
+ assertTrue(results.containsKey("a.val"));
+ assertThat(results.get("a.val").getValue().doubleValue(), equalTo(0.5d));
+
+ assertTrue(results.containsKey("a.avg"));
+ assertThat(results.get("a.avg").getValue().doubleValue(), equalTo(0.25d));
+
+ assertTrue(results.containsKey("a.min"));
+ assertThat(results.get("a.min").getValue().doubleValue(), equalTo(0.0d));
+
+ assertTrue(results.containsKey("a.max"));
+ assertThat(results.get("a.max").getValue().doubleValue(), equalTo(0.5d));
+
+ assertTrue(results.containsKey("a.count"));
+ assertThat(results.get("a.count").getValue().longValue(), equalTo(2L));
+
+ assertTrue(results.containsKey("a.alpha"));
+ assertThat(results.get("a.alpha").getValue().doubleValue(), equalTo(-1.d));
+ }
+
+}