diff --git a/core/src/main/java/com/linecorp/armeria/common/CommonPools.java b/core/src/main/java/com/linecorp/armeria/common/CommonPools.java index e6302151c48..fb3d175c8cf 100644 --- a/core/src/main/java/com/linecorp/armeria/common/CommonPools.java +++ b/core/src/main/java/com/linecorp/armeria/common/CommonPools.java @@ -22,6 +22,8 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.google.common.annotations.VisibleForTesting; + import com.linecorp.armeria.client.ClientFactoryBuilder; import com.linecorp.armeria.common.metric.MeterIdPrefix; import com.linecorp.armeria.common.metric.MoreMeterBinders; @@ -29,6 +31,7 @@ import com.linecorp.armeria.common.util.EventLoopGroups; import com.linecorp.armeria.server.ServerBuilder; +import io.micrometer.core.instrument.binder.netty4.NettyEventExecutorMetrics; import io.netty.channel.EventLoopGroup; /** @@ -45,11 +48,7 @@ public final class CommonPools { EventLoopGroups.newEventLoopGroup(Flags.numCommonWorkers(), "armeria-common-worker", true); static { - // Bind EventLoopMetrics for the common worker group. - MoreMeterBinders - .eventLoopMetrics(WORKER_GROUP, new MeterIdPrefix("armeria.netty.common")) - .bindTo(Flags.meterRegistry()); - + bindEventLoopMetricsForWorkerGroup(WORKER_GROUP); try { final Class aClass = Class.forName("reactor.core.scheduler.Schedulers", true, CommonPools.class.getClassLoader()); @@ -65,6 +64,18 @@ public final class CommonPools { } } + @VisibleForTesting + static void bindEventLoopMetricsForWorkerGroup(EventLoopGroup evGroup) { + // Bind EventLoopMetrics for the common worker group. + MoreMeterBinders + .eventLoopMetrics(evGroup, new MeterIdPrefix("armeria.netty.common")) + .bindTo(Flags.meterRegistry()); + // Bind the common event loop metrics emitted automatically by micrometer. + // These metrics intentionally duplicate those emitted by EventLoopMetrics to preserve + // backward compatibility. + new NettyEventExecutorMetrics(evGroup).bindTo(Flags.meterRegistry()); + } + /** * Returns the default common blocking task {@link BlockingTaskExecutor} which is used for * potentially long-running tasks which may block I/O threads. diff --git a/core/src/main/java/com/linecorp/armeria/common/metric/EventLoopMetrics.java b/core/src/main/java/com/linecorp/armeria/common/metric/EventLoopMetrics.java index 760486b7b81..24af2ce7742 100644 --- a/core/src/main/java/com/linecorp/armeria/common/metric/EventLoopMetrics.java +++ b/core/src/main/java/com/linecorp/armeria/common/metric/EventLoopMetrics.java @@ -98,6 +98,7 @@ void remove(EventLoopGroup eventLoopGroup) { return result; } + @Deprecated // use the same metric with micrometer namespace instead double pendingTasks() { int result = 0; for (EventLoopGroup group : registry) { diff --git a/core/src/test/java/com/linecorp/armeria/common/CommonPoolsTest.java b/core/src/test/java/com/linecorp/armeria/common/CommonPoolsTest.java new file mode 100644 index 00000000000..8db68bee276 --- /dev/null +++ b/core/src/test/java/com/linecorp/armeria/common/CommonPoolsTest.java @@ -0,0 +1,50 @@ +/* + * Copyright 2025 LINE Corporation + * + * LINE Corporation 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: + * + * https://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 com.linecorp.armeria.common; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; + +import java.util.Map; + +import org.junit.jupiter.api.Test; + +import com.linecorp.armeria.common.metric.MoreMeters; +import com.linecorp.armeria.common.util.EventLoopGroups; + +import io.micrometer.core.instrument.binder.netty4.NettyMeters; +import io.netty.channel.EventLoopGroup; + +public class CommonPoolsTest { + @Test + public void testEventLoopMetricsBinding() throws Exception { + final EventLoopGroup testGroup = EventLoopGroups.newEventLoopGroup(1); + + try { + CommonPools.bindEventLoopMetricsForWorkerGroup(testGroup); + + // verify that registry contains the newly added metrics + final Map registeredMeters = MoreMeters.measureAll(Flags.meterRegistry()); + assertThat(registeredMeters.keySet() + .stream() + .anyMatch(key -> key.startsWith( + NettyMeters.EVENT_EXECUTOR_TASKS_PENDING.getName()))) + .isTrue(); + } finally { + testGroup.shutdownNow(); + } + } +}