Refactor PublicMetrics registration

Rework flexible PublicMetrics registration introduced in 2be6b3e4 to
restore compatibility with v1.1 VanillaPublicMetrics. The new
MetricReaderPublicMetrics class now exposes metrics from a MetricReader
and VanillaPublicMetrics is deprecated. The MetricsEndpoint can now
exposes a collection of PublicMetric interface directly.

See gh-1094
This commit is contained in:
Phillip Webb 2014-07-29 12:31:40 -07:00
parent 8e0b3dd00a
commit 14c6243637
11 changed files with 254 additions and 99 deletions

View File

@ -16,9 +16,11 @@
package org.springframework.boot.actuate.autoconfigure; package org.springframework.boot.actuate.autoconfigure;
import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Properties; import java.util.Properties;
@ -32,13 +34,13 @@ import org.springframework.boot.actuate.endpoint.Endpoint;
import org.springframework.boot.actuate.endpoint.EnvironmentEndpoint; import org.springframework.boot.actuate.endpoint.EnvironmentEndpoint;
import org.springframework.boot.actuate.endpoint.HealthEndpoint; import org.springframework.boot.actuate.endpoint.HealthEndpoint;
import org.springframework.boot.actuate.endpoint.InfoEndpoint; import org.springframework.boot.actuate.endpoint.InfoEndpoint;
import org.springframework.boot.actuate.endpoint.MetricReaderPublicMetrics;
import org.springframework.boot.actuate.endpoint.MetricsEndpoint; import org.springframework.boot.actuate.endpoint.MetricsEndpoint;
import org.springframework.boot.actuate.endpoint.PublicMetrics; import org.springframework.boot.actuate.endpoint.PublicMetrics;
import org.springframework.boot.actuate.endpoint.RequestMappingEndpoint; import org.springframework.boot.actuate.endpoint.RequestMappingEndpoint;
import org.springframework.boot.actuate.endpoint.ShutdownEndpoint; import org.springframework.boot.actuate.endpoint.ShutdownEndpoint;
import org.springframework.boot.actuate.endpoint.SystemPublicMetrics; import org.springframework.boot.actuate.endpoint.SystemPublicMetrics;
import org.springframework.boot.actuate.endpoint.TraceEndpoint; import org.springframework.boot.actuate.endpoint.TraceEndpoint;
import org.springframework.boot.actuate.endpoint.VanillaPublicMetrics;
import org.springframework.boot.actuate.health.HealthAggregator; import org.springframework.boot.actuate.health.HealthAggregator;
import org.springframework.boot.actuate.health.HealthIndicator; import org.springframework.boot.actuate.health.HealthIndicator;
import org.springframework.boot.actuate.health.OrderedHealthAggregator; import org.springframework.boot.actuate.health.OrderedHealthAggregator;
@ -85,10 +87,10 @@ public class EndpointAutoConfiguration {
Map<String, HealthIndicator> healthIndicators = new HashMap<String, HealthIndicator>(); Map<String, HealthIndicator> healthIndicators = new HashMap<String, HealthIndicator>();
@Autowired(required = false) @Autowired(required = false)
private MetricReader metricRepository = new InMemoryMetricRepository(); private MetricReader metricReader = new InMemoryMetricRepository();
@Autowired(required = false) @Autowired(required = false)
private Collection<PublicMetrics> allMetrics; private Collection<PublicMetrics> publicMetrics;
@Autowired(required = false) @Autowired(required = false)
private TraceRepository traceRepository = new InMemoryTraceRepository(); private TraceRepository traceRepository = new InMemoryTraceRepository();
@ -129,8 +131,13 @@ public class EndpointAutoConfiguration {
@Bean @Bean
@ConditionalOnMissingBean @ConditionalOnMissingBean
public MetricsEndpoint metricsEndpoint() { public MetricsEndpoint metricsEndpoint() {
PublicMetrics metrics = new VanillaPublicMetrics(this.metricRepository, this.allMetrics); List<PublicMetrics> publicMetrics = new ArrayList<PublicMetrics>();
return new MetricsEndpoint(metrics); publicMetrics.add(new SystemPublicMetrics());
publicMetrics.add(new MetricReaderPublicMetrics(this.metricReader));
if (this.publicMetrics != null) {
publicMetrics.addAll(this.publicMetrics);
}
return new MetricsEndpoint(publicMetrics);
} }
@Bean @Bean
@ -158,19 +165,6 @@ public class EndpointAutoConfiguration {
return new ShutdownEndpoint(); return new ShutdownEndpoint();
} }
@Configuration
@ConditionalOnClass(AbstractHandlerMethodMapping.class)
protected static class RequestMappingEndpointConfiguration {
@Bean
@ConditionalOnMissingBean
public RequestMappingEndpoint requestMappingEndpoint() {
RequestMappingEndpoint endpoint = new RequestMappingEndpoint();
return endpoint;
}
}
@Bean @Bean
@ConditionalOnMissingBean @ConditionalOnMissingBean
public ConfigurationPropertiesReportEndpoint configurationPropertiesReportEndpoint() { public ConfigurationPropertiesReportEndpoint configurationPropertiesReportEndpoint() {
@ -180,11 +174,14 @@ public class EndpointAutoConfiguration {
} }
@Configuration @Configuration
protected static class CorePublicMetrics { @ConditionalOnClass(AbstractHandlerMethodMapping.class)
protected static class RequestMappingEndpointConfiguration {
@Bean @Bean
SystemPublicMetrics systemPublicMetrics() { @ConditionalOnMissingBean
return new SystemPublicMetrics(); public RequestMappingEndpoint requestMappingEndpoint() {
RequestMappingEndpoint endpoint = new RequestMappingEndpoint();
return endpoint;
} }
} }

View File

@ -0,0 +1,53 @@
/*
* 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.reader.MetricReader;
import org.springframework.util.Assert;
/**
* {@link PublicMetrics} exposed from a {@link MetricReader}.
*
* @author Dave Syer
* @author Christian Dupuis
* @author Stephane Nicoll
* @author Phillip Webb
*/
public class MetricReaderPublicMetrics implements PublicMetrics {
private final MetricReader metricReader;
public MetricReaderPublicMetrics(MetricReader metricReader) {
Assert.notNull(metricReader, "MetricReader must not be null");
this.metricReader = metricReader;
}
@Override
public Collection<Metric<?>> metrics() {
List<Metric<?>> result = new ArrayList<Metric<?>>();
for (Metric<?> metric : this.metricReader.findAll()) {
result.add(metric);
}
return result;
}
}

View File

@ -16,40 +16,56 @@
package org.springframework.boot.actuate.endpoint; package org.springframework.boot.actuate.endpoint;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map; import java.util.Map;
import org.springframework.boot.actuate.metrics.Metric; import org.springframework.boot.actuate.metrics.Metric;
import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
import org.springframework.util.Assert; import org.springframework.util.Assert;
/** /**
* {@link Endpoint} to expose {@link PublicMetrics}. * {@link Endpoint} to expose a collection of {@link PublicMetrics}.
* *
* @author Dave Syer * @author Dave Syer
*/ */
@ConfigurationProperties(prefix = "endpoints.metrics", ignoreUnknownFields = false) @ConfigurationProperties(prefix = "endpoints.metrics", ignoreUnknownFields = false)
public class MetricsEndpoint extends AbstractEndpoint<Map<String, Object>> { public class MetricsEndpoint extends AbstractEndpoint<Map<String, Object>> {
private final PublicMetrics metrics; private final List<PublicMetrics> publicMetrics;
/** /**
* Create a new {@link MetricsEndpoint} instance. * Create a new {@link MetricsEndpoint} instance.
* * @param publicMetrics the metrics to expose
* @param metrics the metrics to expose
*/ */
public MetricsEndpoint(PublicMetrics metrics) { public MetricsEndpoint(PublicMetrics publicMetrics) {
this(Collections.singleton(publicMetrics));
}
/**
* Create a new {@link MetricsEndpoint} instance.
* @param publicMetrics the metrics to expose. The collection will be sorted using the
* {@link AnnotationAwareOrderComparator}.
*/
public MetricsEndpoint(Collection<PublicMetrics> publicMetrics) {
super("metrics"); super("metrics");
Assert.notNull(metrics, "Metrics must not be null"); Assert.notNull(publicMetrics, "PublicMetrics must not be null");
this.metrics = metrics; this.publicMetrics = new ArrayList<PublicMetrics>(publicMetrics);
AnnotationAwareOrderComparator.sort(this.publicMetrics);
} }
@Override @Override
public Map<String, Object> invoke() { public Map<String, Object> invoke() {
Map<String, Object> result = new LinkedHashMap<String, Object>(); Map<String, Object> result = new LinkedHashMap<String, Object>();
for (Metric<?> metric : this.metrics.metrics()) { for (PublicMetrics publicMetric : this.publicMetrics) {
for (Metric<?> metric : publicMetric.metrics()) {
result.put(metric.getName(), metric.getValue()); result.put(metric.getName(), metric.getValue());
} }
}
return result; return result;
} }

View File

@ -26,6 +26,7 @@ import java.util.LinkedHashSet;
import java.util.List; import java.util.List;
import org.springframework.boot.actuate.metrics.Metric; import org.springframework.boot.actuate.metrics.Metric;
import org.springframework.core.Ordered;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
/** /**
@ -36,7 +37,7 @@ import org.springframework.util.StringUtils;
* @author Stephane Nicoll * @author Stephane Nicoll
* @since 1.2.0 * @since 1.2.0
*/ */
public class SystemPublicMetrics implements PublicMetrics { public class SystemPublicMetrics implements PublicMetrics, Ordered {
private long timestamp; private long timestamp;
@ -44,16 +45,19 @@ public class SystemPublicMetrics implements PublicMetrics {
this.timestamp = System.currentTimeMillis(); this.timestamp = System.currentTimeMillis();
} }
@Override
public int getOrder() {
return Ordered.HIGHEST_PRECEDENCE + 10;
}
@Override @Override
public Collection<Metric<?>> metrics() { public Collection<Metric<?>> metrics() {
Collection<Metric<?>> result = new LinkedHashSet<Metric<?>>(); Collection<Metric<?>> result = new LinkedHashSet<Metric<?>>();
addBasicMetrics(result); addBasicMetrics(result);
addHeapMetrics(result); addHeapMetrics(result);
addThreadMetrics(result); addThreadMetrics(result);
addClassLoadingMetrics(result); addClassLoadingMetrics(result);
addGarbageCollectionMetrics(result); addGarbageCollectionMetrics(result);
return result; return result;
} }

View File

@ -17,7 +17,6 @@
package org.springframework.boot.actuate.endpoint; package org.springframework.boot.actuate.endpoint;
import java.util.Collection; import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashSet; import java.util.LinkedHashSet;
import org.springframework.boot.actuate.metrics.Metric; import org.springframework.boot.actuate.metrics.Metric;
@ -26,27 +25,21 @@ import org.springframework.util.Assert;
/** /**
* Default implementation of {@link PublicMetrics} that exposes all metrics from a * Default implementation of {@link PublicMetrics} that exposes all metrics from a
* {@link MetricReader} along with a collection of configurable {@link PublicMetrics} * {@link MetricReader} along with memory information.
* instances.
* *
* @author Dave Syer * @author Dave Syer
* @author Christian Dupuis * @author Christian Dupuis
* @author Stephane Nicoll * @deprecated since 1.2 in favor of {@link SystemPublicMetrics},
* {@code MetricReaderPublicMetrics}
*/ */
public class VanillaPublicMetrics implements PublicMetrics { @Deprecated
public class VanillaPublicMetrics extends SystemPublicMetrics {
private final MetricReader reader; private final MetricReader reader;
private final Collection<PublicMetrics> publicMetrics;
public VanillaPublicMetrics(MetricReader reader, Collection<PublicMetrics> publicMetrics) {
Assert.notNull(reader, "MetricReader must not be null");
Assert.notNull(publicMetrics, "PublicMetrics must not be null");
this.reader = reader;
this.publicMetrics = publicMetrics;
}
public VanillaPublicMetrics(MetricReader reader) { public VanillaPublicMetrics(MetricReader reader) {
this(reader, Collections.<PublicMetrics>emptyList()); Assert.notNull(reader, "MetricReader must not be null");
this.reader = reader;
} }
@Override @Override
@ -55,10 +48,7 @@ public class VanillaPublicMetrics implements PublicMetrics {
for (Metric<?> metric : this.reader.findAll()) { for (Metric<?> metric : this.reader.findAll()) {
result.add(metric); result.add(metric);
} }
for (PublicMetrics publicMetric : publicMetrics) { result.addAll(super.metrics());
result.addAll(publicMetric.metrics());
}
return result; return result;
} }

View File

@ -16,6 +16,10 @@
package org.springframework.boot.actuate.autoconfigure; package org.springframework.boot.actuate.autoconfigure;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import org.junit.After; import org.junit.After;
import org.junit.Test; import org.junit.Test;
import org.springframework.boot.actuate.endpoint.AutoConfigurationReportEndpoint; import org.springframework.boot.actuate.endpoint.AutoConfigurationReportEndpoint;
@ -43,10 +47,6 @@ import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull; import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
/** /**
* Tests for {@link EndpointAutoConfiguration}. * Tests for {@link EndpointAutoConfiguration}.
* *
@ -83,8 +83,8 @@ public class EndpointAutoConfigurationTests {
@Test @Test
public void healthEndpoint() { public void healthEndpoint() {
load(EmbeddedDataSourceConfiguration.class, load(EmbeddedDataSourceConfiguration.class, EndpointAutoConfiguration.class,
EndpointAutoConfiguration.class, HealthIndicatorAutoConfiguration.class); HealthIndicatorAutoConfiguration.class);
HealthEndpoint bean = this.context.getBean(HealthEndpoint.class); HealthEndpoint bean = this.context.getBean(HealthEndpoint.class);
assertNotNull(bean); assertNotNull(bean);
Health result = bean.invoke(); Health result = bean.invoke();
@ -94,8 +94,7 @@ public class EndpointAutoConfigurationTests {
@Test @Test
public void healthEndpointWithDefaultHealthIndicator() { public void healthEndpointWithDefaultHealthIndicator() {
load(EndpointAutoConfiguration.class, load(EndpointAutoConfiguration.class, HealthIndicatorAutoConfiguration.class);
HealthIndicatorAutoConfiguration.class);
HealthEndpoint bean = this.context.getBean(HealthEndpoint.class); HealthEndpoint bean = this.context.getBean(HealthEndpoint.class);
assertNotNull(bean); assertNotNull(bean);
Health result = bean.invoke(); Health result = bean.invoke();
@ -128,8 +127,7 @@ public class EndpointAutoConfigurationTests {
@Test @Test
public void autoConfigurationAuditEndpoints() { public void autoConfigurationAuditEndpoints() {
load(EndpointAutoConfiguration.class, load(EndpointAutoConfiguration.class, ConditionEvaluationReport.class);
ConditionEvaluationReport.class);
assertNotNull(this.context.getBean(AutoConfigurationReportEndpoint.class)); assertNotNull(this.context.getBean(AutoConfigurationReportEndpoint.class));
} }
@ -163,7 +161,6 @@ public class EndpointAutoConfigurationTests {
this.context.refresh(); this.context.refresh();
} }
@Configuration @Configuration
static class CustomPublicMetricsConfig { static class CustomPublicMetricsConfig {
@ -172,9 +169,11 @@ public class EndpointAutoConfigurationTests {
return new PublicMetrics() { return new PublicMetrics() {
@Override @Override
public Collection<Metric<?>> metrics() { public Collection<Metric<?>> metrics() {
return Collections.<Metric<?>>singleton(new Metric<Integer>("foo", 1)); Metric<Integer> metric = new Metric<Integer>("foo", 1);
return Collections.<Metric<?>> singleton(metric);
} }
}; };
} }
} }
} }

View File

@ -0,0 +1,48 @@
/*
* 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.List;
import org.junit.Test;
import org.springframework.boot.actuate.metrics.Metric;
import org.springframework.boot.actuate.metrics.reader.MetricReader;
import static org.junit.Assert.assertEquals;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
/**
* Tests for {@link MetricReaderPublicMetrics}.
*
* @author Phillip Webb
*/
public class MetricReaderPublicMetricsTests {
@Test
public void exposesMetrics() {
List<Metric<?>> metrics = new ArrayList<Metric<?>>();
metrics.add(mock(Metric.class));
metrics.add(mock(Metric.class));
MetricReader reader = mock(MetricReader.class);
given(reader.findAll()).willReturn(metrics);
MetricReaderPublicMetrics publicMetrics = new MetricReaderPublicMetrics(reader);
assertEquals(metrics, publicMetrics.metrics());
}
}

View File

@ -16,16 +16,25 @@
package org.springframework.boot.actuate.endpoint; package org.springframework.boot.actuate.endpoint;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.junit.Test; import org.junit.Test;
import org.springframework.boot.actuate.metrics.Metric; import org.springframework.boot.actuate.metrics.Metric;
import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.equalTo;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertThat; import static org.junit.Assert.assertThat;
/** /**
@ -35,6 +44,12 @@ import static org.junit.Assert.assertThat;
*/ */
public class MetricsEndpointTests extends AbstractEndpointTests<MetricsEndpoint> { public class MetricsEndpointTests extends AbstractEndpointTests<MetricsEndpoint> {
private Metric<Number> metric1 = new Metric<Number>("a", 1);
private Metric<Number> metric2 = new Metric<Number>("b", 2);;
private Metric<Number> metric3 = new Metric<Number>("c", 3);;
public MetricsEndpointTests() { public MetricsEndpointTests() {
super(Config.class, MetricsEndpoint.class, "metrics", true, "endpoints.metrics"); super(Config.class, MetricsEndpoint.class, "metrics", true, "endpoints.metrics");
} }
@ -44,6 +59,43 @@ public class MetricsEndpointTests extends AbstractEndpointTests<MetricsEndpoint>
assertThat(getEndpointBean().invoke().get("a"), equalTo((Object) 0.5f)); assertThat(getEndpointBean().invoke().get("a"), equalTo((Object) 0.5f));
} }
@Test
public void ordered() {
List<PublicMetrics> publicMetrics = new ArrayList<PublicMetrics>();
publicMetrics.add(new TestPublicMetrics(2, this.metric2, this.metric2,
this.metric3));
publicMetrics.add(new TestPublicMetrics(1, this.metric1));
Map<String, Object> metrics = new MetricsEndpoint(publicMetrics).invoke();
Iterator<Entry<String, Object>> iterator = metrics.entrySet().iterator();
assertEquals("a", iterator.next().getKey());
assertEquals("b", iterator.next().getKey());
assertEquals("c", iterator.next().getKey());
assertFalse(iterator.hasNext());
}
private static class TestPublicMetrics implements PublicMetrics, Ordered {
private final int order;
private final List<Metric<?>> metrics;
public TestPublicMetrics(int order, Metric<?>... metrics) {
this.order = order;
this.metrics = Arrays.asList(metrics);
}
@Override
public int getOrder() {
return this.order;
}
@Override
public Collection<Metric<?>> metrics() {
return this.metrics;
}
}
@Configuration @Configuration
@EnableConfigurationProperties @EnableConfigurationProperties
public static class Config { public static class Config {

View File

@ -16,15 +16,14 @@
package org.springframework.boot.actuate.endpoint; package org.springframework.boot.actuate.endpoint;
import static org.junit.Assert.*;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import org.junit.Test; import org.junit.Test;
import org.springframework.boot.actuate.metrics.Metric; import org.springframework.boot.actuate.metrics.Metric;
import static org.junit.Assert.assertTrue;
/** /**
* Tests for {@link SystemPublicMetrics} * Tests for {@link SystemPublicMetrics}
* *

View File

@ -16,12 +16,8 @@
package org.springframework.boot.actuate.endpoint; package org.springframework.boot.actuate.endpoint;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date; import java.util.Date;
import java.util.HashMap; import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.Map; import java.util.Map;
import org.junit.Test; import org.junit.Test;
@ -29,15 +25,16 @@ import org.springframework.boot.actuate.metrics.Metric;
import org.springframework.boot.actuate.metrics.repository.InMemoryMetricRepository; import org.springframework.boot.actuate.metrics.repository.InMemoryMetricRepository;
import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.equalTo;
import static org.junit.Assert.*; import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
/** /**
* Tests for {@link VanillaPublicMetrics}. * Tests for {@link VanillaPublicMetrics}.
* *
* @author Phillip Webb * @author Phillip Webb
* @author Christian Dupuis * @author Christian Dupuis
* @author Stephane Nicoll
*/ */
@Deprecated
public class VanillaPublicMetricsTests { public class VanillaPublicMetricsTests {
@Test @Test
@ -49,38 +46,36 @@ public class VanillaPublicMetricsTests {
for (Metric<?> metric : publicMetrics.metrics()) { for (Metric<?> metric : publicMetrics.metrics()) {
results.put(metric.getName(), metric); results.put(metric.getName(), metric);
} }
assertTrue(results.containsKey("mem"));
assertTrue(results.containsKey("mem.free"));
assertThat(results.get("a").getValue().doubleValue(), equalTo(0.5)); assertThat(results.get("a").getValue().doubleValue(), equalTo(0.5));
} }
@Test @Test
public void testAdditionalMetrics() throws Exception { public void testSystemMetrics() throws Exception {
InMemoryMetricRepository repository = new InMemoryMetricRepository(); InMemoryMetricRepository repository = new InMemoryMetricRepository();
Collection<PublicMetrics> allMetrics = new ArrayList<PublicMetrics>(); repository.set(new Metric<Double>("a", 0.5, new Date()));
allMetrics.add(new ImmutablePublicMetrics(new Metric<Number>("first", 2L))); VanillaPublicMetrics publicMetrics = new VanillaPublicMetrics(repository);
allMetrics.add(new ImmutablePublicMetrics(new Metric<Number>("second", 4L)));
VanillaPublicMetrics publicMetrics = new VanillaPublicMetrics(repository, allMetrics);
Map<String, Metric<?>> results = new HashMap<String, Metric<?>>(); Map<String, Metric<?>> results = new HashMap<String, Metric<?>>();
for (Metric<?> metric : publicMetrics.metrics()) { for (Metric<?> metric : publicMetrics.metrics()) {
results.put(metric.getName(), metric); results.put(metric.getName(), metric);
} }
assertTrue(results.containsKey("first")); assertTrue(results.containsKey("mem"));
assertTrue(results.containsKey("second")); assertTrue(results.containsKey("mem.free"));
assertEquals(2, results.size()); assertTrue(results.containsKey("processors"));
} assertTrue(results.containsKey("uptime"));
assertTrue(results.containsKey("heap.committed"));
assertTrue(results.containsKey("heap.init"));
assertTrue(results.containsKey("heap.used"));
assertTrue(results.containsKey("heap"));
private static class ImmutablePublicMetrics implements PublicMetrics { assertTrue(results.containsKey("threads.peak"));
private final Collection<Metric<?>> metrics; assertTrue(results.containsKey("threads.daemon"));
assertTrue(results.containsKey("threads"));
private ImmutablePublicMetrics(Metric<?> metrics) { assertTrue(results.containsKey("classes.loaded"));
this.metrics = new LinkedHashSet<Metric<?>>(); assertTrue(results.containsKey("classes.unloaded"));
this.metrics.addAll(Arrays.asList(metrics)); assertTrue(results.containsKey("classes"));
}
@Override
public Collection<Metric<?>> metrics() {
return metrics;
}
} }
} }

View File

@ -585,12 +585,12 @@ Spring Boot Actuator includes a metrics service with ``gauge'' and ``counter'' s
A ``gauge'' records a single value; and a ``counter'' records a delta (an increment or A ``gauge'' records a single value; and a ``counter'' records a delta (an increment or
decrement). Spring Boot Actuator also provides a decrement). Spring Boot Actuator also provides a
{sc-spring-boot-actuator}/endpoint/PublicMetrics.{sc-ext}[`PublicMetrics`] interface that {sc-spring-boot-actuator}/endpoint/PublicMetrics.{sc-ext}[`PublicMetrics`] interface that
you can implement to expose metrics that you cannot record via one of those two mechanisms. Look you can implement to expose metrics that you cannot record via one of those two
at {sc-spring-boot-actuator}/endpoint/SystemPublicMetrics.{sc-ext}[`SystemPublicMetrics`] mechanisms. Look at {sc-spring-boot-actuator}/endpoint/SystemPublicMetrics.{sc-ext}[`SystemPublicMetrics`]
for an example. for an example.
Metrics for all HTTP requests are automatically recorded, so if you hit the Metrics for all HTTP requests are automatically recorded, so if you hit the `metrics`
`metrics` endpoint you should see a response similar to this: endpoint you should see a response similar to this:
[source,json,indent=0] [source,json,indent=0]
---- ----
@ -668,15 +668,17 @@ TIP: You can use any string as a metric name but you should follow guidelines of
store/graphing technology. Some good guidelines for Graphite are available on store/graphing technology. Some good guidelines for Graphite are available on
http://matt.aimonetti.net/posts/2013/06/26/practical-guide-to-graphite-monitoring/[Matt Aimonetti's Blog]. http://matt.aimonetti.net/posts/2013/06/26/practical-guide-to-graphite-monitoring/[Matt Aimonetti's Blog].
[[production-ready-public-metrics]] [[production-ready-public-metrics]]
=== Adding your own public metrics === Adding your own public metrics
To add additional metrics that are computed every time the metrics endpoint is invoked, To add additional metrics that are computed every time the metrics endpoint is invoked,
simply register additional `PublicMetrics` implementation bean(s). By default, all such simply register additional `PublicMetrics` implementation bean(s). By default, all such
beans are gathered by the endpoint. You can easily change that by defining your own beans are gathered by the endpoint. You can easily change that by defining your own
`MetricsEndpoint`. `MetricsEndpoint`.
[[production-ready-metric-repositories]] [[production-ready-metric-repositories]]
=== Metric repositories === Metric repositories
Metric service implementations are usually bound to a Metric service implementations are usually bound to a