Micrometer: [FeatureRequest] Netty Support

Created on 27 Mar 2018  路  2Comments  路  Source: micrometer-metrics/micrometer

It will be nice to see metrics added around Netty. For example,

  1. Number of threads in the eventloop
  2. Processing time in the eventloop
  3. Throughput
enhancement help wanted

Most helpful comment

Hi, I've just implemented for https://github.com/apache/activemq-artemis/ a Netty pooled allocator MeterBinder: right now I'm pushing it in a PR for artemis but I would be more then happy to send a PR here as well...anyone interested? :)

All 2 comments

I recently added the following netty-micrometer glue code to a spring boot project to monitor memory usage by the default PooledByteBufAllocator.
Although not in your list, this may be useful to some...


lots of code hidden...

package x.y.z;

import io.micrometer.core.instrument.Metrics;
import io.micrometer.core.instrument.Tags;
import io.netty.buffer.*;
import org.springframework.context.annotation.Configuration;

import javax.annotation.PostConstruct;

@Configuration
public class NettyMetricsConfig {
    private static final String NETTY = "netty";
    private static final String ALLOC = "alloc";
    private static final String POOLED = "pooled";
    private static final String UNPOOLED = "unpooled";

    private static final String MEMORY = "memory";
    private static final String DIRECT = "direct";
    private static final String HEAP = "heap";

    private static final String ARENA = "arena";

    private static final String CHUNK = "chunk";

    private static final String THREAD = "thread";
    private static final String LOCAL = "local";

    private static final String CACHE = "cache";
    private static final String SIZE = "size";
    private static final String TINY = "tiny";
    private static final String SMALL = "small";
    private static final String NORMAL = "normal";
    private static final String HUGE = "huge";

    private static final String SUBPAGE = "subpage";
    private static final String CHUNKLIST = "chunklist";
    private static final String NUMBER = "number";

    private static final String USED = "used";
    private static final String COUNT = "count";

    private static final String ALLOCATION = "allocation";
    private static final String DEALLOCATION = "deallocation";
    private static final String ACTIVE = "active";
    private static final String BYTE = "byte";

    private static final String ELEMENT = "element";
    private static final String MAX = "max";
    private static final String MIN = "min";
    private static final String AVAILABLE = "available";
    private static final String PAGE = "page";
    private static final String USAGE = "usage";

    @PostConstruct
    public void configureNettyMetrics() {
        PooledByteBufAllocatorMetric pooledMetric = PooledByteBufAllocator.DEFAULT.metric();

        Tags pooled = Tags.of(ALLOC, POOLED);

        Metrics.gauge(dot(NETTY, ALLOC, MEMORY, USED), pooled.and(MEMORY, DIRECT), pooledMetric, ByteBufAllocatorMetric::usedDirectMemory);
        Metrics.gauge(dot(NETTY, ALLOC, MEMORY, USED), pooled.and(MEMORY, HEAP), pooledMetric, ByteBufAllocatorMetric::usedHeapMemory);

        Metrics.gauge(dot(NETTY, ALLOC, ARENA, COUNT), pooled.and(MEMORY, DIRECT), pooledMetric, PooledByteBufAllocatorMetric::numDirectArenas);
        Metrics.gauge(dot(NETTY, ALLOC, ARENA, COUNT), pooled.and(MEMORY, HEAP), pooledMetric, PooledByteBufAllocatorMetric::numHeapArenas);
        Metrics.gauge(dot(NETTY, ALLOC, THREAD, LOCAL, CACHE, COUNT), pooled, pooledMetric, PooledByteBufAllocatorMetric::numThreadLocalCaches);

        Metrics.gauge(dot(NETTY, ALLOC, CACHE, SIZE), pooled.and(CACHE, TINY), pooledMetric, PooledByteBufAllocatorMetric::tinyCacheSize);
        Metrics.gauge(dot(NETTY, ALLOC, CACHE, SIZE), pooled.and(CACHE, SMALL), pooledMetric, PooledByteBufAllocatorMetric::smallCacheSize);
        Metrics.gauge(dot(NETTY, ALLOC, CACHE, SIZE), pooled.and(CACHE, NORMAL), pooledMetric, PooledByteBufAllocatorMetric::normalCacheSize);
        Metrics.gauge(dot(NETTY, ALLOC, CHUNK, SIZE), pooled, pooledMetric, PooledByteBufAllocatorMetric::chunkSize);

        for (int i = 0; i < pooledMetric.directArenas().size(); i++) {
            Tags tags = Tags.of(MEMORY, DIRECT)
                    .and(dot(ARENA, NUMBER), Integer.toString(i));

            meterPoolArena(tags, pooledMetric.directArenas().get(i));
        }

        for (int i = 0; i < pooledMetric.heapArenas().size(); i++) {
            Tags tags = Tags.of(MEMORY, HEAP)
                    .and(dot(ARENA, NUMBER), Integer.toString(i));

            meterPoolArena(tags, pooledMetric.heapArenas().get(i));
        }

        ByteBufAllocatorMetric unpooledMetric = UnpooledByteBufAllocator.DEFAULT.metric();
        Tags unpooled = Tags.of(ALLOC, UNPOOLED);

        Metrics.gauge(dot(NETTY, ALLOC, MEMORY, USED), unpooled.and(MEMORY, DIRECT), unpooledMetric, ByteBufAllocatorMetric::usedDirectMemory);
        Metrics.gauge(dot(NETTY, ALLOC, MEMORY, USED), unpooled.and(MEMORY, HEAP), unpooledMetric, ByteBufAllocatorMetric::usedHeapMemory);
    }

