Flexible registration of additional PublicMetrics
This commit permits the use of several PublicMetrics instances by default. Previously, only one PublicMetrics service could be specified and a user configuration would remove all the defaulting. VanillaPublicMetrics now takes a collection of PublicMetrics and invokes them in sequence to build the final collection of metrics. The system-related metrics have been moved to SystemPublicMetrics and are registered by default. Also updated the documentation to mention this feature and how it could be fully overridden. Fixes gh-1094
This commit is contained in:
parent
99971a6578
commit
2be6b3e419
|
@ -16,6 +16,7 @@
|
||||||
|
|
||||||
package org.springframework.boot.actuate.autoconfigure;
|
package org.springframework.boot.actuate.autoconfigure;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
@ -35,6 +36,7 @@ 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.TraceEndpoint;
|
import org.springframework.boot.actuate.endpoint.TraceEndpoint;
|
||||||
import org.springframework.boot.actuate.endpoint.VanillaPublicMetrics;
|
import org.springframework.boot.actuate.endpoint.VanillaPublicMetrics;
|
||||||
import org.springframework.boot.actuate.health.HealthAggregator;
|
import org.springframework.boot.actuate.health.HealthAggregator;
|
||||||
|
@ -68,6 +70,7 @@ import org.springframework.web.servlet.handler.AbstractHandlerMethodMapping;
|
||||||
* @author Phillip Webb
|
* @author Phillip Webb
|
||||||
* @author Greg Turnquist
|
* @author Greg Turnquist
|
||||||
* @author Christian Dupuis
|
* @author Christian Dupuis
|
||||||
|
* @author Stephane Nicoll
|
||||||
*/
|
*/
|
||||||
@Configuration
|
@Configuration
|
||||||
public class EndpointAutoConfiguration {
|
public class EndpointAutoConfiguration {
|
||||||
|
@ -85,7 +88,7 @@ public class EndpointAutoConfiguration {
|
||||||
private MetricReader metricRepository = new InMemoryMetricRepository();
|
private MetricReader metricRepository = new InMemoryMetricRepository();
|
||||||
|
|
||||||
@Autowired(required = false)
|
@Autowired(required = false)
|
||||||
private PublicMetrics metrics;
|
private Collection<PublicMetrics> allMetrics;
|
||||||
|
|
||||||
@Autowired(required = false)
|
@Autowired(required = false)
|
||||||
private TraceRepository traceRepository = new InMemoryTraceRepository();
|
private TraceRepository traceRepository = new InMemoryTraceRepository();
|
||||||
|
@ -126,10 +129,8 @@ public class EndpointAutoConfiguration {
|
||||||
@Bean
|
@Bean
|
||||||
@ConditionalOnMissingBean
|
@ConditionalOnMissingBean
|
||||||
public MetricsEndpoint metricsEndpoint() {
|
public MetricsEndpoint metricsEndpoint() {
|
||||||
if (this.metrics == null) {
|
PublicMetrics metrics = new VanillaPublicMetrics(this.metricRepository, this.allMetrics);
|
||||||
this.metrics = new VanillaPublicMetrics(this.metricRepository);
|
return new MetricsEndpoint(metrics);
|
||||||
}
|
|
||||||
return new MetricsEndpoint(this.metrics);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
|
@ -178,6 +179,16 @@ public class EndpointAutoConfiguration {
|
||||||
return endpoint;
|
return endpoint;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
protected static class CorePublicMetrics {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
SystemPublicMetrics systemPublicMetrics() {
|
||||||
|
return new SystemPublicMetrics();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
protected static class InfoPropertiesConfiguration {
|
protected static class InfoPropertiesConfiguration {
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,7 @@ import org.springframework.boot.actuate.metrics.Metric;
|
||||||
*
|
*
|
||||||
* @author Dave Syer
|
* @author Dave Syer
|
||||||
* @see VanillaPublicMetrics
|
* @see VanillaPublicMetrics
|
||||||
|
* @see SystemPublicMetrics
|
||||||
*/
|
*/
|
||||||
public interface PublicMetrics {
|
public interface PublicMetrics {
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,136 @@
|
||||||
|
/*
|
||||||
|
* 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.lang.management.ClassLoadingMXBean;
|
||||||
|
import java.lang.management.GarbageCollectorMXBean;
|
||||||
|
import java.lang.management.ManagementFactory;
|
||||||
|
import java.lang.management.MemoryUsage;
|
||||||
|
import java.lang.management.ThreadMXBean;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.springframework.boot.actuate.metrics.Metric;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A {@link PublicMetrics} implementation that provides various
|
||||||
|
* system-related metrics.
|
||||||
|
*
|
||||||
|
* @author Dave Syer
|
||||||
|
* @author Stephane Nicoll
|
||||||
|
* @since 1.2.0
|
||||||
|
*/
|
||||||
|
public class SystemPublicMetrics implements PublicMetrics {
|
||||||
|
|
||||||
|
private long timestamp;
|
||||||
|
|
||||||
|
public SystemPublicMetrics() {
|
||||||
|
this.timestamp = System.currentTimeMillis();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<Metric<?>> metrics() {
|
||||||
|
Collection<Metric<?>> result = new LinkedHashSet<Metric<?>>();
|
||||||
|
|
||||||
|
addBasicMetrics(result);
|
||||||
|
addHeapMetrics(result);
|
||||||
|
addThreadMetrics(result);
|
||||||
|
addClassLoadingMetrics(result);
|
||||||
|
addGarbageCollectionMetrics(result);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add basic system metrics.
|
||||||
|
*/
|
||||||
|
protected void addBasicMetrics(Collection<Metric<?>> result) {
|
||||||
|
result.add(new Metric<Long>("mem",
|
||||||
|
Runtime.getRuntime().totalMemory() / 1024));
|
||||||
|
result.add(new Metric<Long>("mem.free", Runtime.getRuntime()
|
||||||
|
.freeMemory() / 1024));
|
||||||
|
result.add(new Metric<Integer>("processors", Runtime.getRuntime()
|
||||||
|
.availableProcessors()));
|
||||||
|
// Add JVM up time in ms
|
||||||
|
result.add(new Metric<Long>("uptime", ManagementFactory
|
||||||
|
.getRuntimeMXBean().getUptime()));
|
||||||
|
result.add(new Metric<Long>("instance.uptime", System.currentTimeMillis()
|
||||||
|
- this.timestamp));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add JVM heap metrics.
|
||||||
|
*/
|
||||||
|
protected void addHeapMetrics(Collection<Metric<?>> result) {
|
||||||
|
MemoryUsage memoryUsage = ManagementFactory.getMemoryMXBean()
|
||||||
|
.getHeapMemoryUsage();
|
||||||
|
result.add(new Metric<Long>("heap.committed", memoryUsage.getCommitted() / 1024));
|
||||||
|
result.add(new Metric<Long>("heap.init", memoryUsage.getInit() / 1024));
|
||||||
|
result.add(new Metric<Long>("heap.used", memoryUsage.getUsed() / 1024));
|
||||||
|
result.add(new Metric<Long>("heap", memoryUsage.getMax() / 1024));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add thread metrics.
|
||||||
|
*/
|
||||||
|
protected void addThreadMetrics(Collection<Metric<?>> result) {
|
||||||
|
ThreadMXBean threadMxBean = ManagementFactory.getThreadMXBean();
|
||||||
|
result.add(new Metric<Long>("threads.peak", (long) threadMxBean
|
||||||
|
.getPeakThreadCount()));
|
||||||
|
result.add(new Metric<Long>("threads.daemon", (long) threadMxBean
|
||||||
|
.getDaemonThreadCount()));
|
||||||
|
result.add(new Metric<Long>("threads", (long) threadMxBean.getThreadCount()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add class loading metrics.
|
||||||
|
*/
|
||||||
|
protected void addClassLoadingMetrics(Collection<Metric<?>> result) {
|
||||||
|
ClassLoadingMXBean classLoadingMxBean = ManagementFactory.getClassLoadingMXBean();
|
||||||
|
result.add(new Metric<Long>("classes", (long) classLoadingMxBean
|
||||||
|
.getLoadedClassCount()));
|
||||||
|
result.add(new Metric<Long>("classes.loaded", classLoadingMxBean
|
||||||
|
.getTotalLoadedClassCount()));
|
||||||
|
result.add(new Metric<Long>("classes.unloaded", classLoadingMxBean
|
||||||
|
.getUnloadedClassCount()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add garbage collection metrics.
|
||||||
|
*/
|
||||||
|
protected void addGarbageCollectionMetrics(Collection<Metric<?>> result) {
|
||||||
|
List<GarbageCollectorMXBean> garbageCollectorMxBeans = ManagementFactory
|
||||||
|
.getGarbageCollectorMXBeans();
|
||||||
|
for (GarbageCollectorMXBean garbageCollectorMXBean : garbageCollectorMxBeans) {
|
||||||
|
String name = beautifyGcName(garbageCollectorMXBean.getName());
|
||||||
|
result.add(new Metric<Long>("gc." + name + ".count", garbageCollectorMXBean.getCollectionCount()));
|
||||||
|
result.add(new Metric<Long>("gc." + name + ".time", garbageCollectorMXBean.getCollectionTime()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Turn GC names like 'PS Scavenge' or 'PS MarkSweep' into something that is more
|
||||||
|
* metrics friendly.
|
||||||
|
*/
|
||||||
|
private String beautifyGcName(String name) {
|
||||||
|
return StringUtils.replace(name, " ", "_").toLowerCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -16,36 +16,37 @@
|
||||||
|
|
||||||
package org.springframework.boot.actuate.endpoint;
|
package org.springframework.boot.actuate.endpoint;
|
||||||
|
|
||||||
import java.lang.management.ClassLoadingMXBean;
|
|
||||||
import java.lang.management.GarbageCollectorMXBean;
|
|
||||||
import java.lang.management.ManagementFactory;
|
|
||||||
import java.lang.management.MemoryUsage;
|
|
||||||
import java.lang.management.ThreadMXBean;
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.LinkedHashSet;
|
import java.util.LinkedHashSet;
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.springframework.boot.actuate.metrics.Metric;
|
import org.springframework.boot.actuate.metrics.Metric;
|
||||||
import org.springframework.boot.actuate.metrics.reader.MetricReader;
|
import org.springframework.boot.actuate.metrics.reader.MetricReader;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
import org.springframework.util.StringUtils;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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 memory information.
|
* {@link MetricReader} along with a collection of configurable {@link PublicMetrics}
|
||||||
|
* instances.
|
||||||
*
|
*
|
||||||
* @author Dave Syer
|
* @author Dave Syer
|
||||||
* @author Christian Dupuis
|
* @author Christian Dupuis
|
||||||
|
* @author Stephane Nicoll
|
||||||
*/
|
*/
|
||||||
public class VanillaPublicMetrics implements PublicMetrics {
|
public class VanillaPublicMetrics implements PublicMetrics {
|
||||||
|
|
||||||
private final MetricReader reader;
|
private final MetricReader reader;
|
||||||
private long timestamp;
|
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) {
|
||||||
Assert.notNull(reader, "MetricReader must not be null");
|
this(reader, Collections.<PublicMetrics>emptyList());
|
||||||
this.reader = reader;
|
|
||||||
this.timestamp = System.currentTimeMillis();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -54,92 +55,11 @@ 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) {
|
||||||
addMetrics(result);
|
result.addAll(publicMetric.metrics());
|
||||||
addHeapMetrics(result);
|
}
|
||||||
addThreadMetrics(result);
|
|
||||||
addClassLoadingMetrics(result);
|
|
||||||
addGarbageCollecitonMetrics(result);
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Add basic system metrics.
|
|
||||||
*/
|
|
||||||
protected void addMetrics(Collection<Metric<?>> result) {
|
|
||||||
result.add(new Metric<Long>("mem",
|
|
||||||
new Long(Runtime.getRuntime().totalMemory()) / 1024));
|
|
||||||
result.add(new Metric<Long>("mem.free", new Long(Runtime.getRuntime()
|
|
||||||
.freeMemory()) / 1024));
|
|
||||||
result.add(new Metric<Integer>("processors", Runtime.getRuntime()
|
|
||||||
.availableProcessors()));
|
|
||||||
// Add JVM uptime in ms
|
|
||||||
result.add(new Metric<Long>("uptime", new Long(ManagementFactory
|
|
||||||
.getRuntimeMXBean().getUptime())));
|
|
||||||
result.add(new Metric<Long>("instance.uptime", System.currentTimeMillis()
|
|
||||||
- this.timestamp));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add JVM heap metrics.
|
|
||||||
*/
|
|
||||||
protected void addHeapMetrics(Collection<Metric<?>> result) {
|
|
||||||
MemoryUsage memoryUsage = ManagementFactory.getMemoryMXBean()
|
|
||||||
.getHeapMemoryUsage();
|
|
||||||
result.add(new Metric<Long>("heap.committed", memoryUsage.getCommitted() / 1024));
|
|
||||||
result.add(new Metric<Long>("heap.init", memoryUsage.getInit() / 1024));
|
|
||||||
result.add(new Metric<Long>("heap.used", memoryUsage.getUsed() / 1024));
|
|
||||||
result.add(new Metric<Long>("heap", memoryUsage.getMax() / 1024));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add thread metrics.
|
|
||||||
*/
|
|
||||||
protected void addThreadMetrics(Collection<Metric<?>> result) {
|
|
||||||
ThreadMXBean threadMxBean = ManagementFactory.getThreadMXBean();
|
|
||||||
result.add(new Metric<Long>("threads.peak", new Long(threadMxBean
|
|
||||||
.getPeakThreadCount())));
|
|
||||||
result.add(new Metric<Long>("threads.daemon", new Long(threadMxBean
|
|
||||||
.getDaemonThreadCount())));
|
|
||||||
result.add(new Metric<Long>("threads", new Long(threadMxBean.getThreadCount())));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add class loading metrics.
|
|
||||||
*/
|
|
||||||
protected void addClassLoadingMetrics(Collection<Metric<?>> result) {
|
|
||||||
ClassLoadingMXBean classLoadingMxBean = ManagementFactory.getClassLoadingMXBean();
|
|
||||||
result.add(new Metric<Long>("classes", new Long(classLoadingMxBean
|
|
||||||
.getLoadedClassCount())));
|
|
||||||
result.add(new Metric<Long>("classes.loaded", new Long(classLoadingMxBean
|
|
||||||
.getTotalLoadedClassCount())));
|
|
||||||
result.add(new Metric<Long>("classes.unloaded", new Long(classLoadingMxBean
|
|
||||||
.getUnloadedClassCount())));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add garbage collection metrics.
|
|
||||||
*/
|
|
||||||
protected void addGarbageCollecitonMetrics(Collection<Metric<?>> result) {
|
|
||||||
List<GarbageCollectorMXBean> garbageCollectorMxBeans = ManagementFactory
|
|
||||||
.getGarbageCollectorMXBeans();
|
|
||||||
for (int i = 0; i < garbageCollectorMxBeans.size(); i++) {
|
|
||||||
GarbageCollectorMXBean garbageCollectorMXBean = garbageCollectorMxBeans
|
|
||||||
.get(i);
|
|
||||||
String name = beautifyGcName(garbageCollectorMXBean.getName());
|
|
||||||
result.add(new Metric<Long>("gc." + name + ".count", new Long(
|
|
||||||
garbageCollectorMXBean.getCollectionCount())));
|
|
||||||
result.add(new Metric<Long>("gc." + name + ".time", new Long(
|
|
||||||
garbageCollectorMXBean.getCollectionTime())));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Turn GC names like 'PS Scavenge' or 'PS MarkSweep' into something that is more
|
|
||||||
* metrics friendly.
|
|
||||||
*/
|
|
||||||
private String beautifyGcName(String name) {
|
|
||||||
return StringUtils.replace(name, " ", "_").toLowerCase();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,6 @@
|
||||||
package org.springframework.boot.actuate.autoconfigure;
|
package org.springframework.boot.actuate.autoconfigure;
|
||||||
|
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
import org.junit.Before;
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.springframework.boot.actuate.endpoint.AutoConfigurationReportEndpoint;
|
import org.springframework.boot.actuate.endpoint.AutoConfigurationReportEndpoint;
|
||||||
import org.springframework.boot.actuate.endpoint.BeansEndpoint;
|
import org.springframework.boot.actuate.endpoint.BeansEndpoint;
|
||||||
|
@ -26,20 +25,28 @@ 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.MetricsEndpoint;
|
import org.springframework.boot.actuate.endpoint.MetricsEndpoint;
|
||||||
|
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.TraceEndpoint;
|
import org.springframework.boot.actuate.endpoint.TraceEndpoint;
|
||||||
import org.springframework.boot.actuate.health.Health;
|
import org.springframework.boot.actuate.health.Health;
|
||||||
|
import org.springframework.boot.actuate.metrics.Metric;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionEvaluationReport;
|
import org.springframework.boot.autoconfigure.condition.ConditionEvaluationReport;
|
||||||
import org.springframework.boot.autoconfigure.jdbc.EmbeddedDataSourceConfiguration;
|
import org.springframework.boot.autoconfigure.jdbc.EmbeddedDataSourceConfiguration;
|
||||||
import org.springframework.boot.test.EnvironmentTestUtils;
|
import org.springframework.boot.test.EnvironmentTestUtils;
|
||||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertNotNull;
|
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}.
|
||||||
*
|
*
|
||||||
|
@ -47,18 +54,12 @@ import static org.junit.Assert.assertTrue;
|
||||||
* @author Phillip Webb
|
* @author Phillip Webb
|
||||||
* @author Greg Turnquist
|
* @author Greg Turnquist
|
||||||
* @author Christian Dupuis
|
* @author Christian Dupuis
|
||||||
|
* @author Stephane Nicoll
|
||||||
*/
|
*/
|
||||||
public class EndpointAutoConfigurationTests {
|
public class EndpointAutoConfigurationTests {
|
||||||
|
|
||||||
private AnnotationConfigApplicationContext context;
|
private AnnotationConfigApplicationContext context;
|
||||||
|
|
||||||
@Before
|
|
||||||
public void setup() {
|
|
||||||
this.context = new AnnotationConfigApplicationContext();
|
|
||||||
this.context.register(EndpointAutoConfiguration.class);
|
|
||||||
this.context.refresh();
|
|
||||||
}
|
|
||||||
|
|
||||||
@After
|
@After
|
||||||
public void close() {
|
public void close() {
|
||||||
if (this.context != null) {
|
if (this.context != null) {
|
||||||
|
@ -68,6 +69,7 @@ public class EndpointAutoConfigurationTests {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void endpoints() throws Exception {
|
public void endpoints() throws Exception {
|
||||||
|
load(EndpointAutoConfiguration.class);
|
||||||
assertNotNull(this.context.getBean(BeansEndpoint.class));
|
assertNotNull(this.context.getBean(BeansEndpoint.class));
|
||||||
assertNotNull(this.context.getBean(DumpEndpoint.class));
|
assertNotNull(this.context.getBean(DumpEndpoint.class));
|
||||||
assertNotNull(this.context.getBean(EnvironmentEndpoint.class));
|
assertNotNull(this.context.getBean(EnvironmentEndpoint.class));
|
||||||
|
@ -81,10 +83,8 @@ public class EndpointAutoConfigurationTests {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void healthEndpoint() {
|
public void healthEndpoint() {
|
||||||
this.context = new AnnotationConfigApplicationContext();
|
load(EmbeddedDataSourceConfiguration.class,
|
||||||
this.context.register(EmbeddedDataSourceConfiguration.class,
|
|
||||||
EndpointAutoConfiguration.class, HealthIndicatorAutoConfiguration.class);
|
EndpointAutoConfiguration.class, HealthIndicatorAutoConfiguration.class);
|
||||||
this.context.refresh();
|
|
||||||
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,10 +94,8 @@ public class EndpointAutoConfigurationTests {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void healthEndpointWithDefaultHealthIndicator() {
|
public void healthEndpointWithDefaultHealthIndicator() {
|
||||||
this.context = new AnnotationConfigApplicationContext();
|
load(EndpointAutoConfiguration.class,
|
||||||
this.context.register(EndpointAutoConfiguration.class,
|
|
||||||
HealthIndicatorAutoConfiguration.class);
|
HealthIndicatorAutoConfiguration.class);
|
||||||
this.context.refresh();
|
|
||||||
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();
|
||||||
|
@ -105,11 +103,33 @@ public class EndpointAutoConfigurationTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void autoconfigurationAuditEndpoints() {
|
public void metricEndpointsHasSystemMetricsByDefault() {
|
||||||
this.context = new AnnotationConfigApplicationContext();
|
load(EndpointAutoConfiguration.class);
|
||||||
this.context.register(EndpointAutoConfiguration.class,
|
MetricsEndpoint endpoint = this.context.getBean(MetricsEndpoint.class);
|
||||||
|
Map<String, Object> metrics = endpoint.invoke();
|
||||||
|
assertTrue(metrics.containsKey("mem"));
|
||||||
|
assertTrue(metrics.containsKey("heap.used"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void metricEndpointCustomPublicMetrics() {
|
||||||
|
load(CustomPublicMetricsConfig.class, EndpointAutoConfiguration.class);
|
||||||
|
MetricsEndpoint endpoint = this.context.getBean(MetricsEndpoint.class);
|
||||||
|
Map<String, Object> metrics = endpoint.invoke();
|
||||||
|
|
||||||
|
// Custom metrics
|
||||||
|
assertTrue(metrics.containsKey("foo"));
|
||||||
|
|
||||||
|
// System metrics still available
|
||||||
|
assertTrue(metrics.containsKey("mem"));
|
||||||
|
assertTrue(metrics.containsKey("heap.used"));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void autoConfigurationAuditEndpoints() {
|
||||||
|
load(EndpointAutoConfiguration.class,
|
||||||
ConditionEvaluationReport.class);
|
ConditionEvaluationReport.class);
|
||||||
this.context.refresh();
|
|
||||||
assertNotNull(this.context.getBean(AutoConfigurationReportEndpoint.class));
|
assertNotNull(this.context.getBean(AutoConfigurationReportEndpoint.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -136,4 +156,25 @@ public class EndpointAutoConfigurationTests {
|
||||||
assertNotNull(endpoint);
|
assertNotNull(endpoint);
|
||||||
assertNull(endpoint.invoke().get("git"));
|
assertNull(endpoint.invoke().get("git"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void load(Class<?>... config) {
|
||||||
|
this.context = new AnnotationConfigApplicationContext();
|
||||||
|
this.context.register(config);
|
||||||
|
this.context.refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
static class CustomPublicMetricsConfig {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
PublicMetrics customPublicMetrics() {
|
||||||
|
return new PublicMetrics() {
|
||||||
|
@Override
|
||||||
|
public Collection<Metric<?>> metrics() {
|
||||||
|
return Collections.<Metric<?>>singleton(new Metric<Integer>("foo", 1));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,61 @@
|
||||||
|
/*
|
||||||
|
* 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 static org.junit.Assert.*;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import org.springframework.boot.actuate.metrics.Metric;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests for {@link SystemPublicMetrics}
|
||||||
|
*
|
||||||
|
* @author Stephane Nicoll
|
||||||
|
*/
|
||||||
|
public class SystemPublicMetricsTests {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSystemMetrics() throws Exception {
|
||||||
|
SystemPublicMetrics publicMetrics = new SystemPublicMetrics();
|
||||||
|
Map<String, Metric<?>> results = new HashMap<String, Metric<?>>();
|
||||||
|
for (Metric<?> metric : publicMetrics.metrics()) {
|
||||||
|
results.put(metric.getName(), metric);
|
||||||
|
}
|
||||||
|
assertTrue(results.containsKey("mem"));
|
||||||
|
assertTrue(results.containsKey("mem.free"));
|
||||||
|
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"));
|
||||||
|
|
||||||
|
assertTrue(results.containsKey("threads.peak"));
|
||||||
|
assertTrue(results.containsKey("threads.daemon"));
|
||||||
|
assertTrue(results.containsKey("threads"));
|
||||||
|
|
||||||
|
assertTrue(results.containsKey("classes.loaded"));
|
||||||
|
assertTrue(results.containsKey("classes.unloaded"));
|
||||||
|
assertTrue(results.containsKey("classes"));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -16,8 +16,12 @@
|
||||||
|
|
||||||
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;
|
||||||
|
@ -25,14 +29,14 @@ 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.assertThat;
|
import static org.junit.Assert.*;
|
||||||
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
|
||||||
*/
|
*/
|
||||||
public class VanillaPublicMetricsTests {
|
public class VanillaPublicMetricsTests {
|
||||||
|
|
||||||
|
@ -45,36 +49,38 @@ 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 testSystemMetrics() throws Exception {
|
public void testAdditionalMetrics() throws Exception {
|
||||||
InMemoryMetricRepository repository = new InMemoryMetricRepository();
|
InMemoryMetricRepository repository = new InMemoryMetricRepository();
|
||||||
repository.set(new Metric<Double>("a", 0.5, new Date()));
|
Collection<PublicMetrics> allMetrics = new ArrayList<PublicMetrics>();
|
||||||
VanillaPublicMetrics publicMetrics = new VanillaPublicMetrics(repository);
|
allMetrics.add(new ImmutablePublicMetrics(new Metric<Number>("first", 2L)));
|
||||||
|
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("mem"));
|
assertTrue(results.containsKey("first"));
|
||||||
assertTrue(results.containsKey("mem.free"));
|
assertTrue(results.containsKey("second"));
|
||||||
assertTrue(results.containsKey("processors"));
|
assertEquals(2, results.size());
|
||||||
assertTrue(results.containsKey("uptime"));
|
}
|
||||||
|
|
||||||
assertTrue(results.containsKey("heap.committed"));
|
|
||||||
assertTrue(results.containsKey("heap.init"));
|
|
||||||
assertTrue(results.containsKey("heap.used"));
|
|
||||||
assertTrue(results.containsKey("heap"));
|
|
||||||
|
|
||||||
assertTrue(results.containsKey("threads.peak"));
|
private static class ImmutablePublicMetrics implements PublicMetrics {
|
||||||
assertTrue(results.containsKey("threads.daemon"));
|
private final Collection<Metric<?>> metrics;
|
||||||
assertTrue(results.containsKey("threads"));
|
|
||||||
|
|
||||||
assertTrue(results.containsKey("classes.loaded"));
|
private ImmutablePublicMetrics(Metric<?> metrics) {
|
||||||
assertTrue(results.containsKey("classes.unloaded"));
|
this.metrics = new LinkedHashSet<Metric<?>>();
|
||||||
assertTrue(results.containsKey("classes"));
|
this.metrics.addAll(Arrays.asList(metrics));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<Metric<?>> metrics() {
|
||||||
|
return metrics;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -583,8 +583,14 @@ documentation].
|
||||||
== Metrics
|
== Metrics
|
||||||
Spring Boot Actuator includes a metrics service with ``gauge'' and ``counter'' support.
|
Spring Boot Actuator includes a metrics service with ``gauge'' and ``counter'' support.
|
||||||
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). Metrics for all HTTP requests are automatically recorded, so if you hit the
|
decrement). Spring Boot Actuator also provides a
|
||||||
`metrics` endpoint should should see a response similar to this:
|
{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
|
||||||
|
at {sc-spring-boot-actuator}/endpoint/SystemPublicMetrics.{sc-ext}[`SystemPublicMetrics`]
|
||||||
|
for an example.
|
||||||
|
|
||||||
|
Metrics for all HTTP requests are automatically recorded, so if you hit the
|
||||||
|
`metrics` endpoint you should see a response similar to this:
|
||||||
|
|
||||||
[source,json,indent=0]
|
[source,json,indent=0]
|
||||||
----
|
----
|
||||||
|
@ -612,9 +618,10 @@ decrement). Metrics for all HTTP requests are automatically recorded, so if you
|
||||||
----
|
----
|
||||||
|
|
||||||
Here we can see basic `memory`, `heap`, `class loading`, `processor` and `thread pool`
|
Here we can see basic `memory`, `heap`, `class loading`, `processor` and `thread pool`
|
||||||
information along with some HTTP metrics. In this instance the `root` (``/'') and `/metrics`
|
information provided by `SystemPublicMetrics` along with some HTTP metrics. In this
|
||||||
URLs have returned `HTTP 200` responses `20` and `3` times respectively. It also appears
|
instance the `root` (``/'') and `/metrics` URLs have returned `HTTP 200` responses `20`
|
||||||
that the `root` URL returned `HTTP 401` (unauthorized) `4` times.
|
and `3` times respectively. It also appears that the `root` URL returned `HTTP 401`
|
||||||
|
(unauthorized) `4` times.
|
||||||
|
|
||||||
The `gauge` shows the last response time for a request. So the last request to `root` took
|
The `gauge` shows the last response time for a request. So the last request to `root` took
|
||||||
`2ms` to respond and the last to `/metrics` took `3ms`.
|
`2ms` to respond and the last to `/metrics` took `3ms`.
|
||||||
|
@ -661,6 +668,13 @@ 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]]
|
||||||
|
=== Adding your own public metrics
|
||||||
|
|
||||||
|
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
|
||||||
|
beans are gathered by the endpoint. You can easily change that by defining your own
|
||||||
|
`MetricsEndpoint`.
|
||||||
|
|
||||||
|
|
||||||
[[production-ready-metric-repositories]]
|
[[production-ready-metric-repositories]]
|
||||||
|
|
Loading…
Reference in New Issue