From a66fc3030e853424dea2e194f0e14f0bbeeba1dd Mon Sep 17 00:00:00 2001 From: Christian Dupuis Date: Wed, 30 Apr 2014 15:22:09 +0200 Subject: [PATCH] Add more runtime metrics like information about heap, class loading and threads to the metrics infrastructure --- .../endpoint/VanillaPublicMetrics.java | 61 ++++++++++++++++++- .../endpoint/VanillaPublicMetricsTests.java | 31 +++++++++- .../asciidoc/production-ready-features.adoc | 25 +++++--- 3 files changed, 107 insertions(+), 10 deletions(-) diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/VanillaPublicMetrics.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/VanillaPublicMetrics.java index de647636c04..211526f6d2e 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/VanillaPublicMetrics.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/VanillaPublicMetrics.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2013 the original author or authors. + * 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. @@ -16,6 +16,10 @@ package org.springframework.boot.actuate.endpoint; +import java.lang.management.ClassLoadingMXBean; +import java.lang.management.ManagementFactory; +import java.lang.management.MemoryUsage; +import java.lang.management.ThreadMXBean; import java.util.Collection; import java.util.LinkedHashSet; @@ -28,6 +32,7 @@ import org.springframework.util.Assert; * {@link MetricReader} along with memory information. * * @author Dave Syer + * @author Christian Dupuis */ public class VanillaPublicMetrics implements PublicMetrics { @@ -44,13 +49,65 @@ public class VanillaPublicMetrics implements PublicMetrics { for (Metric metric : this.reader.findAll()) { result.add(metric); } + + addMetrics(result); + addHeapMetrics(result); + addThreadMetrics(result); + addClassLoadingMetrics(result); + + return result; + } + + /** + * Add basic system metrics. + */ + protected void addMetrics(Collection> result) { result.add(new Metric("mem", new Long(Runtime.getRuntime().totalMemory()) / 1024)); result.add(new Metric("mem.free", new Long(Runtime.getRuntime() .freeMemory()) / 1024)); result.add(new Metric("processors", Runtime.getRuntime() .availableProcessors())); - return result; + // Add JVM uptime in ms + result.add(new Metric("uptime", new Long(ManagementFactory + .getRuntimeMXBean().getUptime()))); + } + + /** + * Add JVM heap metrics. + */ + protected void addHeapMetrics(Collection> result) { + MemoryUsage memoryUsage = ManagementFactory.getMemoryMXBean() + .getHeapMemoryUsage(); + result.add(new Metric("heap.committed", memoryUsage.getCommitted() / 1024)); + result.add(new Metric("heap.init", memoryUsage.getInit() / 1024)); + result.add(new Metric("heap.used", memoryUsage.getUsed() / 1024)); + result.add(new Metric("heap", memoryUsage.getMax() / 1024)); + } + + /** + * Add thread metrics. + */ + protected void addThreadMetrics(Collection> result) { + ThreadMXBean threadMxBean = ManagementFactory.getThreadMXBean(); + result.add(new Metric("threads.peak", new Long(threadMxBean + .getPeakThreadCount()))); + result.add(new Metric("threads.deamon", new Long(threadMxBean + .getDaemonThreadCount()))); + result.add(new Metric("threads", new Long(threadMxBean.getThreadCount()))); + } + + /** + * Add class loading metrics. + */ + protected void addClassLoadingMetrics(Collection> result) { + ClassLoadingMXBean classLoadingMxBean = ManagementFactory.getClassLoadingMXBean(); + result.add(new Metric("classes", new Long(classLoadingMxBean + .getLoadedClassCount()))); + result.add(new Metric("classes.loaded", new Long(classLoadingMxBean + .getTotalLoadedClassCount()))); + result.add(new Metric("classes.unloaded", new Long(classLoadingMxBean + .getUnloadedClassCount()))); } } diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/VanillaPublicMetricsTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/VanillaPublicMetricsTests.java index d573fa31af2..e84aa0b33a9 100644 --- a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/VanillaPublicMetricsTests.java +++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/VanillaPublicMetricsTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2013 the original author or authors. + * 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. @@ -32,6 +32,7 @@ import static org.junit.Assert.assertTrue; * Tests for {@link VanillaPublicMetrics}. * * @author Phillip Webb + * @author Christian Dupuis */ public class VanillaPublicMetricsTests { @@ -48,4 +49,32 @@ public class VanillaPublicMetricsTests { assertTrue(results.containsKey("mem.free")); assertThat(results.get("a").getValue().doubleValue(), equalTo(0.5)); } + + @Test + public void testSystemMetrics() throws Exception { + InMemoryMetricRepository repository = new InMemoryMetricRepository(); + repository.set(new Metric("a", 0.5, new Date())); + VanillaPublicMetrics publicMetrics = new VanillaPublicMetrics(repository); + Map> results = new HashMap>(); + 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.deamon")); + assertTrue(results.containsKey("threads")); + + assertTrue(results.containsKey("classes.loaded")); + assertTrue(results.containsKey("classes.unloaded")); + assertTrue(results.containsKey("classes")); + } } diff --git a/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc b/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc index 63cf55a1c68..36ac4a077d4 100644 --- a/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc +++ b/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc @@ -578,16 +578,27 @@ decrement). Metrics for all HTTP requests are automatically recorded, so if you "counter.status.401.root": 4, "gauge.response.root": 2, "gauge.response.metrics": 3, - "mem": 466944, - "mem.free": 410117, - "processors": 8 + "classes": 5808, + "classes.loaded": 5808, + "classes.unloaded": 0, + "heap": 3728384, + "heap.committed": 986624, + "heap.init": 262144, + "heap.used": 52765, + "mem": 986624, + "mem.free": 933858, + "processors": 8, + "threads": 15, + "threads.deamon": 11, + "threads.peak": 15, + "uptime": 494836 } ---- -Here we can see basic `memory` and `processor` information along with some HTTP metrics. -In this instance the `root` (``/'') and `/metrics` URLs have returned `HTTP 200` responses -`20` and `3` times respectively. It also appears that the `root` URL returned `HTTP 401` -(unauthorized) `4` times. +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` +URLs have returned `HTTP 200` responses `20` 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 `2ms` to respond and the last to `/metrics` took `3ms`.