From 14dddb04d780adcc1ce1936a89331e15d1e9f091 Mon Sep 17 00:00:00 2001 From: franz1981 Date: Thu, 30 Jul 2020 12:15:50 +0200 Subject: [PATCH] ARTEMIS-3280 Netty Pool micrometer metric plugin --- .../config/ActiveMQDefaultConfiguration.java | 10 + .../core/config/MetricsConfiguration.java | 10 + .../impl/FileConfigurationParser.java | 2 + .../core/server/metrics/MetricsManager.java | 4 + .../metrics/NettyPooledAllocatorMetrics.java | 369 ++++++++++++++++++ .../schema/artemis-configuration.xsd | 8 + .../config/impl/FileConfigurationTest.java | 2 + .../ConfigurationTest-full-config.xml | 1 + .../ConfigurationTest-xinclude-config.xml | 1 + artemis-server/src/test/resources/metrics.xml | 1 + docs/user-manual/en/metrics.md | 6 +- 11 files changed, 412 insertions(+), 2 deletions(-) create mode 100644 artemis-server/src/main/java/org/apache/activemq/artemis/core/server/metrics/NettyPooledAllocatorMetrics.java diff --git a/artemis-core-client/src/main/java/org/apache/activemq/artemis/api/config/ActiveMQDefaultConfiguration.java b/artemis-core-client/src/main/java/org/apache/activemq/artemis/api/config/ActiveMQDefaultConfiguration.java index 420acac70b..f5771398a3 100644 --- a/artemis-core-client/src/main/java/org/apache/activemq/artemis/api/config/ActiveMQDefaultConfiguration.java +++ b/artemis-core-client/src/main/java/org/apache/activemq/artemis/api/config/ActiveMQDefaultConfiguration.java @@ -630,6 +630,9 @@ public final class ActiveMQDefaultConfiguration { // Number of concurrent workers for a core bridge public static int DEFAULT_BRIDGE_CONCURRENCY = 1; + // Whether or not to report Netty pool metrics + private static final boolean DEFAULT_NETTY_POOL_METRICS = false; + /** * If true then the ActiveMQ Artemis Server will make use of any Protocol Managers that are in available on the classpath. If false then only the core protocol will be available, unless in Embedded mode where users can inject their own Protocol Managers. */ @@ -1721,4 +1724,11 @@ public final class ActiveMQDefaultConfiguration { public static int getDefaultBridgeConcurrency() { return DEFAULT_BRIDGE_CONCURRENCY; } + + /** + * Whether or not to report Netty pool metrics + */ + public static Boolean getDefaultNettyPoolMetrics() { + return DEFAULT_NETTY_POOL_METRICS; + } } diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/config/MetricsConfiguration.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/config/MetricsConfiguration.java index 7244a73437..8a029b0877 100644 --- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/config/MetricsConfiguration.java +++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/config/MetricsConfiguration.java @@ -27,6 +27,7 @@ public class MetricsConfiguration implements Serializable { private boolean jvmMemory = ActiveMQDefaultConfiguration.getDefaultJvmMemoryMetrics(); private boolean jvmGc = ActiveMQDefaultConfiguration.getDefaultJvmGcMetrics(); private boolean jvmThread = ActiveMQDefaultConfiguration.getDefaultJvmThreadMetrics(); + private boolean nettyPool = ActiveMQDefaultConfiguration.getDefaultNettyPoolMetrics(); private ActiveMQMetricsPlugin plugin; public boolean isJvmMemory() { @@ -56,6 +57,15 @@ public class MetricsConfiguration implements Serializable { return this; } + public boolean isNettyPool() { + return nettyPool; + } + + public MetricsConfiguration setNettyPool(boolean nettyPool) { + this.nettyPool = nettyPool; + return this; + } + public ActiveMQMetricsPlugin getPlugin() { return plugin; } diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/deployers/impl/FileConfigurationParser.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/deployers/impl/FileConfigurationParser.java index 2dda424f18..d93af438bb 100644 --- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/deployers/impl/FileConfigurationParser.java +++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/deployers/impl/FileConfigurationParser.java @@ -907,6 +907,8 @@ public final class FileConfigurationParser extends XMLConfigurationUtil { metricsConfiguration.setJvmMemory(XMLUtil.parseBoolean(child)); } else if (child.getNodeName().equals("jvm-threads")) { metricsConfiguration.setJvmThread(XMLUtil.parseBoolean(child)); + } else if (child.getNodeName().equals("netty-pool")) { + metricsConfiguration.setNettyPool(XMLUtil.parseBoolean(child)); } else if (child.getNodeName().equals("plugin")) { metricsConfiguration.setPlugin(parseMetricsPlugin(child, config)); } diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/metrics/MetricsManager.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/metrics/MetricsManager.java index 8fab39c09b..9047a31720 100644 --- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/metrics/MetricsManager.java +++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/metrics/MetricsManager.java @@ -31,6 +31,7 @@ import io.micrometer.core.instrument.Metrics; import io.micrometer.core.instrument.binder.jvm.JvmGcMetrics; import io.micrometer.core.instrument.binder.jvm.JvmMemoryMetrics; import io.micrometer.core.instrument.binder.jvm.JvmThreadMetrics; +import io.netty.buffer.PooledByteBufAllocator; import org.apache.activemq.artemis.api.core.management.ResourceNames; import org.apache.activemq.artemis.core.config.MetricsConfiguration; import org.apache.activemq.artemis.core.settings.HierarchicalRepository; @@ -65,6 +66,9 @@ public class MetricsManager { if (metricsConfiguration.isJvmThread()) { new JvmThreadMetrics().bindTo(meterRegistry); } + if (metricsConfiguration.isNettyPool()) { + new NettyPooledAllocatorMetrics(PooledByteBufAllocator.DEFAULT.metric()).bindTo(meterRegistry); + } } public MeterRegistry getMeterRegistry() { diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/metrics/NettyPooledAllocatorMetrics.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/metrics/NettyPooledAllocatorMetrics.java new file mode 100644 index 0000000000..6274d8d2fd --- /dev/null +++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/metrics/NettyPooledAllocatorMetrics.java @@ -0,0 +1,369 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 org.apache.activemq.artemis.core.server.metrics; + +import java.util.List; +import java.util.function.Function; + +import io.micrometer.core.instrument.Gauge; +import io.micrometer.core.instrument.MeterRegistry; +import io.micrometer.core.instrument.binder.MeterBinder; +import io.netty.buffer.PoolChunkListMetric; +import io.netty.buffer.PoolChunkMetric; +import io.netty.buffer.PoolSubpageMetric; +import io.netty.buffer.PooledByteBufAllocatorMetric; +import io.micrometer.core.instrument.FunctionCounter; +import io.netty.buffer.PoolArenaMetric; + +public final class NettyPooledAllocatorMetrics implements MeterBinder { + + private static final String BYTES_UNIT = "bytes"; + private final PooledByteBufAllocatorMetric metric; + + public NettyPooledAllocatorMetrics(final PooledByteBufAllocatorMetric pooledAllocatorMetric) { + this.metric = pooledAllocatorMetric; + } + + @Override + public void bindTo(final MeterRegistry registry) { + + Gauge.builder("netty.pooled.used.memory", this.metric, metric -> metric.usedDirectMemory()) + .tags("type", "direct") + .description("The used memory") + .baseUnit(BYTES_UNIT).register(registry); + + Gauge.builder("netty.pooled.used.memory", this.metric, metric -> metric.usedHeapMemory()) + .tags("type", "heap") + .description("The used memory") + .baseUnit(BYTES_UNIT).register(registry); + + Gauge.builder("netty.pooled.arenas.num", this.metric, metric -> metric.numDirectArenas()) + .tags("type", "direct") + .description("The number of arenas") + .register(registry); + + Gauge.builder("netty.pooled.arenas.num", this.metric, metric -> metric.numHeapArenas()) + .tags("type", "heap").description("The number or arenas") + .register(registry); + + Gauge.builder("netty.pooled.cachesize", this.metric, metric -> metric.tinyCacheSize()) + .tags("type", "tiny") + .description("The cachesize used by this netty allocator") + .register(registry); + + Gauge.builder("netty.pooled.cachesize", this.metric, metric -> metric.smallCacheSize()) + .tags("type", "small") + .description("The cachesize used by this netty allocator") + .register(registry); + + Gauge.builder("netty.pooled.cachesize", this.metric, metric -> metric.normalCacheSize()) + .tags("type", "normal") + .description("The cachesize used by this netty allocator") + .register(registry); + + Gauge.builder("netty.pooled.threadlocalcache.num", this.metric, metric -> metric.numThreadLocalCaches()) + .description("The number of thread local caches used by this netty allocator") + .register(registry); + + Gauge.builder("netty.pooled.chunk.size", this.metric, metric -> metric.chunkSize()) + .description("The arena chunk size of this netty allocator") + .baseUnit(BYTES_UNIT) + .register(registry); + + { + int i = 0; + for (final PoolArenaMetric poolArenaMetric : metric.directArenas()) { + metricsOfPoolArena(registry, poolArenaMetric, i++, "direct"); + } + } + { + int i = 0; + for (final PoolArenaMetric poolArenaMetric : metric.heapArenas()) { + metricsOfPoolArena(registry, poolArenaMetric, i++, "heap"); + } + } + } + + private void metricsOfPoolArena(final MeterRegistry registry, + final PoolArenaMetric poolArenaMetric, + final int poolArenaIndex, + final String poolArenaType) { + /** + * the number of thread caches backed by this arena. + */ + final String poolArenaIndexString = Integer.toString(poolArenaIndex); + Gauge.builder("netty.pooled.arena.threadcaches.num", poolArenaMetric, metric -> metric.numThreadCaches()) + .tags("pool_arena_type", poolArenaType, "pool_arena_index", poolArenaIndexString) + .description("The number of thread caches backed by this arena") + .register(registry); + + FunctionCounter.builder("netty.pooled.arena.allocations.num", poolArenaMetric, + metric -> metric.numAllocations()) + .tags("pool_arena_type", poolArenaType, "pool_arena_index", poolArenaIndexString, "size", "all") + .description("The number of allocations done via the arena. This includes all sizes") + .register(registry); + + FunctionCounter.builder("netty.pooled.arena.allocations.num", poolArenaMetric, + metric -> metric.numTinyAllocations()) + .tags("pool_arena_type", poolArenaType, "pool_arena_index", poolArenaIndexString, "size", "tiny") + .description("The number of tiny allocations done via the arena") + .register(registry); + + FunctionCounter.builder("netty.pooled.arena.allocations.num", poolArenaMetric, + metric -> metric.numSmallAllocations()) + .tags("pool_arena_type", poolArenaType, "pool_arena_index", poolArenaIndexString, "size", "small") + .description("The number of small allocations done via the arena") + .register(registry); + + FunctionCounter.builder("netty.pooled.arena.allocations.num", poolArenaMetric, + metric -> metric.numNormalAllocations()) + .tags("pool_arena_type", poolArenaType, "pool_arena_index", poolArenaIndexString, "size", "normal") + .description("The number of normal allocations done via the arena") + .register(registry); + + FunctionCounter.builder("netty.pooled.arena.allocations.num", poolArenaMetric, + metric -> metric.numHugeAllocations()) + .tags("pool_arena_type", poolArenaType, "pool_arena_index", poolArenaIndexString, "size", "huge") + .description("The number of huge allocations done via the arena") + .register(registry); + + FunctionCounter.builder("netty.pooled.arena.deallocations.num", poolArenaMetric, + metric -> metric.numDeallocations()) + .tags("pool_arena_type", poolArenaType, "pool_arena_index", poolArenaIndexString, "size", "all") + .description("The number of deallocations done via the arena. This includes all sizes") + .register(registry); + + FunctionCounter.builder("netty.pooled.arena.deallocations.num", poolArenaMetric, + metric -> metric.numTinyDeallocations()) + .tags("pool_arena_type", poolArenaType, "pool_arena_index", poolArenaIndexString, "size", "tiny") + .description("The number of tiny deallocations done via the arena") + .register(registry); + + FunctionCounter.builder("netty.pooled.arena.deallocations.num", poolArenaMetric, + metric -> metric.numSmallDeallocations()) + .tags("pool_arena_type", poolArenaType, "pool_arena_index", poolArenaIndexString, "size", "small") + .description("The number of small deallocations done via the arena") + .register(registry); + + FunctionCounter.builder("netty.pooled.arena.deallocations.num", poolArenaMetric, + metric -> metric.numNormalDeallocations()) + .tags("pool_arena_type", poolArenaType, "pool_arena_index", poolArenaIndexString, "size", "normal") + .description("The number of normal deallocations done via the arena") + .register(registry); + + FunctionCounter.builder("netty.pooled.arena.deallocations.num", poolArenaMetric, + metric -> metric.numHugeDeallocations()) + .tags("pool_arena_type", poolArenaType, "pool_arena_index", poolArenaIndexString, "size", "huge") + .description("The number of huge deallocations done via the arena") + .register(registry); + + Gauge.builder("netty.pooled.arena.active.allocations.num", poolArenaMetric, + metric -> metric.numActiveAllocations()) + .tags("pool_arena_type", poolArenaType, "pool_arena_index", poolArenaIndexString, "size", "all") + .description("The number of currently active allocations") + .register(registry); + + Gauge.builder("netty.pooled.arena.active.allocations.num", poolArenaMetric, + metric -> metric.numActiveTinyAllocations()) + .tags("pool_arena_type", poolArenaType, "pool_arena_index", poolArenaIndexString, "size", "tiny") + .description("The number of currently active tiny allocations") + .register(registry); + + Gauge.builder("netty.pooled.arena.active.allocations.num", poolArenaMetric, + metric -> metric.numActiveSmallAllocations()) + .tags("pool_arena_type", poolArenaType, "pool_arena_index", poolArenaIndexString, "size", "small") + .description("The number of currently active small allocations") + .register(registry); + + Gauge.builder("netty.pooled.arena.active.allocations.num", poolArenaMetric, + metric -> metric.numActiveNormalAllocations()) + .tags("pool_arena_type", poolArenaType, "pool_arena_index", poolArenaIndexString, "size", "normal") + .description("The number of currently active normal allocations") + .register(registry); + + Gauge.builder("netty.pooled.arena.active.allocations.num", poolArenaMetric, + metric -> metric.numActiveHugeAllocations()) + .tags("pool_arena_type", poolArenaType, "pool_arena_index", poolArenaIndexString, "size", "huge") + .description("The number of currently active huge allocations") + .register(registry); + + Gauge.builder("netty.pooled.arena.active.allocated.num", poolArenaMetric, + metric -> metric.numActiveBytes()) + .tags("pool_arena_type", poolArenaType, "pool_arena_index", poolArenaIndexString) + .description("The number of active bytes that are currently allocated by the arena") + .baseUnit(BYTES_UNIT).register(registry); + + Gauge.builder("netty.pooled.arena.chunk.num", poolArenaMetric, + metric -> metric.numChunkLists()) + .tags("pool_arena_type", poolArenaType, "pool_arena_index", poolArenaIndexString) + .description("The number of chunk lists for the arena") + .register(registry); + + Gauge.builder("netty.pooled.arena.subpages.num", poolArenaMetric, + metric -> metric.numTinySubpages()) + .tags("pool_arena_type", poolArenaType, "pool_arena_index", poolArenaIndexString, "size", "tiny") + .description("The number of tiny sub-pages for the arena") + .register(registry); + + Gauge.builder("netty.pooled.arena.subpages.num", poolArenaMetric, + metric -> metric.numSmallSubpages()) + .tags("pool_arena_type", poolArenaType, "pool_arena_index", poolArenaIndexString, "size", "small") + .description("The number of small sub-pages for the arena") + .register(registry); + + List poolChunkListMetrics = poolArenaMetric.chunkLists(); + assert poolChunkListMetrics.size() == 6; + for (PoolChunkListMetric poolChunkListMetric : poolChunkListMetrics) { + final String poolChunkListType = usageTypeOf(poolChunkListMetric); + metricsOfPoolChunkListMetric(registry, poolChunkListMetric, poolArenaIndexString, poolArenaType, poolChunkListType); + } + // smallSubpages metrics + metricsOfPoolSubpageMetric(registry, poolArenaMetric, PoolArenaMetric::smallSubpages, + poolArenaIndexString, poolArenaType, "small"); + // tinySubpages metrics + metricsOfPoolSubpageMetric(registry, poolArenaMetric, PoolArenaMetric::tinySubpages, + poolArenaIndexString, poolArenaType, "tiny"); + + + + } + + private void metricsOfPoolSubpageMetric(final MeterRegistry registry, + final PoolArenaMetric poolArenaMetric, + final Function> poolSubpageMetricProvider, + final String poolArenaIndex, + final String poolArenaType, + final String size) { + Gauge.builder("netty.pooled.arena.subpages.count", poolArenaMetric, metric -> { + long total = 0; + for (PoolSubpageMetric poolSubpageMetric : poolSubpageMetricProvider.apply(metric)) { + total++; + } + return total; + }) + .tags("pool_arena_type", poolArenaType, "pool_arena_index", poolArenaIndex, "size", size) + .description("The total count of subpages") + .register(registry); + + Gauge.builder("netty.pooled.arena.subpages.elementsize", poolArenaMetric, metric -> { + long total = 0; + for (PoolSubpageMetric poolSubpageMetric : poolSubpageMetricProvider.apply(metric)) { + total += poolSubpageMetric.elementSize(); + } + return total; + }) + .tags("pool_arena_type", poolArenaType, "pool_arena_index", poolArenaIndex, "size", size) + .description("The total size (in bytes) of the elements that will be allocated") + .baseUnit(BYTES_UNIT) + .register(registry); + + Gauge.builder("netty.pooled.arena.subpages.maxnumelements", poolArenaMetric, metric -> { + long total = 0; + for (PoolSubpageMetric poolSubpageMetric : poolSubpageMetricProvider.apply(metric)) { + total += poolSubpageMetric.maxNumElements(); + } + return total; + }) + .tags("pool_arena_type", poolArenaType, "pool_arena_index", poolArenaIndex, "size", size) + .description("The total number of maximal elements that can be allocated out of the sub-page.") + .register(registry); + + Gauge.builder("netty.pooled.arena.subpages.numavailable", poolArenaMetric, metric -> { + long total = 0; + for (PoolSubpageMetric poolSubpageMetric : poolSubpageMetricProvider.apply(metric)) { + total += poolSubpageMetric.numAvailable(); + } + return total; + }) + .tags("pool_arena_type", poolArenaType, "pool_arena_index", poolArenaIndex, "size", size) + .description("The total number of available elements to be allocated") + .register(registry); + Gauge.builder("netty.pooled.arena.subpages.pagesize", poolArenaMetric, metric -> { + long total = 0; + for (PoolSubpageMetric poolSubpageMetric : poolSubpageMetricProvider.apply(metric)) { + total += poolSubpageMetric.pageSize(); + } + return total; + }) + .tags("pool_arena_type", poolArenaType, "pool_arena_index", poolArenaIndex, "size", size) + .description("The total size (in bytes) of the pages") + .baseUnit(BYTES_UNIT) + .register(registry); + } + + private static String usageTypeOf(PoolChunkListMetric metric) { + // metrics.add(qInit); 0~25% -> new PoolChunkList(this, q000, Integer.MIN_VALUE, 25, chunkSize); + // metrics.add(q000); 0~50% -> new PoolChunkList(this, q025, 1, 50, chunkSize); + // metrics.add(q025); 25~75% -> new PoolChunkList(this, q050, 25, 75, chunkSize); + // metrics.add(q050); 50~100% -> new PoolChunkList(this, q075, 50, 100, chunkSize); + // metrics.add(q075); 75~100% -> new PoolChunkList(this, q100, 75, 100, chunkSize); + // metrics.add(q100); 100% -> new PoolChunkList(this, null, 100, Integer.MAX_VALUE, chunkSize); + final StringBuilder builder = new StringBuilder("75~100%".length()); + int minUsage = metric.minUsage(); + if (minUsage <= 1) { + minUsage = 0; + } + builder.append(minUsage); + int maxUsage = metric.maxUsage(); + if (maxUsage != minUsage) { + builder.append('~').append(maxUsage); + } + builder.append('%'); + return builder.toString(); + } + + private void metricsOfPoolChunkListMetric(final MeterRegistry registry, + final PoolChunkListMetric poolChunkListMetrics, + final String poolArenaIndex, + final String poolArenaType, + final String poolChunkListType) { + Gauge.builder("netty.pooled.arena.chunk.list.capacity", poolChunkListMetrics, metric -> { + long total = 0; + for (PoolChunkMetric poolChunkMetric : poolChunkListMetrics) { + total += poolChunkMetric.chunkSize(); + } + return total; + }) + .tags("pool_arena_type", poolArenaType, "pool_arena_index", poolArenaIndex, "pool_chunk_list_type", poolChunkListType) + .description("The total capacity in bytes of the chunks in the list") + .baseUnit(BYTES_UNIT) + .register(registry); + Gauge.builder("netty.pooled.arena.chunk.list.free", poolChunkListMetrics, metric -> { + long total = 0; + for (PoolChunkMetric poolChunkMetric : poolChunkListMetrics) { + total += poolChunkMetric.freeBytes(); + } + return total; + }) + .tags("pool_arena_type", poolArenaType, "pool_arena_index", poolArenaIndex, "pool_chunk_list_type", poolChunkListType) + .description("The total free bytes of the chunks in the list") + .baseUnit(BYTES_UNIT) + .register(registry); + + Gauge.builder("netty.pooled.arena.chunk.list.count", poolChunkListMetrics, metric -> { + long total = 0; + for (PoolChunkMetric poolChunkMetric : poolChunkListMetrics) { + total++; + } + return total; + }) + .tags("pool_arena_type", poolArenaType, "pool_arena_index", poolArenaIndex, "pool_chunk_list_type", poolChunkListType) + .description("The number of chunks in the list") + .register(registry); + } + +} \ No newline at end of file diff --git a/artemis-server/src/main/resources/schema/artemis-configuration.xsd b/artemis-server/src/main/resources/schema/artemis-configuration.xsd index c9e44e64ca..ad612d2f24 100644 --- a/artemis-server/src/main/resources/schema/artemis-configuration.xsd +++ b/artemis-server/src/main/resources/schema/artemis-configuration.xsd @@ -1187,6 +1187,14 @@ + + + + whether or not to report Netty pool metrics + + + + diff --git a/artemis-server/src/test/java/org/apache/activemq/artemis/core/config/impl/FileConfigurationTest.java b/artemis-server/src/test/java/org/apache/activemq/artemis/core/config/impl/FileConfigurationTest.java index ea1b4d8890..7878098e72 100644 --- a/artemis-server/src/test/java/org/apache/activemq/artemis/core/config/impl/FileConfigurationTest.java +++ b/artemis-server/src/test/java/org/apache/activemq/artemis/core/config/impl/FileConfigurationTest.java @@ -494,6 +494,7 @@ public class FileConfigurationTest extends ConfigurationImplTest { assertFalse(metricsConfiguration.isJvmMemory()); assertTrue(metricsConfiguration.isJvmGc()); assertTrue(metricsConfiguration.isJvmThread()); + assertTrue(metricsConfiguration.isNettyPool()); } private void verifyAddresses() { @@ -797,6 +798,7 @@ public class FileConfigurationTest extends ConfigurationImplTest { assertTrue(metricsConfiguration.isJvmMemory()); assertTrue(metricsConfiguration.isJvmGc()); assertTrue(metricsConfiguration.isJvmThread()); + assertTrue(metricsConfiguration.isNettyPool()); ActiveMQMetricsPlugin metricPlugin = metricsConfiguration.getPlugin(); assertTrue(metricPlugin instanceof FakeMetricPlugin); diff --git a/artemis-server/src/test/resources/ConfigurationTest-full-config.xml b/artemis-server/src/test/resources/ConfigurationTest-full-config.xml index fa41ef390e..a72459c5bd 100644 --- a/artemis-server/src/test/resources/ConfigurationTest-full-config.xml +++ b/artemis-server/src/test/resources/ConfigurationTest-full-config.xml @@ -326,6 +326,7 @@ false true true + true diff --git a/artemis-server/src/test/resources/ConfigurationTest-xinclude-config.xml b/artemis-server/src/test/resources/ConfigurationTest-xinclude-config.xml index ed25c0cb95..4da00b70d8 100644 --- a/artemis-server/src/test/resources/ConfigurationTest-xinclude-config.xml +++ b/artemis-server/src/test/resources/ConfigurationTest-xinclude-config.xml @@ -210,6 +210,7 @@ false true true + true diff --git a/artemis-server/src/test/resources/metrics.xml b/artemis-server/src/test/resources/metrics.xml index 57a15a49f3..f4167ded9f 100644 --- a/artemis-server/src/test/resources/metrics.xml +++ b/artemis-server/src/test/resources/metrics.xml @@ -23,6 +23,7 @@ true true true + true diff --git a/docs/user-manual/en/metrics.md b/docs/user-manual/en/metrics.md index 3cdff631e7..a05c395091 100644 --- a/docs/user-manual/en/metrics.md +++ b/docs/user-manual/en/metrics.md @@ -82,8 +82,9 @@ message count). However, these metrics can be deduced by aggregating the lower level metrics (e.g. aggregate the message.count metrics from all queues to get the total). -JVM memory metrics are also exported by default and GC and thread metrics can -be configured +JVM memory metrics are also exported by default and GC, thread metrics, and +[Netty](https://netty.io/4.1/api/io/netty/buffer/PooledByteBufAllocatorMetric.html) +metrics can be configured ## Configuration @@ -100,6 +101,7 @@ JVM metrics: true true true + true ```