Browse Source

Fix double registered metrics and chain getters throwing NPE #104306

some of the metrics were accidentaly registered under the same name and were logging errors in apm agent logs (#103388)
also there were nullpointers in apm agent logs, the chained getters were replaced to use an optional
the fix in #103520 does not helped with NPEs
Przemyslaw Gomulka 1 year ago
parent
commit
293d0302fb
1 changed files with 269 additions and 56 deletions
  1. 269 56
      server/src/main/java/org/elasticsearch/monitor/metrics/NodeMetrics.java

+ 269 - 56
server/src/main/java/org/elasticsearch/monitor/metrics/NodeMetrics.java

@@ -24,6 +24,7 @@ import org.elasticsearch.telemetry.metric.MeterRegistry;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Optional;
 
 /**
  * NodeMetrics monitors various statistics of an Elasticsearch node and exposes them as metrics through
@@ -65,7 +66,13 @@ public class NodeMetrics extends AbstractLifecycleComponent {
                 "es.indices.get.total",
                 "Total number of get operations",
                 "operation",
-                () -> new LongWithAttributes(stats.getOrRefresh().getIndices().getGet().getCount())
+                () -> new LongWithAttributes(
+                    Optional.ofNullable(stats.getOrRefresh())
+                        .map(o -> o.getIndices())
+                        .map(o -> o.getGet())
+                        .map(o -> o.getCount())
+                        .orElse(0L)
+                )
             )
         );
 
@@ -74,7 +81,13 @@ public class NodeMetrics extends AbstractLifecycleComponent {
                 "es.indices.get.time",
                 "Time in milliseconds spent performing get operations.",
                 "milliseconds",
-                () -> new LongWithAttributes(stats.getOrRefresh().getIndices().getGet().getTimeInMillis())
+                () -> new LongWithAttributes(
+                    Optional.ofNullable(stats.getOrRefresh())
+                        .map(o -> o.getIndices())
+                        .map(o -> o.getGet())
+                        .map(o -> o.getTimeInMillis())
+                        .orElse(0L)
+                )
             )
         );
 
@@ -83,7 +96,14 @@ public class NodeMetrics extends AbstractLifecycleComponent {
                 "es.indices.search.fetch.total",
                 "Total number of fetch operations.",
                 "operation",
-                () -> new LongWithAttributes(stats.getOrRefresh().getIndices().getSearch().getTotal().getFetchCount())
+                () -> new LongWithAttributes(
+                    Optional.ofNullable(stats.getOrRefresh())
+                        .map(o -> o.getIndices())
+                        .map(o -> o.getSearch())
+                        .map(o -> o.getTotal())
+                        .map(o -> o.getFetchCount())
+                        .orElse(0L)
+                )
             )
         );
 
@@ -92,7 +112,14 @@ public class NodeMetrics extends AbstractLifecycleComponent {
                 "es.indices.search.fetch.time",
                 "Time in milliseconds spent performing fetch operations.",
                 "milliseconds",
-                () -> new LongWithAttributes(stats.getOrRefresh().getIndices().getSearch().getTotal().getFetchTimeInMillis())
+                () -> new LongWithAttributes(
+                    Optional.ofNullable(stats.getOrRefresh())
+                        .map(o -> o.getIndices())
+                        .map(o -> o.getSearch())
+                        .map(o -> o.getTotal())
+                        .map(o -> o.getFetchTimeInMillis())
+                        .orElse(0L)
+                )
             )
         );
 
@@ -101,7 +128,13 @@ public class NodeMetrics extends AbstractLifecycleComponent {
                 "es.indices.merge.total",
                 "Total number of merge operations.",
                 "operation",
-                () -> new LongWithAttributes(stats.getOrRefresh().getIndices().getMerge().getTotal())
+                () -> new LongWithAttributes(
+                    Optional.ofNullable(stats.getOrRefresh())
+                        .map(o -> o.getIndices())
+                        .map(o -> o.getMerge())
+                        .map(o -> o.getTotal())
+                        .orElse(0L)
+                )
             )
         );
 
@@ -110,7 +143,13 @@ public class NodeMetrics extends AbstractLifecycleComponent {
                 "es.indices.merge.time",
                 "Time in milliseconds spent performing merge operations.",
                 "milliseconds",
-                () -> new LongWithAttributes(stats.getOrRefresh().getIndices().getMerge().getTotalTimeInMillis())
+                () -> new LongWithAttributes(
+                    Optional.ofNullable(stats.getOrRefresh())
+                        .map(o -> o.getIndices())
+                        .map(o -> o.getMerge())
+                        .map(o -> o.getTotalTimeInMillis())
+                        .orElse(0L)
+                )
             )
         );
 
@@ -119,7 +158,13 @@ public class NodeMetrics extends AbstractLifecycleComponent {
                 "es.translog.operations.total",
                 "Number of transaction log operations.",
                 "operation",
-                () -> new LongWithAttributes(stats.getOrRefresh().getIndices().getTranslog().estimatedNumberOfOperations())
+                () -> new LongWithAttributes(
+                    Optional.ofNullable(stats.getOrRefresh())
+                        .map(o -> o.getIndices())
+                        .map(o -> o.getTranslog())
+                        .map(o -> o.estimatedNumberOfOperations())
+                        .orElse(0)
+                )
             )
         );
 
@@ -128,7 +173,13 @@ public class NodeMetrics extends AbstractLifecycleComponent {
                 "es.translog.size",
                 "Size, in bytes, of the transaction log.",
                 "bytes",
-                () -> new LongWithAttributes(stats.getOrRefresh().getIndices().getTranslog().getTranslogSizeInBytes())
+                () -> new LongWithAttributes(
+                    Optional.ofNullable(stats.getOrRefresh())
+                        .map(o -> o.getIndices())
+                        .map(o -> o.getTranslog())
+                        .map(o -> o.getTranslogSizeInBytes())
+                        .orElse(0L)
+                )
             )
         );
 
@@ -137,7 +188,13 @@ public class NodeMetrics extends AbstractLifecycleComponent {
                 "es.translog.uncommitted_operations.total",
                 "Number of uncommitted transaction log operations.",
                 "operations",
-                () -> new LongWithAttributes(stats.getOrRefresh().getIndices().getTranslog().getUncommittedOperations())
+                () -> new LongWithAttributes(
+                    Optional.ofNullable(stats.getOrRefresh())
+                        .map(o -> o.getIndices())
+                        .map(o -> o.getTranslog())
+                        .map(o -> o.getUncommittedOperations())
+                        .orElse(0)
+                )
             )
         );
 
@@ -146,7 +203,13 @@ public class NodeMetrics extends AbstractLifecycleComponent {
                 "es.translog.uncommitted_operations.size",
                 "Size, in bytes, of uncommitted transaction log operations.",
                 "bytes",
-                () -> new LongWithAttributes(stats.getOrRefresh().getIndices().getTranslog().getUncommittedSizeInBytes())
+                () -> new LongWithAttributes(
+                    Optional.ofNullable(stats.getOrRefresh())
+                        .map(o -> o.getIndices())
+                        .map(o -> o.getTranslog())
+                        .map(o -> o.getUncommittedSizeInBytes())
+                        .orElse(0L)
+                )
             )
         );
 
@@ -155,7 +218,13 @@ public class NodeMetrics extends AbstractLifecycleComponent {
                 "es.translog.earliest_last_modified.time",
                 "Earliest last modified age for the transaction log.",
                 "time",
-                () -> new LongWithAttributes(stats.getOrRefresh().getIndices().getTranslog().getEarliestLastModifiedAge())
+                () -> new LongWithAttributes(
+                    Optional.ofNullable(stats.getOrRefresh())
+                        .map(o -> o.getIndices())
+                        .map(o -> o.getTranslog())
+                        .map(o -> o.getEarliestLastModifiedAge())
+                        .orElse(0L)
+                )
             )
         );
 
@@ -164,7 +233,13 @@ public class NodeMetrics extends AbstractLifecycleComponent {
                 "es.transport.rx.size",
                 "Size, in bytes, of RX packets received by the node during internal cluster communication.",
                 "bytes",
-                () -> new LongWithAttributes(stats.getOrRefresh().getTransport().getRxSize().getBytes())
+                () -> new LongWithAttributes(
+                    Optional.ofNullable(stats.getOrRefresh())
+                        .map(o -> o.getTransport())
+                        .map(o -> o.getRxSize())
+                        .map(o -> o.getBytes())
+                        .orElse(0L)
+                )
             )
         );
 
@@ -173,7 +248,13 @@ public class NodeMetrics extends AbstractLifecycleComponent {
                 "es.transport.tx.size",
                 "Size, in bytes, of TX packets sent by the node during internal cluster communication.",
                 "bytes",
-                () -> new LongWithAttributes(stats.getOrRefresh().getTransport().getTxSize().getBytes())
+                () -> new LongWithAttributes(
+                    Optional.ofNullable(stats.getOrRefresh())
+                        .map(o -> o.getTransport())
+                        .map(o -> o.getTxSize())
+                        .map(o -> o.getBytes())
+                        .orElse(0L)
+                )
             )
         );
 
@@ -182,7 +263,9 @@ public class NodeMetrics extends AbstractLifecycleComponent {
                 "es.jvm.mem.pools.young.size",
                 "Memory, in bytes, used by the young generation heap.",
                 "bytes",
-                () -> new LongWithAttributes(bytesUsedByGCGen(stats.getOrRefresh().getJvm().getMem(), GcNames.YOUNG))
+                () -> new LongWithAttributes(
+                    bytesUsedByGCGen(Optional.ofNullable(stats.getOrRefresh()).map(o -> o.getJvm()).map(o -> o.getMem()), GcNames.YOUNG)
+                )
             )
         );
 
@@ -191,7 +274,9 @@ public class NodeMetrics extends AbstractLifecycleComponent {
                 "es.jvm.mem.pools.survivor.size",
                 "Memory, in bytes, used by the survivor space.",
                 "bytes",
-                () -> new LongWithAttributes(bytesUsedByGCGen(stats.getOrRefresh().getJvm().getMem(), GcNames.SURVIVOR))
+                () -> new LongWithAttributes(
+                    bytesUsedByGCGen(Optional.ofNullable(stats.getOrRefresh()).map(o -> o.getJvm()).map(o -> o.getMem()), GcNames.SURVIVOR)
+                )
             )
         );
 
@@ -200,7 +285,9 @@ public class NodeMetrics extends AbstractLifecycleComponent {
                 "es.jvm.mem.pools.old.size",
                 "Memory, in bytes, used by the old generation heap.",
                 "bytes",
-                () -> new LongWithAttributes(bytesUsedByGCGen(stats.getOrRefresh().getJvm().getMem(), GcNames.OLD))
+                () -> new LongWithAttributes(
+                    bytesUsedByGCGen(Optional.ofNullable(stats.getOrRefresh()).map(o -> o.getJvm()).map(o -> o.getMem()), GcNames.OLD)
+                )
             )
         );
 
@@ -209,7 +296,13 @@ public class NodeMetrics extends AbstractLifecycleComponent {
                 "es.fs.io_stats.time.total",
                 "The total time in millis spent performing I/O operations across all devices used by Elasticsearch.",
                 "milliseconds",
-                () -> new LongWithAttributes(stats.getOrRefresh().getFs().getIoStats().getTotalIOTimeMillis())
+                () -> new LongWithAttributes(
+                    Optional.ofNullable(stats.getOrRefresh())
+                        .map(o -> o.getFs())
+                        .map(o -> o.getIoStats())
+                        .map(o -> o.getTotalIOTimeMillis())
+                        .orElse(0L)
+                )
             )
         );
 
@@ -218,61 +311,112 @@ public class NodeMetrics extends AbstractLifecycleComponent {
                 "es.indexing.docs.total",
                 "Total number of indexed documents",
                 "documents",
-                () -> new LongWithAttributes(stats.getOrRefresh().getIndices().getIndexing().getTotal().getIndexCount())
+                () -> new LongWithAttributes(
+                    Optional.ofNullable(stats.getOrRefresh())
+                        .map(o -> o.getIndices())
+                        .map(o -> o.getIndexing())
+                        .map(o -> o.getTotal())
+                        .map(o -> o.getIndexCount())
+                        .orElse(0L)
+                )
             )
         );
 
         metrics.add(
             registry.registerLongGauge(
-                "es.indexing.docs.total",
+                "es.indexing.docs.current.total",
                 "Current number of indexing documents",
                 "documents",
-                () -> new LongWithAttributes(stats.getOrRefresh().getIndices().getIndexing().getTotal().getIndexCurrent())
+                () -> new LongWithAttributes(
+                    Optional.ofNullable(stats.getOrRefresh())
+                        .map(o -> o.getIndices())
+                        .map(o -> o.getIndexing())
+                        .map(o -> o.getTotal())
+                        .map(o -> o.getIndexCurrent())
+                        .orElse(0L)
+                )
             )
         );
 
         metrics.add(
             registry.registerLongAsyncCounter(
-                "es.indices.indexing.failed.total",
+                "es.indexing.indexing.failed.total",
                 "Total number of failed indexing operations",
                 "operations",
-                () -> new LongWithAttributes(stats.getOrRefresh().getIndices().getIndexing().getTotal().getIndexFailedCount())
+                () -> new LongWithAttributes(
+                    Optional.ofNullable(stats.getOrRefresh())
+                        .map(o -> o.getIndices())
+                        .map(o -> o.getIndexing())
+                        .map(o -> o.getTotal())
+                        .map(o -> o.getIndexFailedCount())
+                        .orElse(0L)
+                )
             )
         );
 
         metrics.add(
             registry.registerLongAsyncCounter(
-                "es.indices.deletion.docs.total",
+                "es.indexing.deletion.docs.total",
                 "Total number of deleted documents",
                 "documents",
-                () -> new LongWithAttributes(stats.getOrRefresh().getIndices().getIndexing().getTotal().getDeleteCount())
+                () -> new LongWithAttributes(
+                    Optional.ofNullable(stats.getOrRefresh())
+                        .map(o -> o.getIndices())
+                        .map(o -> o.getIndexing())
+                        .map(o -> o.getTotal())
+                        .map(o -> o.getDeleteCount())
+                        .orElse(0L)
+                )
             )
         );
 
         metrics.add(
             registry.registerLongGauge(
-                "es.indices.deletion.docs.total",
+                "es.indexing.deletion.docs.current.total",
                 "Current number of deleting documents",
                 "documents",
-                () -> new LongWithAttributes(stats.getOrRefresh().getIndices().getIndexing().getTotal().getDeleteCurrent())
+                () -> new LongWithAttributes(
+                    Optional.ofNullable(stats.getOrRefresh())
+                        .map(o -> o.getIndices())
+                        .map(o -> o.getIndexing())
+                        .map(o -> o.getTotal())
+                        .map(o -> o.getDeleteCurrent())
+                        .orElse(0L)
+                )
             )
         );
 
         metrics.add(
             registry.registerLongAsyncCounter(
-                "es.indices.indexing.time",
+                "es.indexing.time",
                 "Total indices indexing time",
                 "milliseconds",
-                () -> new LongWithAttributes(stats.getOrRefresh().getIndices().getIndexing().getTotal().getIndexTime().millis())
+                () -> new LongWithAttributes(
+                    Optional.ofNullable(stats.getOrRefresh())
+                        .map(o -> o.getIndices())
+                        .map(o -> o.getIndexing())
+                        .map(o -> o.getTotal())
+                        .map(o -> o.getIndexTime())
+                        .map(o -> o.millis())
+                        .orElse(0L)
+                )
             )
         );
 
         metrics.add(
             registry.registerLongAsyncCounter(
-                "es.indices.deletion.time",
+                "es.deletion.time",
                 "Total indices deletion time",
                 "milliseconds",
-                () -> new LongWithAttributes(stats.getOrRefresh().getIndices().getIndexing().getTotal().getDeleteTime().millis())
+                () -> new LongWithAttributes(
+                    Optional.ofNullable(stats.getOrRefresh())
+                        .map(o -> o.getIndices())
+                        .map(o -> o.getIndexing())
+                        .map(o -> o.getTotal())
+                        .map(o -> o.getDeleteTime())
+                        .map(o -> o.millis())
+                        .orElse(0L)
+                )
             )
         );
 
@@ -281,7 +425,15 @@ public class NodeMetrics extends AbstractLifecycleComponent {
                 "es.indices.throttle.time",
                 "Total indices throttle time",
                 "milliseconds",
-                () -> new LongWithAttributes(stats.getOrRefresh().getIndices().getIndexing().getTotal().getThrottleTime().millis())
+                () -> new LongWithAttributes(
+                    Optional.ofNullable(stats.getOrRefresh())
+                        .map(o -> o.getIndices())
+                        .map(o -> o.getIndexing())
+                        .map(o -> o.getTotal())
+                        .map(o -> o.getThrottleTime())
+                        .map(o -> o.millis())
+                        .orElse(0L)
+                )
             )
         );
 
@@ -290,7 +442,14 @@ public class NodeMetrics extends AbstractLifecycleComponent {
                 "es.indices.noop.total",
                 "Total number of noop shard operations",
                 "operations",
-                () -> new LongWithAttributes(stats.getOrRefresh().getIndices().getIndexing().getTotal().getNoopUpdateCount())
+                () -> new LongWithAttributes(
+                    Optional.ofNullable(stats.getOrRefresh())
+                        .map(o -> o.getIndices())
+                        .map(o -> o.getIndexing())
+                        .map(o -> o.getTotal())
+                        .map(o -> o.getNoopUpdateCount())
+                        .orElse(0L)
+                )
             )
         );
 
@@ -299,7 +458,12 @@ public class NodeMetrics extends AbstractLifecycleComponent {
                 "es.indexing.coordinating_operations.size",
                 "Total number of memory bytes consumed by coordinating operations",
                 "bytes",
-                () -> new LongWithAttributes(stats.getOrRefresh().getIndexingPressureStats().getTotalCoordinatingBytes())
+                () -> new LongWithAttributes(
+                    Optional.ofNullable(stats.getOrRefresh())
+                        .map(o -> o.getIndexingPressureStats())
+                        .map(o -> o.getTotalCoordinatingBytes())
+                        .orElse(0L)
+                )
             )
         );
 
@@ -308,25 +472,40 @@ public class NodeMetrics extends AbstractLifecycleComponent {
                 "es.indexing.coordinating_operations.total",
                 "Total number of coordinating operations",
                 "operations",
-                () -> new LongWithAttributes(stats.getOrRefresh().getIndexingPressureStats().getTotalCoordinatingOps())
+                () -> new LongWithAttributes(
+                    Optional.ofNullable(stats.getOrRefresh())
+                        .map(o -> o.getIndexingPressureStats())
+                        .map(o -> o.getTotalCoordinatingOps())
+                        .orElse(0L)
+                )
             )
         );
 
         metrics.add(
             registry.registerLongGauge(
-                "es.indexing.coordinating_operations.size",
+                "es.indexing.coordinating_operations.current.size",
                 "Current number of memory bytes consumed by coordinating operations",
                 "bytes",
-                () -> new LongWithAttributes(stats.getOrRefresh().getIndexingPressureStats().getCurrentCoordinatingBytes())
+                () -> new LongWithAttributes(
+                    Optional.ofNullable(stats.getOrRefresh())
+                        .map(o -> o.getIndexingPressureStats())
+                        .map(o -> o.getCurrentCoordinatingBytes())
+                        .orElse(0L)
+                )
             )
         );
 
         metrics.add(
             registry.registerLongGauge(
-                "es.indexing.coordinating_operations.total",
+                "es.indexing.coordinating_operations.current.total",
                 "Current number of coordinating operations",
                 "operations",
-                () -> new LongWithAttributes(stats.getOrRefresh().getIndexingPressureStats().getCurrentCoordinatingOps())
+                () -> new LongWithAttributes(
+                    Optional.ofNullable(stats.getOrRefresh())
+                        .map(o -> o.getIndexingPressureStats())
+                        .map(o -> o.getCurrentCoordinatingOps())
+                        .orElse(0L)
+                )
             )
         );
 
@@ -335,7 +514,12 @@ public class NodeMetrics extends AbstractLifecycleComponent {
                 "es.indexing.coordinating_operations.rejections.total",
                 "Total number of coordinating operations rejections",
                 "operations",
-                () -> new LongWithAttributes(stats.getOrRefresh().getIndexingPressureStats().getCoordinatingRejections())
+                () -> new LongWithAttributes(
+                    Optional.ofNullable(stats.getOrRefresh())
+                        .map(o -> o.getIndexingPressureStats())
+                        .map(o -> o.getCoordinatingRejections())
+                        .orElse(0L)
+                )
             )
         );
 
@@ -344,7 +528,12 @@ public class NodeMetrics extends AbstractLifecycleComponent {
                 "es.indexing.primary_operations.size",
                 "Total number of memory bytes consumed by primary operations",
                 "bytes",
-                () -> new LongWithAttributes(stats.getOrRefresh().getIndexingPressureStats().getTotalPrimaryBytes())
+                () -> new LongWithAttributes(
+                    Optional.ofNullable(stats.getOrRefresh())
+                        .map(o -> o.getIndexingPressureStats())
+                        .map(o -> o.getTotalPrimaryBytes())
+                        .orElse(0L)
+                )
             )
         );
 
@@ -353,25 +542,40 @@ public class NodeMetrics extends AbstractLifecycleComponent {
                 "es.indexing.primary_operations.total",
                 "Total number of primary operations",
                 "operations",
-                () -> new LongWithAttributes(stats.getOrRefresh().getIndexingPressureStats().getTotalPrimaryOps())
+                () -> new LongWithAttributes(
+                    Optional.ofNullable(stats.getOrRefresh())
+                        .map(o -> o.getIndexingPressureStats())
+                        .map(o -> o.getTotalPrimaryOps())
+                        .orElse(0L)
+                )
             )
         );
 
         metrics.add(
             registry.registerLongGauge(
-                "es.indexing.primary_operations.size",
+                "es.indexing.primary_operations.current.size",
                 "Current number of memory bytes consumed by primary operations",
                 "bytes",
-                () -> new LongWithAttributes(stats.getOrRefresh().getIndexingPressureStats().getCurrentPrimaryBytes())
+                () -> new LongWithAttributes(
+                    Optional.ofNullable(stats.getOrRefresh())
+                        .map(o -> o.getIndexingPressureStats())
+                        .map(o -> o.getCurrentPrimaryBytes())
+                        .orElse(0L)
+                )
             )
         );
 
         metrics.add(
             registry.registerLongGauge(
-                "es.indexing.primary_operations.total",
+                "es.indexing.primary_operations.current.total",
                 "Current number of primary operations",
                 "operations",
-                () -> new LongWithAttributes(stats.getOrRefresh().getIndexingPressureStats().getCurrentPrimaryOps())
+                () -> new LongWithAttributes(
+                    Optional.ofNullable(stats.getOrRefresh())
+                        .map(o -> o.getIndexingPressureStats())
+                        .map(o -> o.getCurrentPrimaryOps())
+                        .orElse(0L)
+                )
             )
         );
 
@@ -380,7 +584,12 @@ public class NodeMetrics extends AbstractLifecycleComponent {
                 "es.indexing.primary_operations.rejections.total",
                 "Total number of primary operations rejections",
                 "operations",
-                () -> new LongWithAttributes(stats.getOrRefresh().getIndexingPressureStats().getPrimaryRejections())
+                () -> new LongWithAttributes(
+                    Optional.ofNullable(stats.getOrRefresh())
+                        .map(o -> o.getIndexingPressureStats())
+                        .map(o -> o.getPrimaryRejections())
+                        .orElse(0L)
+                )
             )
         );
 
@@ -389,7 +598,9 @@ public class NodeMetrics extends AbstractLifecycleComponent {
                 "es.indexing.memory.limit.size",
                 "Current memory limit for primary and coordinating operations",
                 "bytes",
-                () -> new LongWithAttributes(stats.getOrRefresh().getIndexingPressureStats().getMemoryLimit())
+                () -> new LongWithAttributes(
+                    Optional.ofNullable(stats.getOrRefresh()).map(o -> o.getIndexingPressureStats()).map(o -> o.getMemoryLimit()).orElse(0L)
+                )
             )
         );
 
@@ -398,18 +609,20 @@ public class NodeMetrics extends AbstractLifecycleComponent {
     /**
      * Retrieves the bytes used by a specific garbage collection generation from the provided JvmStats.Mem.
      *
-     * @param mem  The JvmStats.Mem containing memory pool information.
-     * @param name The name of the garbage collection generation (e.g., "young", "survivor", "old").
+     * @param optionalMem The JvmStats.Mem containing memory pool information.
+     * @param name        The name of the garbage collection generation (e.g., "young", "survivor", "old").
      * @return The number of bytes used by the specified garbage collection generation.
      */
-    private long bytesUsedByGCGen(JvmStats.Mem mem, String name) {
-        long bytesUsed = 0;
-        for (JvmStats.MemoryPool pool : mem) {
-            if (pool.getName().equals(name)) {
-                bytesUsed = pool.getUsed().getBytes();
+    private long bytesUsedByGCGen(Optional<JvmStats.Mem> optionalMem, String name) {
+        return optionalMem.map(mem -> {
+            long bytesUsed = 0;
+            for (JvmStats.MemoryPool pool : mem) {
+                if (pool.getName().equals(name)) {
+                    bytesUsed = pool.getUsed().getBytes();
+                }
             }
-        }
-        return bytesUsed;
+            return bytesUsed;
+        }).orElse(0L);
     }
 
     /**