From 496dfa3b15106c7d2ff08dfbb380fad4e7c91d69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Xavier=20L=C3=A9aut=C3=A9?= Date: Sun, 25 Aug 2019 08:26:58 -0400 Subject: [PATCH] fix JVMMonitor initialization with JDK11 (#8397) JVMMonitor requires access to jdk.internal.perf.Perf to enable GC counters, which requires additional JVM arguments with JDK11. This change adds a fallback in case GC counters cannot be initialized, and logs a warning message explaining how GC counters can be enabled. --- .../druid/java/util/metrics/JvmMonitor.java | 31 +++++++++++++++++-- .../java/util/metrics/JvmMonitorTest.java | 3 ++ 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/org/apache/druid/java/util/metrics/JvmMonitor.java b/core/src/main/java/org/apache/druid/java/util/metrics/JvmMonitor.java index 118ed315eee..2309139e176 100644 --- a/core/src/main/java/org/apache/druid/java/util/metrics/JvmMonitor.java +++ b/core/src/main/java/org/apache/druid/java/util/metrics/JvmMonitor.java @@ -19,9 +19,11 @@ package org.apache.druid.java.util.metrics; +import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableMap; import org.apache.druid.java.util.common.StringUtils; +import org.apache.druid.java.util.common.logger.Logger; import org.apache.druid.java.util.emitter.service.ServiceEmitter; import org.apache.druid.java.util.emitter.service.ServiceMetricEvent; import org.gridkit.lab.jvm.perfdata.JStatData; @@ -29,6 +31,7 @@ import org.gridkit.lab.jvm.perfdata.JStatData.LongCounter; import org.gridkit.lab.jvm.perfdata.JStatData.StringCounter; import org.gridkit.lab.jvm.perfdata.JStatData.TickCounter; +import javax.annotation.Nullable; import java.lang.management.BufferPoolMXBean; import java.lang.management.ManagementFactory; import java.lang.management.MemoryPoolMXBean; @@ -40,11 +43,16 @@ import java.util.Map; public class JvmMonitor extends FeedDefiningMonitor { + private static final Logger log = new Logger(JvmMonitor.class); + private final Map dimensions; private final long pid; - private final GcCounters gcCounters = new GcCounters(); + @VisibleForTesting + @Nullable + final GcCounters gcCounters; + @Nullable private final AllocationMetricCollector collector; public JvmMonitor() @@ -69,6 +77,7 @@ public class JvmMonitor extends FeedDefiningMonitor this.dimensions = ImmutableMap.copyOf(dimensions); this.pid = Preconditions.checkNotNull(pidDiscoverer).getPid(); this.collector = AllocationMetricCollectors.getAllocationMetricCollector(); + this.gcCounters = tryCreateGcCounters(); } @Override @@ -146,7 +155,25 @@ public class JvmMonitor extends FeedDefiningMonitor private void emitGcMetrics(ServiceEmitter emitter) { - gcCounters.emit(emitter, dimensions); + if (gcCounters != null) { + gcCounters.emit(emitter, dimensions); + } + } + + @Nullable + private GcCounters tryCreateGcCounters() + { + try { + return new GcCounters(); + } + catch (RuntimeException e) { + // in JDK11 jdk.internal.perf.Perf is not accessible, unless + // --add-exports java.base/jdk.internal.perf=ALL-UNNAMED is set + log.warn("Cannot initialize GC counters. If running JDK11 and above," + + " add --add-exports java.base/jdk.internal.perf=ALL-UNNAMED" + + " to the JVM arguments to enable GC counters."); + } + return null; } /** diff --git a/core/src/test/java/org/apache/druid/java/util/metrics/JvmMonitorTest.java b/core/src/test/java/org/apache/druid/java/util/metrics/JvmMonitorTest.java index a1dead94edc..1e5cff5016b 100644 --- a/core/src/test/java/org/apache/druid/java/util/metrics/JvmMonitorTest.java +++ b/core/src/test/java/org/apache/druid/java/util/metrics/JvmMonitorTest.java @@ -24,6 +24,7 @@ import org.apache.druid.java.util.emitter.core.Event; import org.apache.druid.java.util.emitter.service.ServiceEmitter; import org.apache.druid.java.util.emitter.service.ServiceMetricEvent; import org.junit.Assert; +import org.junit.Assume; import org.junit.Test; import java.util.List; @@ -39,6 +40,8 @@ public class JvmMonitorTest final ServiceEmitter serviceEmitter = new ServiceEmitter("test", "localhost", emitter); serviceEmitter.start(); final JvmMonitor jvmMonitor = new JvmMonitor(); + // skip tests if gc counters fail to initialize with this JDK + Assume.assumeNotNull(jvmMonitor.gcCounters); while (true) { // generate some garbage to see gc counters incremented