    private void meterPoolArena(Tags tags, PoolArenaMetric pam) {
        Metrics.gauge(dot(NETTY, ALLOC, ARENA, THREAD, CACHE, COUNT), tags, pam, PoolArenaMetric::numThreadCaches);
        Metrics.gauge(dot(NETTY, ALLOC, ARENA, SUBPAGE, COUNT), tags.and(SUBPAGE, TINY), pam, PoolArenaMetric::numTinySubpages);
        Metrics.gauge(dot(NETTY, ALLOC, ARENA, SUBPAGE, COUNT), tags.and(SUBPAGE, SMALL), pam, PoolArenaMetric::numSmallSubpages);
        Metrics.gauge(dot(NETTY, ALLOC, ARENA, CHUNKLIST, COUNT), tags, pam, PoolArenaMetric::numChunkLists);

        Metrics.gauge(dot(NETTY, ALLOC, ARENA, ALLOCATION, COUNT), tags, pam, PoolArenaMetric::numAllocations);
        Metrics.gauge(dot(NETTY, ALLOC, ARENA, ALLOCATION, COUNT), tags.and(SIZE, TINY), pam, PoolArenaMetric::numTinyAllocations);
        Metrics.gauge(dot(NETTY, ALLOC, ARENA, ALLOCATION, COUNT), tags.and(SIZE, SMALL), pam, PoolArenaMetric::numSmallAllocations);
        Metrics.gauge(dot(NETTY, ALLOC, ARENA, ALLOCATION, COUNT), tags.and(SIZE, NORMAL), pam, PoolArenaMetric::numNormalAllocations);
        Metrics.gauge(dot(NETTY, ALLOC, ARENA, ALLOCATION, COUNT), tags.and(SIZE, HUGE), pam, PoolArenaMetric::numHugeAllocations);


        Metrics.gauge(dot(NETTY, ALLOC, ARENA, DEALLOCATION, COUNT), tags, pam, PoolArenaMetric::numDeallocations);
        Metrics.gauge(dot(NETTY, ALLOC, ARENA, DEALLOCATION, COUNT), tags.and(SIZE, TINY), pam, PoolArenaMetric::numTinyDeallocations);
        Metrics.gauge(dot(NETTY, ALLOC, ARENA, DEALLOCATION, COUNT), tags.and(SIZE, SMALL), pam, PoolArenaMetric::numSmallDeallocations);
        Metrics.gauge(dot(NETTY, ALLOC, ARENA, DEALLOCATION, COUNT), tags.and(SIZE, NORMAL), pam, PoolArenaMetric::numNormalDeallocations);
        Metrics.gauge(dot(NETTY, ALLOC, ARENA, DEALLOCATION, COUNT), tags.and(SIZE, HUGE), pam, PoolArenaMetric::numHugeDeallocations);

        Metrics.gauge(dot(NETTY, ALLOC, ARENA, ALLOCATION, ACTIVE, COUNT), tags, pam, PoolArenaMetric::numActiveAllocations);
        Metrics.gauge(dot(NETTY, ALLOC, ARENA, ALLOCATION, ACTIVE, COUNT), tags.and(SIZE, TINY), pam, PoolArenaMetric::numActiveTinyAllocations);
        Metrics.gauge(dot(NETTY, ALLOC, ARENA, ALLOCATION, ACTIVE, COUNT), tags.and(SIZE, SMALL), pam, PoolArenaMetric::numActiveSmallAllocations);
        Metrics.gauge(dot(NETTY, ALLOC, ARENA, ALLOCATION, ACTIVE, COUNT), tags.and(SIZE, NORMAL), pam, PoolArenaMetric::numActiveNormalAllocations);
        Metrics.gauge(dot(NETTY, ALLOC, ARENA, ALLOCATION, ACTIVE, COUNT), tags.and(SIZE, HUGE), pam, PoolArenaMetric::numActiveHugeAllocations);

        Metrics.gauge(dot(NETTY, ALLOC, ARENA, ACTIVE, BYTE, COUNT), tags, pam, PoolArenaMetric::numActiveHugeAllocations);

        for (int i = 0; i < pam.tinySubpages().size(); i++) {
            Tags tinySubpage = tags.and(SUBPAGE, TINY)
                    .and(dot(SUBPAGE, NUMBER), Integer.toString(i));

            meterSubpage(tinySubpage, pam.tinySubpages().get(i));
        }

        for (int i = 0; i < pam.smallSubpages().size(); i++) {
            Tags tinySubpage = tags.and(SUBPAGE, SMALL)
                    .and(dot(SUBPAGE, NUMBER), Integer.toString(i));

            meterSubpage(tinySubpage, pam.smallSubpages().get(i));
        }

        for (int i = 0; i < pam.chunkLists().size(); i++) {
            Tags chunkList = tags.and(dot(CHUNKLIST, NUMBER), Integer.toString(i));

            meterChunkList(chunkList, pam.chunkLists().get(i));
        }
    }

