Skip to content

Commit b358267

Browse files
authored
Add Undertow 2.1.7.final+ worker thread pool metrics. (#744)
1 parent d53f04b commit b358267

File tree

9 files changed

+305
-23
lines changed

9 files changed

+305
-23
lines changed

CHANGES.md

+1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ Release Notes.
2626
* Change context and parent entry span propagation mechanism from gRPC ThreadLocal context to SkyWalking native dynamic
2727
field as new propagation mechanism, to better support async scenarios.
2828
* Add Caffeine plugin as optional.
29+
* Add Undertow 2.1.7.final+ worker thread pool metrics.
2930

3031
All issues and pull requests are [here](https://github.com/apache/skywalking/milestone/222?closed=1)
3132

apm-sniffer/apm-sdk-plugin/undertow-worker-thread-pool-plugin/pom.xml

+8-1
Original file line numberDiff line numberDiff line change
@@ -29,5 +29,12 @@
2929
<name>undertow-worker-thread-pool-plugin</name>
3030
<url>http://maven.apache.org</url>
3131

32-
32+
<dependencies>
33+
<dependency>
34+
<groupId>org.jboss.xnio</groupId>
35+
<artifactId>xnio-api</artifactId>
36+
<version>3.8.4.Final</version>
37+
<scope>provided</scope>
38+
</dependency>
39+
</dependencies>
3340
</project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*
17+
*/
18+
19+
package org.apache.skywalking.apm.plugin.undertow.worker.thread.pool;
20+
21+
import java.util.HashMap;
22+
import java.util.Map;
23+
import java.util.Objects;
24+
import java.util.function.Function;
25+
import java.util.function.Supplier;
26+
import org.apache.skywalking.apm.agent.core.meter.MeterFactory;
27+
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
28+
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceConstructorInterceptor;
29+
import org.apache.skywalking.apm.plugin.undertow.worker.thread.pool.util.XnioWorkerTaskPoolAccessor;
30+
import org.xnio.XnioWorker;
31+
32+
public class XnioWorkerConstructorInterceptor implements InstanceConstructorInterceptor {
33+
34+
private static final String THREAD_POOL_NAME = "undertow_worker_pool";
35+
36+
private static final Map<String, Function<XnioWorkerTaskPoolAccessor, Supplier<Double>>> METRIC_MAP = new HashMap<String, Function<XnioWorkerTaskPoolAccessor, Supplier<Double>>>() {{
37+
put("core_pool_size", (XnioWorkerTaskPoolAccessor threadPoolExecutor) -> () -> (double) threadPoolExecutor.getCorePoolSize());
38+
put("max_pool_size", (XnioWorkerTaskPoolAccessor threadPoolExecutor) -> () -> (double) threadPoolExecutor.getMaximumPoolSize());
39+
put("pool_size", (XnioWorkerTaskPoolAccessor threadPoolExecutor) -> () -> (double) threadPoolExecutor.getPoolSize());
40+
put("queue_size", (XnioWorkerTaskPoolAccessor threadPoolExecutor) -> () -> (double) threadPoolExecutor.getQueueSize());
41+
put("active_size", (XnioWorkerTaskPoolAccessor threadPoolExecutor) -> () -> (double) threadPoolExecutor.getActiveCount());
42+
}};
43+
44+
@Override
45+
public void onConstruct(EnhancedInstance objInst, Object[] allArguments) throws Throwable {
46+
buildThreadPoolMeterMetric(new XnioWorkerTaskPoolAccessor((XnioWorker) objInst));
47+
}
48+
49+
private void buildThreadPoolMeterMetric(XnioWorkerTaskPoolAccessor xnioWorkerTaskPoolAccessor) {
50+
String threadPoolMeterName = "thread_pool";
51+
String poolNameTag = "pool_name";
52+
String metricTypeTag = "metric_type";
53+
METRIC_MAP.forEach((key, value) -> {
54+
if (Objects.equals(key, "pool_size")) {
55+
if (xnioWorkerTaskPoolAccessor.isContainsGetPoolSizeMethod()) {
56+
MeterFactory.gauge(threadPoolMeterName, value.apply(xnioWorkerTaskPoolAccessor))
57+
.tag(poolNameTag, THREAD_POOL_NAME).tag(metricTypeTag, key).build();
58+
}
59+
} else {
60+
MeterFactory.gauge(threadPoolMeterName, value.apply(xnioWorkerTaskPoolAccessor))
61+
.tag(poolNameTag, THREAD_POOL_NAME).tag(metricTypeTag, key).build();
62+
}
63+
});
64+
}
65+
}

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

+28-15
Original file line numberDiff line numberDiff line change
@@ -19,43 +19,56 @@
1919
package org.apache.skywalking.apm.plugin.undertow.worker.thread.pool.define;
2020

2121
import static net.bytebuddy.matcher.ElementMatchers.any;
22-
import static org.apache.skywalking.apm.agent.core.plugin.match.HierarchyMatch.byHierarchyMatch;
23-
import static org.apache.skywalking.apm.agent.core.plugin.match.PrefixMatch.nameStartsWith;
22+
import static net.bytebuddy.matcher.ElementMatchers.named;
23+
import static org.apache.skywalking.apm.agent.core.plugin.match.NameMatch.byName;
2424

25+
import java.util.Collections;
26+
import java.util.List;
2527
import net.bytebuddy.description.method.MethodDescription;
2628
import net.bytebuddy.matcher.ElementMatcher;
29+
import org.apache.skywalking.apm.agent.core.plugin.WitnessMethod;
2730
import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
2831
import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
2932
import org.apache.skywalking.apm.agent.core.plugin.interceptor.StaticMethodsInterceptPoint;
3033
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassEnhancePluginDefine;
3134
import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
32-
import org.apache.skywalking.apm.agent.core.plugin.match.logical.LogicalMatchOperation;
3335

36+
/**
37+
* ThreadPoolExecutor implemented xnio worker task pool before 3.6.0
38+
*/
3439
public class UndertowWorkerThreadPoolInstrumentation extends ClassEnhancePluginDefine {
3540

36-
private static final String THREAD_POOL_EXECUTOR_CLASS = "java.util.concurrent.ThreadPoolExecutor";
41+
private static final String THREAD_POOL_EXECUTOR_CLASS = "org.xnio.XnioWorker$TaskPool";
3742

3843
private static final String UNDERTOW_WORKER_THREAD_POOL_INTERCEPT = "org.apache.skywalking.apm.plugin.undertow.worker.thread.pool.UndertowWorkerThreadPoolConstructorIntercept";
3944

45+
@Override
46+
protected List<WitnessMethod> witnessMethods() {
47+
return Collections.singletonList(new WitnessMethod(
48+
"org.xnio.XnioWorker$TaskPool",
49+
named("terminated")
50+
));
51+
}
52+
4053
@Override
4154
protected ClassMatch enhanceClass() {
42-
return LogicalMatchOperation.and(nameStartsWith("org.xnio"), byHierarchyMatch(THREAD_POOL_EXECUTOR_CLASS));
55+
return byName(THREAD_POOL_EXECUTOR_CLASS);
4356
}
4457

4558
@Override
4659
public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
47-
return new ConstructorInterceptPoint[]{
48-
new ConstructorInterceptPoint() {
49-
@Override
50-
public ElementMatcher<MethodDescription> getConstructorMatcher() {
51-
return any();
52-
}
60+
return new ConstructorInterceptPoint[] {
61+
new ConstructorInterceptPoint() {
62+
@Override
63+
public ElementMatcher<MethodDescription> getConstructorMatcher() {
64+
return any();
65+
}
5366

54-
@Override
55-
public String getConstructorInterceptor() {
56-
return UNDERTOW_WORKER_THREAD_POOL_INTERCEPT;
57-
}
67+
@Override
68+
public String getConstructorInterceptor() {
69+
return UNDERTOW_WORKER_THREAD_POOL_INTERCEPT;
5870
}
71+
}
5972
};
6073
}
6174

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*
17+
*/
18+
19+
package org.apache.skywalking.apm.plugin.undertow.worker.thread.pool.define;
20+
21+
import net.bytebuddy.description.method.MethodDescription;
22+
import net.bytebuddy.matcher.ElementMatcher;
23+
import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
24+
import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
25+
import org.apache.skywalking.apm.agent.core.plugin.interceptor.StaticMethodsInterceptPoint;
26+
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassEnhancePluginDefine;
27+
import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
28+
29+
import static net.bytebuddy.matcher.ElementMatchers.any;
30+
import static org.apache.skywalking.apm.agent.core.plugin.match.NameMatch.byName;
31+
32+
/**
33+
* xnio task pool new implementation since 3.6.0
34+
* https://github.com/xnio/xnio/commit/071800e0a85c9da9b88a976ac7ecb85760924dbf
35+
*/
36+
public class XnioWorkerConstructorInstrumentation extends ClassEnhancePluginDefine {
37+
38+
private static final String XNIO_WORKER_CLASS = "org.xnio.XnioWorker";
39+
40+
private static final String UNDERTOW_WORKER_THREAD_POOL_INTERCEPT = "org.apache.skywalking.apm.plugin.undertow.worker.thread.pool.XnioWorkerConstructorInterceptor";
41+
42+
@Override
43+
protected String[] witnessClasses() {
44+
return new String[] {"org.xnio.XnioWorker$EnhancedQueueExecutorTaskPool"};
45+
}
46+
47+
@Override
48+
protected ClassMatch enhanceClass() {
49+
return byName(XNIO_WORKER_CLASS);
50+
}
51+
52+
@Override
53+
public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
54+
return new ConstructorInterceptPoint[] {
55+
new ConstructorInterceptPoint() {
56+
@Override
57+
public ElementMatcher<MethodDescription> getConstructorMatcher() {
58+
return any();
59+
}
60+
61+
@Override
62+
public String getConstructorInterceptor() {
63+
return UNDERTOW_WORKER_THREAD_POOL_INTERCEPT;
64+
}
65+
}
66+
};
67+
}
68+
69+
@Override
70+
public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
71+
return new InstanceMethodsInterceptPoint[0];
72+
}
73+
74+
@Override
75+
public StaticMethodsInterceptPoint[] getStaticMethodsInterceptPoints() {
76+
return new StaticMethodsInterceptPoint[0];
77+
}
78+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*
17+
*/
18+
19+
package org.apache.skywalking.apm.plugin.undertow.worker.thread.pool.util;
20+
21+
import java.lang.reflect.Field;
22+
import java.lang.reflect.InvocationTargetException;
23+
import java.lang.reflect.Method;
24+
import lombok.Getter;
25+
import org.xnio.XnioWorker;
26+
27+
public class XnioWorkerTaskPoolAccessor {
28+
29+
private final Object taskPool;
30+
@Getter
31+
private boolean containsGetPoolSizeMethod;
32+
33+
private Method getCorePoolSizeMethod;
34+
private Method getMaximumPoolSizeMethod;
35+
private Method getActiveCountMethod;
36+
private Method getPoolSizeMethod;
37+
private Method getQueueSizeMethod;
38+
39+
public XnioWorkerTaskPoolAccessor(final XnioWorker worker) throws NoSuchFieldException, IllegalAccessException {
40+
Field field = worker.getClass().getSuperclass().getDeclaredField("taskPool");
41+
field.setAccessible(true);
42+
this.taskPool = field.get(worker);
43+
44+
try {
45+
getCorePoolSizeMethod = taskPool.getClass().getDeclaredMethod("getCorePoolSize");
46+
getCorePoolSizeMethod.setAccessible(true);
47+
} catch (NoSuchMethodException e) {
48+
// ignore
49+
}
50+
try {
51+
getMaximumPoolSizeMethod = taskPool.getClass().getDeclaredMethod("getMaximumPoolSize");
52+
getMaximumPoolSizeMethod.setAccessible(true);
53+
} catch (NoSuchMethodException e) {
54+
// ignore
55+
}
56+
try {
57+
getActiveCountMethod = taskPool.getClass().getDeclaredMethod("getActiveCount");
58+
getActiveCountMethod.setAccessible(true);
59+
} catch (NoSuchMethodException e) {
60+
// ignore
61+
}
62+
try {
63+
// getPoolSize add since 3.8.0
64+
getPoolSizeMethod = taskPool.getClass().getDeclaredMethod("getPoolSize");
65+
getPoolSizeMethod.setAccessible(true);
66+
containsGetPoolSizeMethod = true;
67+
} catch (NoSuchMethodException e) {
68+
containsGetPoolSizeMethod = false;
69+
}
70+
try {
71+
getQueueSizeMethod = taskPool.getClass().getDeclaredMethod("getQueueSize");
72+
getQueueSizeMethod.setAccessible(true);
73+
} catch (NoSuchMethodException e) {
74+
// ignore
75+
}
76+
}
77+
78+
public int getCorePoolSize() {
79+
try {
80+
return (int) getCorePoolSizeMethod.invoke(taskPool);
81+
} catch (IllegalAccessException | InvocationTargetException e) {
82+
throw new RuntimeException(e);
83+
}
84+
}
85+
86+
public int getMaximumPoolSize() {
87+
try {
88+
return (int) getMaximumPoolSizeMethod.invoke(taskPool);
89+
} catch (IllegalAccessException | InvocationTargetException e) {
90+
throw new RuntimeException(e);
91+
}
92+
}
93+
94+
public int getActiveCount() {
95+
try {
96+
return (int) getActiveCountMethod.invoke(taskPool);
97+
} catch (IllegalAccessException | InvocationTargetException e) {
98+
throw new RuntimeException(e);
99+
}
100+
}
101+
102+
public int getPoolSize() {
103+
try {
104+
return (int) getPoolSizeMethod.invoke(taskPool);
105+
} catch (IllegalAccessException | InvocationTargetException e) {
106+
throw new RuntimeException(e);
107+
}
108+
}
109+
110+
public int getQueueSize() {
111+
try {
112+
return (int) getQueueSizeMethod.invoke(taskPool);
113+
} catch (IllegalAccessException | InvocationTargetException e) {
114+
throw new RuntimeException(e);
115+
}
116+
}
117+
}

apm-sniffer/apm-sdk-plugin/undertow-worker-thread-pool-plugin/src/main/resources/skywalking-plugin.def

+2-1
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,5 @@
1414
# See the License for the specific language governing permissions and
1515
# limitations under the License.
1616

17-
undertow-worker-thread-pool=org.apache.skywalking.apm.plugin.undertow.worker.thread.pool.define.UndertowWorkerThreadPoolInstrumentation
17+
undertow-worker-thread-pool=org.apache.skywalking.apm.plugin.undertow.worker.thread.pool.define.UndertowWorkerThreadPoolInstrumentation
18+
undertow-worker-thread-pool=org.apache.skywalking.apm.plugin.undertow.worker.thread.pool.define.XnioWorkerConstructorInstrumentation

0 commit comments

Comments
 (0)