Skip to content

Commit

Permalink
Additional JVM metrics (#954)
Browse files Browse the repository at this point in the history
- ClassLoading - Classloading is the most significant contributor
  to startup time and we've seen apps affected by runtime class
  generation issues more than once
- Thread - Characterize JVMs by thread count, detect issues with
  excessive thread allocations
- Compilation - We're currently evaluating alternative JVM runtimes
  and starting to understand C2 compilation times will be useful

Co-authored-by: Brian Harrington <brharrington@gmail.com>
  • Loading branch information
DanielThomas and brharrington authored Apr 12, 2022
1 parent ad07414 commit acc4fdc
Showing 1 changed file with 46 additions and 2 deletions.
48 changes: 46 additions & 2 deletions spectator-ext-jvm/src/main/java/com/netflix/spectator/jvm/Jmx.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,17 @@
*/
package com.netflix.spectator.jvm;

import com.netflix.spectator.api.Gauge;
import com.netflix.spectator.api.Registry;
import com.netflix.spectator.api.patterns.PolledMeter;
import com.typesafe.config.Config;

import java.lang.management.BufferPoolMXBean;
import java.lang.management.ClassLoadingMXBean;
import java.lang.management.CompilationMXBean;
import java.lang.management.ManagementFactory;
import java.lang.management.MemoryPoolMXBean;
import java.lang.management.ThreadMXBean;

/**
* Helpers for working with JMX mbeans.
Expand All @@ -36,15 +41,54 @@ private Jmx() {
* mbeans from the local jvm.
*/
public static void registerStandardMXBeans(Registry registry) {
for (MemoryPoolMXBean mbean : ManagementFactory.getPlatformMXBeans(MemoryPoolMXBean.class)) {
monitorClassLoadingMXBean(registry);
monitorThreadMXBean(registry);
monitorCompilationMXBean(registry);

for (MemoryPoolMXBean mbean : ManagementFactory.getMemoryPoolMXBeans()) {
registry.register(new MemoryPoolMeter(registry, mbean));
}

for (BufferPoolMXBean mbean : ManagementFactory.getPlatformMXBeans(BufferPoolMXBean.class)) {
registry.register(new BufferPoolMeter(registry, mbean));
}
}

private static void monitorClassLoadingMXBean(Registry registry) {
ClassLoadingMXBean classLoadingMXBean = ManagementFactory.getClassLoadingMXBean();
PolledMeter.using(registry)
.withName("jvm.classloading.classesLoaded")
.monitorMonotonicCounter(classLoadingMXBean, ClassLoadingMXBean::getTotalLoadedClassCount);
PolledMeter.using(registry)
.withName("jvm.classloading.classesUnloaded")
.monitorMonotonicCounter(classLoadingMXBean, ClassLoadingMXBean::getUnloadedClassCount);
}

private static void monitorThreadMXBean(Registry registry) {
ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
PolledMeter.using(registry)
.withName("jvm.thread.threadsStarted")
.monitorMonotonicCounter(threadMXBean, ThreadMXBean::getTotalStartedThreadCount);

Gauge nonDaemonThreadCount = registry.gauge("jvm.thread.threadCount", "id", "non-daemon");
Gauge daemonThreadCount = registry.gauge("jvm.thread.threadCount", "id", "daemon");
PolledMeter.poll(registry, () -> {
int threads = threadMXBean.getThreadCount();
int daemonThreads = threadMXBean.getDaemonThreadCount();
nonDaemonThreadCount.set(Math.max(0, threads - daemonThreads));
daemonThreadCount.set(daemonThreads);
});
}

private static void monitorCompilationMXBean(Registry registry) {
CompilationMXBean compilationMXBean = ManagementFactory.getCompilationMXBean();
if (compilationMXBean.isCompilationTimeMonitoringSupported()) {
PolledMeter.using(registry)
.withName("jvm.compilation.compilationTime")
.withTag("compiler", compilationMXBean.getName())
.monitorMonotonicCounterDouble(compilationMXBean, c -> c.getTotalCompilationTime() / 1000.0);
}
}

/**
* Add meters based on configured JMX queries. See the {@link JmxConfig} class for more
* details.
Expand Down

0 comments on commit acc4fdc

Please sign in to comment.