From fe9cb381382ce9c83e278215d67f11dba292eaa6 Mon Sep 17 00:00:00 2001 From: Juan Celhay Date: Thu, 15 Jan 2026 14:14:54 -0500 Subject: [PATCH 1/9] add jvm metrics --- .../registry/module/RegistryComponent.java | 2 + .../whitebox/ApplicationMetricsModule.java | 16 ++++ .../monitoring/whitebox/JvmMetrics.java | 76 +++++++++++++++++++ .../monitoring/whitebox/JvmMetricsTest.java | 61 +++++++++++++++ 4 files changed, 155 insertions(+) create mode 100644 core/src/main/java/google/registry/monitoring/whitebox/ApplicationMetricsModule.java create mode 100644 core/src/main/java/google/registry/monitoring/whitebox/JvmMetrics.java create mode 100644 core/src/test/java/google/registry/monitoring/whitebox/JvmMetricsTest.java diff --git a/core/src/main/java/google/registry/module/RegistryComponent.java b/core/src/main/java/google/registry/module/RegistryComponent.java index 7f7170340a0..9b2a50b51b3 100644 --- a/core/src/main/java/google/registry/module/RegistryComponent.java +++ b/core/src/main/java/google/registry/module/RegistryComponent.java @@ -39,6 +39,7 @@ import google.registry.keyring.api.KeyModule; import google.registry.module.RegistryComponent.RegistryModule; import google.registry.module.RequestComponent.RequestComponentModule; +import google.registry.monitoring.whitebox.ApplicationMetricsModule; import google.registry.monitoring.whitebox.StackdriverModule; import google.registry.mosapi.module.MosApiModule; import google.registry.persistence.PersistenceModule; @@ -58,6 +59,7 @@ @Singleton @Component( modules = { + ApplicationMetricsModule.class, AuthModule.class, BatchModule.class, BigqueryModule.class, diff --git a/core/src/main/java/google/registry/monitoring/whitebox/ApplicationMetricsModule.java b/core/src/main/java/google/registry/monitoring/whitebox/ApplicationMetricsModule.java new file mode 100644 index 00000000000..913d827f312 --- /dev/null +++ b/core/src/main/java/google/registry/monitoring/whitebox/ApplicationMetricsModule.java @@ -0,0 +1,16 @@ +// Example ApplicationMetricsModule.java +package google.registry.monitoring.whitebox; // Or a more suitable package + +import dagger.Module; +import dagger.Provides; +import javax.inject.Singleton; + +@Module +public final class ApplicationMetricsModule { + + @Provides + @Singleton + static JvmMetrics provideJvmMetrics() { + return new JvmMetrics(registry); + } +} \ No newline at end of file diff --git a/core/src/main/java/google/registry/monitoring/whitebox/JvmMetrics.java b/core/src/main/java/google/registry/monitoring/whitebox/JvmMetrics.java new file mode 100644 index 00000000000..3ab5d78349b --- /dev/null +++ b/core/src/main/java/google/registry/monitoring/whitebox/JvmMetrics.java @@ -0,0 +1,76 @@ +package google.registry.monitoring.whitebox; + +import java.lang.management.ManagementFactory; +import java.lang.management.MemoryMXBean; +import java.lang.management.MemoryUsage; + + +/** Exposes JVM metrics. */ +@Singleton +class JvmMetrics { + + private static final LabelDescriptor TYPE_LABEL = LabelDescriptor.create("type", "Memory type (e.g., heap, non_heap)"); + + // Memory Metrics + private final GaugeMetric memoryUsed; + private final GaugeMetric memoryCommitted; + private final GaugeMetric memoryMax; + + private final MemoryMXBean memoryMxBean; + long heapUsed = heapUsage.getUsed(); + long heapMax = heapUsage.getMax(); + long nonHeapUsed = nonHeapUsage.getUsed(); + + + @Inject + JvmMetrics() { + this(ManagementFactory.getMemoryMXBean()); + } + + // Constructor for testing + JvmMetrics(MemoryMXBean memoryMxBean) { + this.memoryMxBean = memoryMxBean; + MetricRegistry registry = MetricRegistryImpl.getDefault(); + + memoryUsed = + registry.newGaugeMetric( + "/jvm/memory/used", + "Current memory usage in bytes", + "bytes", + null, + TYPE_LABEL); + + memoryCommitted = + registry.newGaugeMetric( + "/jvm/memory/committed", + "Committed memory in bytes", + "bytes", + null, + TYPE_LABEL); + + memoryMax = + registry.newGaugeMetric( + "/jvm/memory/max", + "Maximum memory in bytes", + "bytes", + null, + TYPE_LABEL); + + registry.registerCallback(this::updateMemoryMetrics); + } + + private void updateMemoryMetrics() { + // Heap Memory + MemoryUsage heapUsage = memoryMxBean.getHeapMemoryUsage(); + memoryUsed.set(heapUsage.getUsed(), "heap"); + memoryCommitted.set(heapUsage.getCommitted(), "heap"); + memoryMax.set(heapUsage.getMax(), "heap"); + + // Non-Heap Memory + MemoryUsage nonHeapUsage = memoryMxBean.getNonHeapMemoryUsage(); + memoryUsed.set(nonHeapUsage.getUsed(), "non_heap"); + memoryCommitted.set(nonHeapUsage.getCommitted(), "non_heap"); + memoryMax.set(nonHeapUsage.getMax(), "non_heap"); + } + +} \ No newline at end of file diff --git a/core/src/test/java/google/registry/monitoring/whitebox/JvmMetricsTest.java b/core/src/test/java/google/registry/monitoring/whitebox/JvmMetricsTest.java new file mode 100644 index 00000000000..4d42e9e57eb --- /dev/null +++ b/core/src/test/java/google/registry/monitoring/whitebox/JvmMetricsTest.java @@ -0,0 +1,61 @@ +package google.registry.monitoring.whitebox; + +import static com.google.common.truth.Truth.assertThat; + +import google.registry.monitoring.whitebox.CheckApiMetric.Status; +import google.registry.testing.FakeClock; +import org.joda.time.DateTime; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +/** Unit tests for {@link JvmMetrics}. */ +class JvmMetricsTests { + @Rule public final MockitoRule mocks = MockitoJUnit.rule(); + + private MetricRegistry registry; + private JvmMetrics jvmMetrics; + + @Mock private MemoryMXBean mockMemoryMXBean; + + @Before + public void setUp() { + MetricRegistryImpl.getDefault().clear(); + registry = MetricRegistryImpl.getDefault(); + + jvmMetrics = new JvmMetrics(mockMemoryMXBean); + } + + @Test + public void metricsRegistered() { + assertThat(registry.getMetric("/jvm/memory/used")).isNotNull(); + assertThat(registry.getMetric("/jvm/memory/committed")).isNotNull(); + assertThat(registry.getMetric("/jvm/memory/max")).isNotNull(); + + assertThat(registry.getMetric("/jvm/memory/used")).isInstanceOf(GaugeMetric.class); + } + + + @Test + public void updateMemoryMetrics_withMockedBean() { + MemoryUsage heapUsage = new MemoryUsage(100, 200, 500, 1000); + MemoryUsage nonHeapUsage = new MemoryUsage(50, 100, 250, 500); + when(mockMemoryMXBean.getHeapMemoryUsage()).thenReturn(heapUsage); + when(mockMemoryMXBean.getNonHeapMemoryUsage()).thenReturn(nonHeapUsage); + + JvmMetrics testMetrics = new JvmMetrics(mockMemoryMXBean); + testMetrics.updateMemoryMetrics(); + + GaugeMetric used = (GaugeMetric) registry.getMetric("/jvm/memory/used"); + GaugeMetric committed = (GaugeMetric) registry.getMetric("/jvm/memory/committed"); + GaugeMetric max = (GaugeMetric) registry.getMetric("/jvm/memory/max"); + + assertThat(used.get("heap")).isEqualTo(100); + assertThat(committed.get("heap")).isEqualTo(500); + assertThat(max.get("heap")).isEqualTo(1000); + + assertThat(used.get("non_heap")).isEqualTo(50); + assertThat(committed.get("non_heap")).isEqualTo(250); + assertThat(max.get("non_heap")).isEqualTo(500); + } + +} \ No newline at end of file From 51b3b9936732495c086bf4f3f9c8be3fb3299e0b Mon Sep 17 00:00:00 2001 From: Juan Celhay Date: Thu, 15 Jan 2026 14:15:39 -0500 Subject: [PATCH 2/9] include all changes --- .../whitebox/ApplicationMetricsModule.java | 21 +++- .../monitoring/whitebox/JvmMetrics.java | 113 +++++++++++------- .../monitoring/whitebox/JvmMetricsTest.java | 80 +++++++------ 3 files changed, 130 insertions(+), 84 deletions(-) diff --git a/core/src/main/java/google/registry/monitoring/whitebox/ApplicationMetricsModule.java b/core/src/main/java/google/registry/monitoring/whitebox/ApplicationMetricsModule.java index 913d827f312..d0d051ff1c7 100644 --- a/core/src/main/java/google/registry/monitoring/whitebox/ApplicationMetricsModule.java +++ b/core/src/main/java/google/registry/monitoring/whitebox/ApplicationMetricsModule.java @@ -1,9 +1,22 @@ -// Example ApplicationMetricsModule.java +// Copyright 2017 The Nomulus Authors. All Rights Reserved. +// +// 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 google.registry.monitoring.whitebox; // Or a more suitable package import dagger.Module; import dagger.Provides; -import javax.inject.Singleton; +import jakarta.inject.Singleton; @Module public final class ApplicationMetricsModule { @@ -11,6 +24,6 @@ public final class ApplicationMetricsModule { @Provides @Singleton static JvmMetrics provideJvmMetrics() { - return new JvmMetrics(registry); + return new JvmMetrics(); } -} \ No newline at end of file +} diff --git a/core/src/main/java/google/registry/monitoring/whitebox/JvmMetrics.java b/core/src/main/java/google/registry/monitoring/whitebox/JvmMetrics.java index 3ab5d78349b..f0443194a0c 100644 --- a/core/src/main/java/google/registry/monitoring/whitebox/JvmMetrics.java +++ b/core/src/main/java/google/registry/monitoring/whitebox/JvmMetrics.java @@ -1,27 +1,41 @@ +// Copyright 2017 The Nomulus Authors. All Rights Reserved. +// +// 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 google.registry.monitoring.whitebox; import java.lang.management.ManagementFactory; import java.lang.management.MemoryMXBean; import java.lang.management.MemoryUsage; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; +import com.google.monitoring.metrics.MetricRegistry; +import com.google.monitoring.metrics.MetricRegistryImpl; +import com.google.monitoring.metrics.LabelDescriptor; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; +import com.google.common.base.Supplier; + /** Exposes JVM metrics. */ @Singleton class JvmMetrics { - private static final LabelDescriptor TYPE_LABEL = LabelDescriptor.create("type", "Memory type (e.g., heap, non_heap)"); - - // Memory Metrics - private final GaugeMetric memoryUsed; - private final GaugeMetric memoryCommitted; - private final GaugeMetric memoryMax; - + private static final ImmutableSet TYPE_LABEL_SET = + ImmutableSet.of(LabelDescriptor.create("type", "Memory type (e.g., heap, non_heap)")); private final MemoryMXBean memoryMxBean; - long heapUsed = heapUsage.getUsed(); - long heapMax = heapUsage.getMax(); - long nonHeapUsed = nonHeapUsage.getUsed(); - - @Inject JvmMetrics() { this(ManagementFactory.getMemoryMXBean()); @@ -32,45 +46,54 @@ class JvmMetrics { this.memoryMxBean = memoryMxBean; MetricRegistry registry = MetricRegistryImpl.getDefault(); - memoryUsed = - registry.newGaugeMetric( - "/jvm/memory/used", - "Current memory usage in bytes", - "bytes", - null, - TYPE_LABEL); - - memoryCommitted = - registry.newGaugeMetric( - "/jvm/memory/committed", - "Committed memory in bytes", - "bytes", - null, - TYPE_LABEL); + registry.newGauge( + "/jvm/memory/used", + "Current memory usage in bytes", + "bytes", + TYPE_LABEL_SET, + (Supplier, Long>>) this::getUsedMemory, + Long.class); + + registry.newGauge( + "/jvm/memory/committed", + "Committed memory in bytes", + "bytes", + TYPE_LABEL_SET, + (Supplier, Long>>) this::getCommittedMemory, + Long.class); + + registry.newGauge( + "/jvm/memory/max", + "Maximum memory in bytes", + "bytes", + TYPE_LABEL_SET, + (Supplier, Long>>) this::getMaxMemory, + Long.class); + } - memoryMax = - registry.newGaugeMetric( - "/jvm/memory/max", - "Maximum memory in bytes", - "bytes", - null, - TYPE_LABEL); - registry.registerCallback(this::updateMemoryMetrics); + ImmutableMap, Long> getUsedMemory() { + MemoryUsage heapUsage = memoryMxBean.getHeapMemoryUsage(); + MemoryUsage nonHeapUsage = memoryMxBean.getNonHeapMemoryUsage(); + return ImmutableMap.of( + ImmutableList.of("heap"), heapUsage.getUsed(), + ImmutableList.of("non_heap"), nonHeapUsage.getUsed()); } - private void updateMemoryMetrics() { - // Heap Memory + ImmutableMap, Long> getCommittedMemory() { MemoryUsage heapUsage = memoryMxBean.getHeapMemoryUsage(); - memoryUsed.set(heapUsage.getUsed(), "heap"); - memoryCommitted.set(heapUsage.getCommitted(), "heap"); - memoryMax.set(heapUsage.getMax(), "heap"); + MemoryUsage nonHeapUsage = memoryMxBean.getNonHeapMemoryUsage(); + return ImmutableMap.of( + ImmutableList.of("heap"), heapUsage.getCommitted(), + ImmutableList.of("non_heap"), nonHeapUsage.getCommitted()); + } - // Non-Heap Memory + ImmutableMap, Long> getMaxMemory() { + MemoryUsage heapUsage = memoryMxBean.getHeapMemoryUsage(); MemoryUsage nonHeapUsage = memoryMxBean.getNonHeapMemoryUsage(); - memoryUsed.set(nonHeapUsage.getUsed(), "non_heap"); - memoryCommitted.set(nonHeapUsage.getCommitted(), "non_heap"); - memoryMax.set(nonHeapUsage.getMax(), "non_heap"); + return ImmutableMap.of( + ImmutableList.of("heap"), heapUsage.getMax(), + ImmutableList.of("non_heap"), nonHeapUsage.getMax()); } -} \ No newline at end of file +} diff --git a/core/src/test/java/google/registry/monitoring/whitebox/JvmMetricsTest.java b/core/src/test/java/google/registry/monitoring/whitebox/JvmMetricsTest.java index 4d42e9e57eb..b719780754b 100644 --- a/core/src/test/java/google/registry/monitoring/whitebox/JvmMetricsTest.java +++ b/core/src/test/java/google/registry/monitoring/whitebox/JvmMetricsTest.java @@ -1,61 +1,71 @@ +// Copyright 2017 The Nomulus Authors. All Rights Reserved. +// +// 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 google.registry.monitoring.whitebox; import static com.google.common.truth.Truth.assertThat; - -import google.registry.monitoring.whitebox.CheckApiMetric.Status; -import google.registry.testing.FakeClock; -import org.joda.time.DateTime; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.google.monitoring.metrics.MetricRegistry; +import com.google.monitoring.metrics.MetricRegistryImpl; +import java.lang.management.MemoryMXBean; +import java.lang.management.MemoryUsage; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; /** Unit tests for {@link JvmMetrics}. */ class JvmMetricsTests { - @Rule public final MockitoRule mocks = MockitoJUnit.rule(); private MetricRegistry registry; private JvmMetrics jvmMetrics; - @Mock private MemoryMXBean mockMemoryMXBean; + private MemoryMXBean mockMemoryMXBean = mock(MemoryMXBean.class); - @Before + private static final MemoryUsage HEAP_USAGE = new MemoryUsage(100, 200, 500, 1000); + private static final MemoryUsage NON_HEAP_USAGE = new MemoryUsage(50, 100, 250, 500); + + @BeforeEach public void setUp() { - MetricRegistryImpl.getDefault().clear(); registry = MetricRegistryImpl.getDefault(); + when(mockMemoryMXBean.getHeapMemoryUsage()).thenReturn(HEAP_USAGE); + when(mockMemoryMXBean.getNonHeapMemoryUsage()).thenReturn(NON_HEAP_USAGE); + + jvmMetrics = new JvmMetrics(mockMemoryMXBean); } @Test public void metricsRegistered() { - assertThat(registry.getMetric("/jvm/memory/used")).isNotNull(); - assertThat(registry.getMetric("/jvm/memory/committed")).isNotNull(); - assertThat(registry.getMetric("/jvm/memory/max")).isNotNull(); - - assertThat(registry.getMetric("/jvm/memory/used")).isInstanceOf(GaugeMetric.class); + // We expect 3 metrics to be registered by JvmMetrics + assertThat(registry.getRegisteredMetrics()).hasSize(3); + // We can't easily verify their names, but we know they are VirtualMetrics + for (var metric : registry.getRegisteredMetrics()) { + assertThat(metric).isInstanceOf(com.google.monitoring.metrics.VirtualMetric.class); + } } + @Test - public void updateMemoryMetrics_withMockedBean() { - MemoryUsage heapUsage = new MemoryUsage(100, 200, 500, 1000); - MemoryUsage nonHeapUsage = new MemoryUsage(50, 100, 250, 500); - when(mockMemoryMXBean.getHeapMemoryUsage()).thenReturn(heapUsage); - when(mockMemoryMXBean.getNonHeapMemoryUsage()).thenReturn(nonHeapUsage); - - JvmMetrics testMetrics = new JvmMetrics(mockMemoryMXBean); - testMetrics.updateMemoryMetrics(); - - GaugeMetric used = (GaugeMetric) registry.getMetric("/jvm/memory/used"); - GaugeMetric committed = (GaugeMetric) registry.getMetric("/jvm/memory/committed"); - GaugeMetric max = (GaugeMetric) registry.getMetric("/jvm/memory/max"); - - assertThat(used.get("heap")).isEqualTo(100); - assertThat(committed.get("heap")).isEqualTo(500); - assertThat(max.get("heap")).isEqualTo(1000); - - assertThat(used.get("non_heap")).isEqualTo(50); - assertThat(committed.get("non_heap")).isEqualTo(250); - assertThat(max.get("non_heap")).isEqualTo(500); + public void testGetUsedMemory() { + ImmutableMap, Long> values = jvmMetrics.getUsedMemory(); + assertThat(values).containsExactly( + ImmutableList.of("heap"), 100L, + ImmutableList.of("non_heap"), 50L); } - -} \ No newline at end of file +} From 398a908e4873fb50d201f09d6d069eb2e6ce93e2 Mon Sep 17 00:00:00 2001 From: Juan Celhay Date: Thu, 15 Jan 2026 15:44:12 -0500 Subject: [PATCH 3/9] Fix tests and lint errors --- .../whitebox/ApplicationMetricsModule.java | 3 +- .../monitoring/whitebox/JvmMetrics.java | 20 +++++------ .../monitoring/whitebox/JvmMetricsTest.java | 34 +++++++++++++------ 3 files changed, 35 insertions(+), 22 deletions(-) diff --git a/core/src/main/java/google/registry/monitoring/whitebox/ApplicationMetricsModule.java b/core/src/main/java/google/registry/monitoring/whitebox/ApplicationMetricsModule.java index d0d051ff1c7..5418313b491 100644 --- a/core/src/main/java/google/registry/monitoring/whitebox/ApplicationMetricsModule.java +++ b/core/src/main/java/google/registry/monitoring/whitebox/ApplicationMetricsModule.java @@ -12,12 +12,13 @@ // See the License for the specific language governing permissions and // limitations under the License. -package google.registry.monitoring.whitebox; // Or a more suitable package +package google.registry.monitoring.whitebox; import dagger.Module; import dagger.Provides; import jakarta.inject.Singleton; +/** Provide application-level metrics in this module. */ @Module public final class ApplicationMetricsModule { diff --git a/core/src/main/java/google/registry/monitoring/whitebox/JvmMetrics.java b/core/src/main/java/google/registry/monitoring/whitebox/JvmMetrics.java index f0443194a0c..93f4b504459 100644 --- a/core/src/main/java/google/registry/monitoring/whitebox/JvmMetrics.java +++ b/core/src/main/java/google/registry/monitoring/whitebox/JvmMetrics.java @@ -14,20 +14,18 @@ package google.registry.monitoring.whitebox; -import java.lang.management.ManagementFactory; -import java.lang.management.MemoryMXBean; -import java.lang.management.MemoryUsage; -import jakarta.inject.Inject; -import jakarta.inject.Singleton; -import com.google.monitoring.metrics.MetricRegistry; -import com.google.monitoring.metrics.MetricRegistryImpl; -import com.google.monitoring.metrics.LabelDescriptor; +import com.google.common.base.Supplier; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; -import com.google.common.base.Supplier; - - +import com.google.monitoring.metrics.LabelDescriptor; +import com.google.monitoring.metrics.MetricRegistry; +import com.google.monitoring.metrics.MetricRegistryImpl; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; +import java.lang.management.ManagementFactory; +import java.lang.management.MemoryMXBean; +import java.lang.management.MemoryUsage; /** Exposes JVM metrics. */ @Singleton diff --git a/core/src/test/java/google/registry/monitoring/whitebox/JvmMetricsTest.java b/core/src/test/java/google/registry/monitoring/whitebox/JvmMetricsTest.java index b719780754b..b5b8bfc41d6 100644 --- a/core/src/test/java/google/registry/monitoring/whitebox/JvmMetricsTest.java +++ b/core/src/test/java/google/registry/monitoring/whitebox/JvmMetricsTest.java @@ -32,40 +32,54 @@ class JvmMetricsTests { private MetricRegistry registry; private JvmMetrics jvmMetrics; - private MemoryMXBean mockMemoryMXBean = mock(MemoryMXBean.class); - private static final MemoryUsage HEAP_USAGE = new MemoryUsage(100, 200, 500, 1000); - private static final MemoryUsage NON_HEAP_USAGE = new MemoryUsage(50, 100, 250, 500); + private static final MemoryUsage HEAP_USAGE = new MemoryUsage(/*init*/ 100, + /*used*/ 200, /*commited*/ 500, /*max*/ 1000); + private static final MemoryUsage NON_HEAP_USAGE = new MemoryUsage(/*init*/ 50, + /*used*/ 100, /*commited*/ 250, /*max*/ 500); @BeforeEach public void setUp() { + MetricRegistryImpl.getDefault().unregisterAllMetrics(); registry = MetricRegistryImpl.getDefault(); when(mockMemoryMXBean.getHeapMemoryUsage()).thenReturn(HEAP_USAGE); when(mockMemoryMXBean.getNonHeapMemoryUsage()).thenReturn(NON_HEAP_USAGE); - jvmMetrics = new JvmMetrics(mockMemoryMXBean); } @Test public void metricsRegistered() { - // We expect 3 metrics to be registered by JvmMetrics assertThat(registry.getRegisteredMetrics()).hasSize(3); - // We can't easily verify their names, but we know they are VirtualMetrics + for (var metric : registry.getRegisteredMetrics()) { assertThat(metric).isInstanceOf(com.google.monitoring.metrics.VirtualMetric.class); } } - - @Test public void testGetUsedMemory() { ImmutableMap, Long> values = jvmMetrics.getUsedMemory(); assertThat(values).containsExactly( - ImmutableList.of("heap"), 100L, - ImmutableList.of("non_heap"), 50L); + ImmutableList.of("heap"), 200L, + ImmutableList.of("non_heap"), 100L); + } + + @Test + public void testGetCommittedMemory() { + ImmutableMap, Long> values = jvmMetrics.getCommittedMemory(); + assertThat(values).containsExactly( + ImmutableList.of("heap"), 500L, + ImmutableList.of("non_heap"), 250L); + } + + @Test + public void testGetMaxMemory() { + ImmutableMap, Long> values = jvmMetrics.getMaxMemory(); + assertThat(values).containsExactly( + ImmutableList.of("heap"), 1000L, + ImmutableList.of("non_heap"), 500L); } } From d96edb57c449d83cbcca4f2b883dcca7f096f647 Mon Sep 17 00:00:00 2001 From: Juan Celhay Date: Thu, 15 Jan 2026 15:49:28 -0500 Subject: [PATCH 4/9] Fix formatting --- .../java/google/registry/monitoring/whitebox/JvmMetrics.java | 5 ++++- .../google/registry/monitoring/whitebox/JvmMetricsTest.java | 3 +++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/google/registry/monitoring/whitebox/JvmMetrics.java b/core/src/main/java/google/registry/monitoring/whitebox/JvmMetrics.java index 93f4b504459..d89af22f9f6 100644 --- a/core/src/main/java/google/registry/monitoring/whitebox/JvmMetrics.java +++ b/core/src/main/java/google/registry/monitoring/whitebox/JvmMetrics.java @@ -34,6 +34,7 @@ class JvmMetrics { private static final ImmutableSet TYPE_LABEL_SET = ImmutableSet.of(LabelDescriptor.create("type", "Memory type (e.g., heap, non_heap)")); private final MemoryMXBean memoryMxBean; + @Inject JvmMetrics() { this(ManagementFactory.getMemoryMXBean()); @@ -73,6 +74,7 @@ class JvmMetrics { ImmutableMap, Long> getUsedMemory() { MemoryUsage heapUsage = memoryMxBean.getHeapMemoryUsage(); MemoryUsage nonHeapUsage = memoryMxBean.getNonHeapMemoryUsage(); + return ImmutableMap.of( ImmutableList.of("heap"), heapUsage.getUsed(), ImmutableList.of("non_heap"), nonHeapUsage.getUsed()); @@ -81,6 +83,7 @@ ImmutableMap, Long> getUsedMemory() { ImmutableMap, Long> getCommittedMemory() { MemoryUsage heapUsage = memoryMxBean.getHeapMemoryUsage(); MemoryUsage nonHeapUsage = memoryMxBean.getNonHeapMemoryUsage(); + return ImmutableMap.of( ImmutableList.of("heap"), heapUsage.getCommitted(), ImmutableList.of("non_heap"), nonHeapUsage.getCommitted()); @@ -89,9 +92,9 @@ ImmutableMap, Long> getCommittedMemory() { ImmutableMap, Long> getMaxMemory() { MemoryUsage heapUsage = memoryMxBean.getHeapMemoryUsage(); MemoryUsage nonHeapUsage = memoryMxBean.getNonHeapMemoryUsage(); + return ImmutableMap.of( ImmutableList.of("heap"), heapUsage.getMax(), ImmutableList.of("non_heap"), nonHeapUsage.getMax()); } - } diff --git a/core/src/test/java/google/registry/monitoring/whitebox/JvmMetricsTest.java b/core/src/test/java/google/registry/monitoring/whitebox/JvmMetricsTest.java index b5b8bfc41d6..ae76d33bd3b 100644 --- a/core/src/test/java/google/registry/monitoring/whitebox/JvmMetricsTest.java +++ b/core/src/test/java/google/registry/monitoring/whitebox/JvmMetricsTest.java @@ -62,6 +62,7 @@ public void metricsRegistered() { @Test public void testGetUsedMemory() { ImmutableMap, Long> values = jvmMetrics.getUsedMemory(); + assertThat(values).containsExactly( ImmutableList.of("heap"), 200L, ImmutableList.of("non_heap"), 100L); @@ -70,6 +71,7 @@ public void testGetUsedMemory() { @Test public void testGetCommittedMemory() { ImmutableMap, Long> values = jvmMetrics.getCommittedMemory(); + assertThat(values).containsExactly( ImmutableList.of("heap"), 500L, ImmutableList.of("non_heap"), 250L); @@ -78,6 +80,7 @@ public void testGetCommittedMemory() { @Test public void testGetMaxMemory() { ImmutableMap, Long> values = jvmMetrics.getMaxMemory(); + assertThat(values).containsExactly( ImmutableList.of("heap"), 1000L, ImmutableList.of("non_heap"), 500L); From 9703c4ec7734b508fbc9991d46eaa73432417c05 Mon Sep 17 00:00:00 2001 From: Juan Celhay Date: Thu, 15 Jan 2026 17:30:28 -0500 Subject: [PATCH 5/9] Instantiate jvmmetrics class in stackdriver module --- .../registry/module/RegistryComponent.java | 2 -- .../whitebox/ApplicationMetricsModule.java | 30 ------------------- .../whitebox/StackdriverModule.java | 11 +++++-- .../monitoring/whitebox/JvmMetricsTest.java | 2 +- 4 files changed, 10 insertions(+), 35 deletions(-) delete mode 100644 core/src/main/java/google/registry/monitoring/whitebox/ApplicationMetricsModule.java diff --git a/core/src/main/java/google/registry/module/RegistryComponent.java b/core/src/main/java/google/registry/module/RegistryComponent.java index 9b2a50b51b3..7f7170340a0 100644 --- a/core/src/main/java/google/registry/module/RegistryComponent.java +++ b/core/src/main/java/google/registry/module/RegistryComponent.java @@ -39,7 +39,6 @@ import google.registry.keyring.api.KeyModule; import google.registry.module.RegistryComponent.RegistryModule; import google.registry.module.RequestComponent.RequestComponentModule; -import google.registry.monitoring.whitebox.ApplicationMetricsModule; import google.registry.monitoring.whitebox.StackdriverModule; import google.registry.mosapi.module.MosApiModule; import google.registry.persistence.PersistenceModule; @@ -59,7 +58,6 @@ @Singleton @Component( modules = { - ApplicationMetricsModule.class, AuthModule.class, BatchModule.class, BigqueryModule.class, diff --git a/core/src/main/java/google/registry/monitoring/whitebox/ApplicationMetricsModule.java b/core/src/main/java/google/registry/monitoring/whitebox/ApplicationMetricsModule.java deleted file mode 100644 index 5418313b491..00000000000 --- a/core/src/main/java/google/registry/monitoring/whitebox/ApplicationMetricsModule.java +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright 2017 The Nomulus Authors. All Rights Reserved. -// -// 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 google.registry.monitoring.whitebox; - -import dagger.Module; -import dagger.Provides; -import jakarta.inject.Singleton; - -/** Provide application-level metrics in this module. */ -@Module -public final class ApplicationMetricsModule { - - @Provides - @Singleton - static JvmMetrics provideJvmMetrics() { - return new JvmMetrics(); - } -} diff --git a/core/src/main/java/google/registry/monitoring/whitebox/StackdriverModule.java b/core/src/main/java/google/registry/monitoring/whitebox/StackdriverModule.java index aa89ec1d560..046a0507132 100644 --- a/core/src/main/java/google/registry/monitoring/whitebox/StackdriverModule.java +++ b/core/src/main/java/google/registry/monitoring/whitebox/StackdriverModule.java @@ -32,7 +32,7 @@ import jakarta.inject.Singleton; import org.joda.time.Duration; -/** Dagger module for Google Stackdriver service connection objects. */ +/** Dagger module for monitoring and Google Stackdriver service connection objects. */ @Module public final class StackdriverModule { @@ -77,10 +77,17 @@ static MetricWriter provideMetricWriter( @Provides static MetricReporter provideMetricReporter( - MetricWriter metricWriter, @Config("metricsWriteInterval") Duration writeInterval) { + MetricWriter metricWriter, @Config("metricsWriteInterval") Duration writeInterval, + JvmMetrics unusedJvmMetrics) { return new MetricReporter( metricWriter, writeInterval.getStandardSeconds(), new ThreadFactoryBuilder().setDaemon(true).build()); } + + @Singleton + @Provides + static JvmMetrics provideJvmMetrics() { + return new JvmMetrics(); + } } diff --git a/core/src/test/java/google/registry/monitoring/whitebox/JvmMetricsTest.java b/core/src/test/java/google/registry/monitoring/whitebox/JvmMetricsTest.java index ae76d33bd3b..3856729ffc2 100644 --- a/core/src/test/java/google/registry/monitoring/whitebox/JvmMetricsTest.java +++ b/core/src/test/java/google/registry/monitoring/whitebox/JvmMetricsTest.java @@ -80,7 +80,7 @@ public void testGetCommittedMemory() { @Test public void testGetMaxMemory() { ImmutableMap, Long> values = jvmMetrics.getMaxMemory(); - + assertThat(values).containsExactly( ImmutableList.of("heap"), 1000L, ImmutableList.of("non_heap"), 500L); From 9b4f740a47144f0eb33045867c912e81abcfd66a Mon Sep 17 00:00:00 2001 From: Juan Celhay Date: Tue, 20 Jan 2026 11:43:33 -0500 Subject: [PATCH 6/9] add metrics registration behaviour and explicit call --- .../registry/monitoring/whitebox/JvmMetrics.java | 3 +++ .../monitoring/whitebox/StackdriverModule.java | 10 +++------- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/core/src/main/java/google/registry/monitoring/whitebox/JvmMetrics.java b/core/src/main/java/google/registry/monitoring/whitebox/JvmMetrics.java index d89af22f9f6..de4b7bc6562 100644 --- a/core/src/main/java/google/registry/monitoring/whitebox/JvmMetrics.java +++ b/core/src/main/java/google/registry/monitoring/whitebox/JvmMetrics.java @@ -43,6 +43,9 @@ class JvmMetrics { // Constructor for testing JvmMetrics(MemoryMXBean memoryMxBean) { this.memoryMxBean = memoryMxBean; + } + /** Registers JVM gauges with the default registry. */ + void register() { MetricRegistry registry = MetricRegistryImpl.getDefault(); registry.newGauge( diff --git a/core/src/main/java/google/registry/monitoring/whitebox/StackdriverModule.java b/core/src/main/java/google/registry/monitoring/whitebox/StackdriverModule.java index 046a0507132..389ddb3e52f 100644 --- a/core/src/main/java/google/registry/monitoring/whitebox/StackdriverModule.java +++ b/core/src/main/java/google/registry/monitoring/whitebox/StackdriverModule.java @@ -78,16 +78,12 @@ static MetricWriter provideMetricWriter( @Provides static MetricReporter provideMetricReporter( MetricWriter metricWriter, @Config("metricsWriteInterval") Duration writeInterval, - JvmMetrics unusedJvmMetrics) { + JvmMetrics jvmMetrics) { + jvmMetrics.register(); + return new MetricReporter( metricWriter, writeInterval.getStandardSeconds(), new ThreadFactoryBuilder().setDaemon(true).build()); } - - @Singleton - @Provides - static JvmMetrics provideJvmMetrics() { - return new JvmMetrics(); - } } From 18cbfb91ead507c5f4dadb2bf05fce1830b349a8 Mon Sep 17 00:00:00 2001 From: Juan Celhay Date: Tue, 20 Jan 2026 12:30:51 -0500 Subject: [PATCH 7/9] redo tests --- .../registry/monitoring/whitebox/StackdriverModule.java | 2 +- .../google/registry/monitoring/whitebox/JvmMetricsTest.java | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/google/registry/monitoring/whitebox/StackdriverModule.java b/core/src/main/java/google/registry/monitoring/whitebox/StackdriverModule.java index 389ddb3e52f..dcfef956208 100644 --- a/core/src/main/java/google/registry/monitoring/whitebox/StackdriverModule.java +++ b/core/src/main/java/google/registry/monitoring/whitebox/StackdriverModule.java @@ -78,7 +78,7 @@ static MetricWriter provideMetricWriter( @Provides static MetricReporter provideMetricReporter( MetricWriter metricWriter, @Config("metricsWriteInterval") Duration writeInterval, - JvmMetrics jvmMetrics) { + JvmMetrics unusedJvmMetrics) { jvmMetrics.register(); return new MetricReporter( diff --git a/core/src/test/java/google/registry/monitoring/whitebox/JvmMetricsTest.java b/core/src/test/java/google/registry/monitoring/whitebox/JvmMetricsTest.java index 3856729ffc2..7b56326a29a 100644 --- a/core/src/test/java/google/registry/monitoring/whitebox/JvmMetricsTest.java +++ b/core/src/test/java/google/registry/monitoring/whitebox/JvmMetricsTest.java @@ -52,6 +52,8 @@ public void setUp() { @Test public void metricsRegistered() { + jvmMetrics.register(); + assertThat(registry.getRegisteredMetrics()).hasSize(3); for (var metric : registry.getRegisteredMetrics()) { @@ -61,6 +63,7 @@ public void metricsRegistered() { @Test public void testGetUsedMemory() { + jvmMetrics.register(); ImmutableMap, Long> values = jvmMetrics.getUsedMemory(); assertThat(values).containsExactly( @@ -70,6 +73,7 @@ public void testGetUsedMemory() { @Test public void testGetCommittedMemory() { + jvmMetrics.register(); ImmutableMap, Long> values = jvmMetrics.getCommittedMemory(); assertThat(values).containsExactly( @@ -79,6 +83,7 @@ public void testGetCommittedMemory() { @Test public void testGetMaxMemory() { + jvmMetrics.register(); ImmutableMap, Long> values = jvmMetrics.getMaxMemory(); assertThat(values).containsExactly( From 8f772974b5fc67ed380129158263cb3abbec3758 Mon Sep 17 00:00:00 2001 From: Juan Celhay Date: Tue, 20 Jan 2026 12:54:34 -0500 Subject: [PATCH 8/9] fix formatting/variable name --- .../java/google/registry/monitoring/whitebox/JvmMetrics.java | 3 ++- .../google/registry/monitoring/whitebox/StackdriverModule.java | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/google/registry/monitoring/whitebox/JvmMetrics.java b/core/src/main/java/google/registry/monitoring/whitebox/JvmMetrics.java index de4b7bc6562..0f2b832d16e 100644 --- a/core/src/main/java/google/registry/monitoring/whitebox/JvmMetrics.java +++ b/core/src/main/java/google/registry/monitoring/whitebox/JvmMetrics.java @@ -40,10 +40,11 @@ class JvmMetrics { this(ManagementFactory.getMemoryMXBean()); } - // Constructor for testing + /** Constructor for testing. */ JvmMetrics(MemoryMXBean memoryMxBean) { this.memoryMxBean = memoryMxBean; } + /** Registers JVM gauges with the default registry. */ void register() { MetricRegistry registry = MetricRegistryImpl.getDefault(); diff --git a/core/src/main/java/google/registry/monitoring/whitebox/StackdriverModule.java b/core/src/main/java/google/registry/monitoring/whitebox/StackdriverModule.java index dcfef956208..389ddb3e52f 100644 --- a/core/src/main/java/google/registry/monitoring/whitebox/StackdriverModule.java +++ b/core/src/main/java/google/registry/monitoring/whitebox/StackdriverModule.java @@ -78,7 +78,7 @@ static MetricWriter provideMetricWriter( @Provides static MetricReporter provideMetricReporter( MetricWriter metricWriter, @Config("metricsWriteInterval") Duration writeInterval, - JvmMetrics unusedJvmMetrics) { + JvmMetrics jvmMetrics) { jvmMetrics.register(); return new MetricReporter( From fefff6eeb547714ff92df518e97328e1cc90d826 Mon Sep 17 00:00:00 2001 From: Juan Celhay Date: Tue, 20 Jan 2026 13:45:20 -0500 Subject: [PATCH 9/9] lint --- .../monitoring/whitebox/JvmMetrics.java | 1 - .../whitebox/StackdriverModule.java | 3 +- .../monitoring/whitebox/JvmMetricsTest.java | 29 ++++++++++--------- 3 files changed, 18 insertions(+), 15 deletions(-) diff --git a/core/src/main/java/google/registry/monitoring/whitebox/JvmMetrics.java b/core/src/main/java/google/registry/monitoring/whitebox/JvmMetrics.java index 0f2b832d16e..750683986be 100644 --- a/core/src/main/java/google/registry/monitoring/whitebox/JvmMetrics.java +++ b/core/src/main/java/google/registry/monitoring/whitebox/JvmMetrics.java @@ -74,7 +74,6 @@ void register() { Long.class); } - ImmutableMap, Long> getUsedMemory() { MemoryUsage heapUsage = memoryMxBean.getHeapMemoryUsage(); MemoryUsage nonHeapUsage = memoryMxBean.getNonHeapMemoryUsage(); diff --git a/core/src/main/java/google/registry/monitoring/whitebox/StackdriverModule.java b/core/src/main/java/google/registry/monitoring/whitebox/StackdriverModule.java index 389ddb3e52f..0396e013e17 100644 --- a/core/src/main/java/google/registry/monitoring/whitebox/StackdriverModule.java +++ b/core/src/main/java/google/registry/monitoring/whitebox/StackdriverModule.java @@ -77,7 +77,8 @@ static MetricWriter provideMetricWriter( @Provides static MetricReporter provideMetricReporter( - MetricWriter metricWriter, @Config("metricsWriteInterval") Duration writeInterval, + MetricWriter metricWriter, + @Config("metricsWriteInterval") Duration writeInterval, JvmMetrics jvmMetrics) { jvmMetrics.register(); diff --git a/core/src/test/java/google/registry/monitoring/whitebox/JvmMetricsTest.java b/core/src/test/java/google/registry/monitoring/whitebox/JvmMetricsTest.java index 7b56326a29a..1bc4f040ecb 100644 --- a/core/src/test/java/google/registry/monitoring/whitebox/JvmMetricsTest.java +++ b/core/src/test/java/google/registry/monitoring/whitebox/JvmMetricsTest.java @@ -34,10 +34,10 @@ class JvmMetricsTests { private JvmMetrics jvmMetrics; private MemoryMXBean mockMemoryMXBean = mock(MemoryMXBean.class); - private static final MemoryUsage HEAP_USAGE = new MemoryUsage(/*init*/ 100, - /*used*/ 200, /*commited*/ 500, /*max*/ 1000); - private static final MemoryUsage NON_HEAP_USAGE = new MemoryUsage(/*init*/ 50, - /*used*/ 100, /*commited*/ 250, /*max*/ 500); + private static final MemoryUsage HEAP_USAGE = + new MemoryUsage(/*init*/ 100, /*used*/ 200, /*commited*/ 500, /*max*/ 1000); + private static final MemoryUsage NON_HEAP_USAGE = + new MemoryUsage(/*init*/ 50, /*used*/ 100, /*commited*/ 250, /*max*/ 500); @BeforeEach public void setUp() { @@ -66,9 +66,10 @@ public void testGetUsedMemory() { jvmMetrics.register(); ImmutableMap, Long> values = jvmMetrics.getUsedMemory(); - assertThat(values).containsExactly( - ImmutableList.of("heap"), 200L, - ImmutableList.of("non_heap"), 100L); + assertThat(values) + .containsExactly( + ImmutableList.of("heap"), 200L, + ImmutableList.of("non_heap"), 100L); } @Test @@ -76,9 +77,10 @@ public void testGetCommittedMemory() { jvmMetrics.register(); ImmutableMap, Long> values = jvmMetrics.getCommittedMemory(); - assertThat(values).containsExactly( - ImmutableList.of("heap"), 500L, - ImmutableList.of("non_heap"), 250L); + assertThat(values) + .containsExactly( + ImmutableList.of("heap"), 500L, + ImmutableList.of("non_heap"), 250L); } @Test @@ -86,8 +88,9 @@ public void testGetMaxMemory() { jvmMetrics.register(); ImmutableMap, Long> values = jvmMetrics.getMaxMemory(); - assertThat(values).containsExactly( - ImmutableList.of("heap"), 1000L, - ImmutableList.of("non_heap"), 500L); + assertThat(values) + .containsExactly( + ImmutableList.of("heap"), 1000L, + ImmutableList.of("non_heap"), 500L); } }