    private void meterSubpage(Tags tags, PoolSubpageMetric psm) {
        Metrics.gauge(dot(NETTY, ALLOC, ARENA, SUBPAGE, ELEMENT, MAX), tags, psm, PoolSubpageMetric::maxNumElements);
        Metrics.gauge(dot(NETTY, ALLOC, ARENA, SUBPAGE, AVAILABLE, COUNT), tags, psm, PoolSubpageMetric::numAvailable);
        Metrics.gauge(dot(NETTY, ALLOC, ARENA, SUBPAGE, ELEMENT, SIZE), tags, psm, PoolSubpageMetric::elementSize);
        Metrics.gauge(dot(NETTY, ALLOC, ARENA, SUBPAGE, PAGE, SIZE), tags, psm, PoolSubpageMetric::pageSize);
    }

    private void meterChunkList(Tags tags, PoolChunkListMetric pclm) {
        Metrics.gauge(dot(NETTY, ALLOC, ARENA, CHUNKLIST, USAGE, MIN), tags, pclm, PoolChunkListMetric::minUsage);
        Metrics.gauge(dot(NETTY, ALLOC, ARENA, CHUNKLIST, USAGE, MAX), tags, pclm, PoolChunkListMetric::maxUsage);
    }

    private String dot(String... strings) {
        return String.join(".", strings);
    }
}

Hi, I've just implemented for https://github.com/apache/activemq-artemis/ a Netty pooled allocator MeterBinder: right now I'm pushing it in a PR for artemis but I would be more then happy to send a PR here as well...anyone interested? :)

Was this page helpful?
0 / 5 - 0 ratings