From 0aad99aa96b4269e9bc490e4388a353361d31852 Mon Sep 17 00:00:00 2001 From: weixiang Date: Mon, 30 Dec 2024 17:30:25 +0800 Subject: [PATCH 1/2] Add Undertow 2.1.7.final+ worker thread pool metrics. --- CHANGES.md | 1 + .../pom.xml | 9 +- .../XnioWorkerConstructorInterceptor.java | 65 ++++++++++ ...dertowWorkerThreadPoolInstrumentation.java | 43 ++++--- .../XnioWorkerConstructorInstrumentation.java | 78 ++++++++++++ .../pool/util/XnioWorkerTaskPoolAccessor.java | 117 ++++++++++++++++++ .../src/main/resources/skywalking-plugin.def | 3 +- .../config/expectedData.yaml | 10 +- .../pom.xml | 2 +- 9 files changed, 305 insertions(+), 23 deletions(-) create mode 100644 apm-sniffer/apm-sdk-plugin/undertow-worker-thread-pool-plugin/src/main/java/org/apache/skywalking/apm/plugin/undertow/worker/thread/pool/XnioWorkerConstructorInterceptor.java create mode 100644 apm-sniffer/apm-sdk-plugin/undertow-worker-thread-pool-plugin/src/main/java/org/apache/skywalking/apm/plugin/undertow/worker/thread/pool/define/XnioWorkerConstructorInstrumentation.java create mode 100644 apm-sniffer/apm-sdk-plugin/undertow-worker-thread-pool-plugin/src/main/java/org/apache/skywalking/apm/plugin/undertow/worker/thread/pool/util/XnioWorkerTaskPoolAccessor.java diff --git a/CHANGES.md b/CHANGES.md index 8a74479321..007f7ca21a 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -26,6 +26,7 @@ Release Notes. * Change context and parent entry span propagation mechanism from gRPC ThreadLocal context to SkyWalking native dynamic field as new propagation mechanism, to better support async scenarios. * Add Caffeine plugin as optional. +* Add Undertow 2.1.7.final+ worker thread pool metrics. All issues and pull requests are [here](https://github.com/apache/skywalking/milestone/222?closed=1) diff --git a/apm-sniffer/apm-sdk-plugin/undertow-worker-thread-pool-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/undertow-worker-thread-pool-plugin/pom.xml index 06470ce5d3..d1c1359a35 100644 --- a/apm-sniffer/apm-sdk-plugin/undertow-worker-thread-pool-plugin/pom.xml +++ b/apm-sniffer/apm-sdk-plugin/undertow-worker-thread-pool-plugin/pom.xml @@ -29,5 +29,12 @@ undertow-worker-thread-pool-plugin http://maven.apache.org - + + + org.jboss.xnio + xnio-api + 3.8.4.Final + provided + + \ No newline at end of file diff --git a/apm-sniffer/apm-sdk-plugin/undertow-worker-thread-pool-plugin/src/main/java/org/apache/skywalking/apm/plugin/undertow/worker/thread/pool/XnioWorkerConstructorInterceptor.java b/apm-sniffer/apm-sdk-plugin/undertow-worker-thread-pool-plugin/src/main/java/org/apache/skywalking/apm/plugin/undertow/worker/thread/pool/XnioWorkerConstructorInterceptor.java new file mode 100644 index 0000000000..88cecc5ca1 --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/undertow-worker-thread-pool-plugin/src/main/java/org/apache/skywalking/apm/plugin/undertow/worker/thread/pool/XnioWorkerConstructorInterceptor.java @@ -0,0 +1,65 @@ +/* + * 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.skywalking.apm.plugin.undertow.worker.thread.pool; + +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.function.Function; +import java.util.function.Supplier; +import org.apache.skywalking.apm.agent.core.meter.MeterFactory; +import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance; +import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceConstructorInterceptor; +import org.apache.skywalking.apm.plugin.undertow.worker.thread.pool.util.XnioWorkerTaskPoolAccessor; +import org.xnio.XnioWorker; + +public class XnioWorkerConstructorInterceptor implements InstanceConstructorInterceptor { + + private static final String THREAD_POOL_NAME = "undertow_worker_pool"; + + private static final Map>> METRIC_MAP = new HashMap>>() {{ + put("core_pool_size", (XnioWorkerTaskPoolAccessor threadPoolExecutor) -> () -> (double) threadPoolExecutor.getCorePoolSize()); + put("max_pool_size", (XnioWorkerTaskPoolAccessor threadPoolExecutor) -> () -> (double) threadPoolExecutor.getMaximumPoolSize()); + put("pool_size", (XnioWorkerTaskPoolAccessor threadPoolExecutor) -> () -> (double) threadPoolExecutor.getPoolSize()); + put("queue_size", (XnioWorkerTaskPoolAccessor threadPoolExecutor) -> () -> (double) threadPoolExecutor.getQueueSize()); + put("active_size", (XnioWorkerTaskPoolAccessor threadPoolExecutor) -> () -> (double) threadPoolExecutor.getActiveCount()); + }}; + + @Override + public void onConstruct(EnhancedInstance objInst, Object[] allArguments) throws Throwable { + buildThreadPoolMeterMetric(new XnioWorkerTaskPoolAccessor((XnioWorker) objInst)); + } + + private void buildThreadPoolMeterMetric(XnioWorkerTaskPoolAccessor xnioWorkerTaskPoolAccessor) { + String threadPoolMeterName = "thread_pool"; + String poolNameTag = "pool_name"; + String metricTypeTag = "metric_type"; + METRIC_MAP.forEach((key, value) -> { + if (Objects.equals(key, "pool_size")) { + if (xnioWorkerTaskPoolAccessor.isContainsGetPoolSizeMethod()) { + MeterFactory.gauge(threadPoolMeterName, value.apply(xnioWorkerTaskPoolAccessor)) + .tag(poolNameTag, THREAD_POOL_NAME).tag(metricTypeTag, key).build(); + } + } else { + MeterFactory.gauge(threadPoolMeterName, value.apply(xnioWorkerTaskPoolAccessor)) + .tag(poolNameTag, THREAD_POOL_NAME).tag(metricTypeTag, key).build(); + } + }); + } +} diff --git a/apm-sniffer/apm-sdk-plugin/undertow-worker-thread-pool-plugin/src/main/java/org/apache/skywalking/apm/plugin/undertow/worker/thread/pool/define/UndertowWorkerThreadPoolInstrumentation.java b/apm-sniffer/apm-sdk-plugin/undertow-worker-thread-pool-plugin/src/main/java/org/apache/skywalking/apm/plugin/undertow/worker/thread/pool/define/UndertowWorkerThreadPoolInstrumentation.java index edca92a998..ce827e349c 100644 --- a/apm-sniffer/apm-sdk-plugin/undertow-worker-thread-pool-plugin/src/main/java/org/apache/skywalking/apm/plugin/undertow/worker/thread/pool/define/UndertowWorkerThreadPoolInstrumentation.java +++ b/apm-sniffer/apm-sdk-plugin/undertow-worker-thread-pool-plugin/src/main/java/org/apache/skywalking/apm/plugin/undertow/worker/thread/pool/define/UndertowWorkerThreadPoolInstrumentation.java @@ -19,43 +19,56 @@ package org.apache.skywalking.apm.plugin.undertow.worker.thread.pool.define; import static net.bytebuddy.matcher.ElementMatchers.any; -import static org.apache.skywalking.apm.agent.core.plugin.match.HierarchyMatch.byHierarchyMatch; -import static org.apache.skywalking.apm.agent.core.plugin.match.PrefixMatch.nameStartsWith; +import static net.bytebuddy.matcher.ElementMatchers.named; +import static org.apache.skywalking.apm.agent.core.plugin.match.NameMatch.byName; +import java.util.Collections; +import java.util.List; import net.bytebuddy.description.method.MethodDescription; import net.bytebuddy.matcher.ElementMatcher; +import org.apache.skywalking.apm.agent.core.plugin.WitnessMethod; import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint; import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint; import org.apache.skywalking.apm.agent.core.plugin.interceptor.StaticMethodsInterceptPoint; import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassEnhancePluginDefine; import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch; -import org.apache.skywalking.apm.agent.core.plugin.match.logical.LogicalMatchOperation; +/** + * ThreadPoolExecutor implemented xnio worker task pool before 3.6.0 + */ public class UndertowWorkerThreadPoolInstrumentation extends ClassEnhancePluginDefine { - private static final String THREAD_POOL_EXECUTOR_CLASS = "java.util.concurrent.ThreadPoolExecutor"; + private static final String THREAD_POOL_EXECUTOR_CLASS = "org.xnio.XnioWorker$TaskPool"; private static final String UNDERTOW_WORKER_THREAD_POOL_INTERCEPT = "org.apache.skywalking.apm.plugin.undertow.worker.thread.pool.UndertowWorkerThreadPoolConstructorIntercept"; + @Override + protected List witnessMethods() { + return Collections.singletonList(new WitnessMethod( + "org.xnio.XnioWorker$TaskPool", + named("terminated") + )); + } + @Override protected ClassMatch enhanceClass() { - return LogicalMatchOperation.and(nameStartsWith("org.xnio"), byHierarchyMatch(THREAD_POOL_EXECUTOR_CLASS)); + return byName(THREAD_POOL_EXECUTOR_CLASS); } @Override public ConstructorInterceptPoint[] getConstructorsInterceptPoints() { - return new ConstructorInterceptPoint[]{ - new ConstructorInterceptPoint() { - @Override - public ElementMatcher getConstructorMatcher() { - return any(); - } + return new ConstructorInterceptPoint[] { + new ConstructorInterceptPoint() { + @Override + public ElementMatcher getConstructorMatcher() { + return any(); + } - @Override - public String getConstructorInterceptor() { - return UNDERTOW_WORKER_THREAD_POOL_INTERCEPT; - } + @Override + public String getConstructorInterceptor() { + return UNDERTOW_WORKER_THREAD_POOL_INTERCEPT; } + } }; } diff --git a/apm-sniffer/apm-sdk-plugin/undertow-worker-thread-pool-plugin/src/main/java/org/apache/skywalking/apm/plugin/undertow/worker/thread/pool/define/XnioWorkerConstructorInstrumentation.java b/apm-sniffer/apm-sdk-plugin/undertow-worker-thread-pool-plugin/src/main/java/org/apache/skywalking/apm/plugin/undertow/worker/thread/pool/define/XnioWorkerConstructorInstrumentation.java new file mode 100644 index 0000000000..5a5dc803a6 --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/undertow-worker-thread-pool-plugin/src/main/java/org/apache/skywalking/apm/plugin/undertow/worker/thread/pool/define/XnioWorkerConstructorInstrumentation.java @@ -0,0 +1,78 @@ +/* + * 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.skywalking.apm.plugin.undertow.worker.thread.pool.define; + +import net.bytebuddy.description.method.MethodDescription; +import net.bytebuddy.matcher.ElementMatcher; +import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint; +import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint; +import org.apache.skywalking.apm.agent.core.plugin.interceptor.StaticMethodsInterceptPoint; +import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassEnhancePluginDefine; +import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch; + +import static net.bytebuddy.matcher.ElementMatchers.any; +import static org.apache.skywalking.apm.agent.core.plugin.match.NameMatch.byName; + +/** + * xnio task pool new implementation since 3.6.0 + * + */ +public class XnioWorkerConstructorInstrumentation extends ClassEnhancePluginDefine { + + private static final String XNIO_WORKER_CLASS = "org.xnio.XnioWorker"; + + private static final String UNDERTOW_WORKER_THREAD_POOL_INTERCEPT = "org.apache.skywalking.apm.plugin.undertow.worker.thread.pool.XnioWorkerConstructorInterceptor"; + + @Override + protected String[] witnessClasses() { + return new String[] {"org.xnio.XnioWorker$EnhancedQueueExecutorTaskPool"}; + } + + @Override + protected ClassMatch enhanceClass() { + return byName(XNIO_WORKER_CLASS); + } + + @Override + public ConstructorInterceptPoint[] getConstructorsInterceptPoints() { + return new ConstructorInterceptPoint[] { + new ConstructorInterceptPoint() { + @Override + public ElementMatcher getConstructorMatcher() { + return any(); + } + + @Override + public String getConstructorInterceptor() { + return UNDERTOW_WORKER_THREAD_POOL_INTERCEPT; + } + } + }; + } + + @Override + public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() { + return new InstanceMethodsInterceptPoint[0]; + } + + @Override + public StaticMethodsInterceptPoint[] getStaticMethodsInterceptPoints() { + return new StaticMethodsInterceptPoint[0]; + } +} diff --git a/apm-sniffer/apm-sdk-plugin/undertow-worker-thread-pool-plugin/src/main/java/org/apache/skywalking/apm/plugin/undertow/worker/thread/pool/util/XnioWorkerTaskPoolAccessor.java b/apm-sniffer/apm-sdk-plugin/undertow-worker-thread-pool-plugin/src/main/java/org/apache/skywalking/apm/plugin/undertow/worker/thread/pool/util/XnioWorkerTaskPoolAccessor.java new file mode 100644 index 0000000000..2284115437 --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/undertow-worker-thread-pool-plugin/src/main/java/org/apache/skywalking/apm/plugin/undertow/worker/thread/pool/util/XnioWorkerTaskPoolAccessor.java @@ -0,0 +1,117 @@ +/* + * 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.skywalking.apm.plugin.undertow.worker.thread.pool.util; + +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import lombok.Getter; +import org.xnio.XnioWorker; + +public class XnioWorkerTaskPoolAccessor { + + private final Object taskPool; + @Getter + private boolean containsGetPoolSizeMethod; + + private Method getCorePoolSizeMethod; + private Method getMaximumPoolSizeMethod; + private Method getActiveCountMethod; + private Method getPoolSizeMethod; + private Method getQueueSizeMethod; + + public XnioWorkerTaskPoolAccessor(final XnioWorker worker) throws NoSuchFieldException, IllegalAccessException { + Field field = worker.getClass().getSuperclass().getDeclaredField("taskPool"); + field.setAccessible(true); + this.taskPool = field.get(worker); + + try { + getCorePoolSizeMethod = taskPool.getClass().getDeclaredMethod("getCorePoolSize"); + getCorePoolSizeMethod.setAccessible(true); + } catch (NoSuchMethodException e) { + // ignore + } + try { + getMaximumPoolSizeMethod = taskPool.getClass().getDeclaredMethod("getMaximumPoolSize"); + getMaximumPoolSizeMethod.setAccessible(true); + } catch (NoSuchMethodException e) { + // ignore + } + try { + getActiveCountMethod = taskPool.getClass().getDeclaredMethod("getActiveCount"); + getActiveCountMethod.setAccessible(true); + } catch (NoSuchMethodException e) { + // ignore + } + try { + // getPoolSize add since 3.8.0 + getPoolSizeMethod = taskPool.getClass().getDeclaredMethod("getPoolSize"); + getPoolSizeMethod.setAccessible(true); + containsGetPoolSizeMethod = true; + } catch (NoSuchMethodException e) { + containsGetPoolSizeMethod = false; + } + try { + getQueueSizeMethod = taskPool.getClass().getDeclaredMethod("getQueueSize"); + getQueueSizeMethod.setAccessible(true); + } catch (NoSuchMethodException e) { + // ignore + } + } + + public int getCorePoolSize() { + try { + return (int) getCorePoolSizeMethod.invoke(taskPool); + } catch (IllegalAccessException | InvocationTargetException e) { + throw new RuntimeException(e); + } + } + + public int getMaximumPoolSize() { + try { + return (int) getMaximumPoolSizeMethod.invoke(taskPool); + } catch (IllegalAccessException | InvocationTargetException e) { + throw new RuntimeException(e); + } + } + + public int getActiveCount() { + try { + return (int) getActiveCountMethod.invoke(taskPool); + } catch (IllegalAccessException | InvocationTargetException e) { + throw new RuntimeException(e); + } + } + + public int getPoolSize() { + try { + return (int) getPoolSizeMethod.invoke(taskPool); + } catch (IllegalAccessException | InvocationTargetException e) { + throw new RuntimeException(e); + } + } + + public int getQueueSize() { + try { + return (int) getQueueSizeMethod.invoke(taskPool); + } catch (IllegalAccessException | InvocationTargetException e) { + throw new RuntimeException(e); + } + } +} diff --git a/apm-sniffer/apm-sdk-plugin/undertow-worker-thread-pool-plugin/src/main/resources/skywalking-plugin.def b/apm-sniffer/apm-sdk-plugin/undertow-worker-thread-pool-plugin/src/main/resources/skywalking-plugin.def index 22837a7aad..8ff6aacdbd 100644 --- a/apm-sniffer/apm-sdk-plugin/undertow-worker-thread-pool-plugin/src/main/resources/skywalking-plugin.def +++ b/apm-sniffer/apm-sdk-plugin/undertow-worker-thread-pool-plugin/src/main/resources/skywalking-plugin.def @@ -14,4 +14,5 @@ # See the License for the specific language governing permissions and # limitations under the License. -undertow-worker-thread-pool=org.apache.skywalking.apm.plugin.undertow.worker.thread.pool.define.UndertowWorkerThreadPoolInstrumentation \ No newline at end of file +undertow-worker-thread-pool=org.apache.skywalking.apm.plugin.undertow.worker.thread.pool.define.UndertowWorkerThreadPoolInstrumentation +undertow-worker-thread-pool=org.apache.skywalking.apm.plugin.undertow.worker.thread.pool.define.XnioWorkerConstructorInstrumentation \ No newline at end of file diff --git a/test/plugin/scenarios/undertow-worker-thread-pool-scenario/config/expectedData.yaml b/test/plugin/scenarios/undertow-worker-thread-pool-scenario/config/expectedData.yaml index 424a39aee8..ba30823ec1 100644 --- a/test/plugin/scenarios/undertow-worker-thread-pool-scenario/config/expectedData.yaml +++ b/test/plugin/scenarios/undertow-worker-thread-pool-scenario/config/expectedData.yaml @@ -22,29 +22,29 @@ meterItems: tags: - {name: metric_type, value: core_pool_size} - {name: pool_name, value: undertow_worker_pool} - singleValue: ge 1 + singleValue: ge -1 - meterId: name: thread_pool tags: - {name: metric_type, value: max_pool_size} - {name: pool_name, value: undertow_worker_pool} - singleValue: ge 1 + singleValue: ge -1 - meterId: name: thread_pool tags: - {name: metric_type, value: pool_size} - {name: pool_name, value: undertow_worker_pool} - singleValue: ge 0 + singleValue: ge -1 - meterId: name: thread_pool tags: - {name: metric_type, value: active_size} - {name: pool_name, value: undertow_worker_pool} - singleValue: ge 0 + singleValue: ge -1 - meterId: name: thread_pool tags: - {name: metric_type, value: queue_size} - {name: pool_name, value: undertow_worker_pool} - singleValue: ge 0 + singleValue: ge -1 diff --git a/test/plugin/scenarios/undertow-worker-thread-pool-scenario/pom.xml b/test/plugin/scenarios/undertow-worker-thread-pool-scenario/pom.xml index 7babe86a4e..ff3f3f582e 100644 --- a/test/plugin/scenarios/undertow-worker-thread-pool-scenario/pom.xml +++ b/test/plugin/scenarios/undertow-worker-thread-pool-scenario/pom.xml @@ -41,7 +41,7 @@ org.springframework.boot spring-boot-dependencies - ${spring-boot-version} + ${test.framework.version} pom import From 2e43ec4cf3726d31f38f20fb3e2a0498d83d85de Mon Sep 17 00:00:00 2001 From: weixiang Date: Mon, 30 Dec 2024 18:24:32 +0800 Subject: [PATCH 2/2] Fix java doc check. --- .../pool/define/XnioWorkerConstructorInstrumentation.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apm-sniffer/apm-sdk-plugin/undertow-worker-thread-pool-plugin/src/main/java/org/apache/skywalking/apm/plugin/undertow/worker/thread/pool/define/XnioWorkerConstructorInstrumentation.java b/apm-sniffer/apm-sdk-plugin/undertow-worker-thread-pool-plugin/src/main/java/org/apache/skywalking/apm/plugin/undertow/worker/thread/pool/define/XnioWorkerConstructorInstrumentation.java index 5a5dc803a6..2bc13dd20f 100644 --- a/apm-sniffer/apm-sdk-plugin/undertow-worker-thread-pool-plugin/src/main/java/org/apache/skywalking/apm/plugin/undertow/worker/thread/pool/define/XnioWorkerConstructorInstrumentation.java +++ b/apm-sniffer/apm-sdk-plugin/undertow-worker-thread-pool-plugin/src/main/java/org/apache/skywalking/apm/plugin/undertow/worker/thread/pool/define/XnioWorkerConstructorInstrumentation.java @@ -31,7 +31,7 @@ /** * xnio task pool new implementation since 3.6.0 - * + * https://github.com/xnio/xnio/commit/071800e0a85c9da9b88a976ac7ecb85760924dbf */ public class XnioWorkerConstructorInstrumentation extends ClassEnhancePluginDefine {