Skip to content

Commit 7eb796b

Browse files
authored
Support collecting dubbo thread pool metrics (#382)
1 parent 615aa8e commit 7eb796b

15 files changed

Lines changed: 416 additions & 10 deletions

File tree

CHANGES.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ Release Notes.
88
* Polish test framework to support `arm64/v8` platforms
99
* Fix wrong config name `plugin.toolkit.use_qualified_name_as_operation_name`, and system variable name `SW_PLUGIN_TOOLKIT_USE_QUALIFIED_NAME_AS_OPERATION_NAME:false`. They were **toolit**.
1010
* Rename `JDBI` to `JDBC`
11+
* Support collecting dubbo thread pool metrics
1112

1213
#### Documentation
1314

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
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.asf.dubbo;
20+
21+
import org.apache.dubbo.common.URL;
22+
import org.apache.dubbo.remoting.transport.AbstractServer;
23+
import org.apache.skywalking.apm.agent.core.meter.MeterFactory;
24+
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
25+
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceConstructorInterceptor;
26+
27+
import java.lang.reflect.Field;
28+
import java.util.concurrent.ExecutorService;
29+
import java.util.concurrent.ThreadPoolExecutor;
30+
31+
public class AbstractServerConstructorInterceptor implements InstanceConstructorInterceptor {
32+
private static final String METER_NAME = "thread_pool";
33+
private static final String METRIC_POOL_NAME_TAG_NAME = "pool_name";
34+
private static final String METRIC_TYPE_TAG_NAME = "metric_type";
35+
36+
@Override
37+
public void onConstruct(EnhancedInstance objInst, Object[] allArguments) throws Throwable {
38+
Field executorField = AbstractServer.class.getDeclaredField("executor");
39+
executorField.setAccessible(true);
40+
ExecutorService executor = (ExecutorService) executorField.get(objInst);
41+
42+
URL url = (URL) allArguments[0];
43+
int port = url.getPort();
44+
45+
if (!(executor instanceof ThreadPoolExecutor)) {
46+
return;
47+
}
48+
ThreadPoolExecutor threadPoolExecutor = (ThreadPoolExecutor) executor;
49+
// TODO String.format("DubboServerHandler-%s:%s", host, port) will be better
50+
String threadPoolName = String.format("DubboServerHandler-%s", port);
51+
52+
MeterFactory.gauge(METER_NAME, () -> (double) (threadPoolExecutor.getCorePoolSize()))
53+
.tag(METRIC_POOL_NAME_TAG_NAME, threadPoolName)
54+
.tag(METRIC_TYPE_TAG_NAME, "core_pool_size")
55+
.build();
56+
MeterFactory.gauge(METER_NAME, () -> (double) (threadPoolExecutor.getMaximumPoolSize()))
57+
.tag(METRIC_POOL_NAME_TAG_NAME, threadPoolName)
58+
.tag(METRIC_TYPE_TAG_NAME, "max_pool_size")
59+
.build();
60+
MeterFactory.gauge(METER_NAME, () -> (double) (threadPoolExecutor.getLargestPoolSize()))
61+
.tag(METRIC_POOL_NAME_TAG_NAME, threadPoolName)
62+
.tag(METRIC_TYPE_TAG_NAME, "largest_pool_size")
63+
.build();
64+
MeterFactory.gauge(METER_NAME, () -> (double) (threadPoolExecutor.getPoolSize()))
65+
.tag(METRIC_POOL_NAME_TAG_NAME, threadPoolName)
66+
.tag(METRIC_TYPE_TAG_NAME, "pool_size")
67+
.build();
68+
MeterFactory.gauge(METER_NAME, () -> (double) (threadPoolExecutor.getQueue().size()))
69+
.tag(METRIC_POOL_NAME_TAG_NAME, threadPoolName)
70+
.tag(METRIC_TYPE_TAG_NAME, "queue_size")
71+
.build();
72+
MeterFactory.gauge(METER_NAME, () -> (double) (threadPoolExecutor.getActiveCount()))
73+
.tag(METRIC_POOL_NAME_TAG_NAME, threadPoolName)
74+
.tag(METRIC_TYPE_TAG_NAME, "active_size")
75+
.build();
76+
MeterFactory.gauge(METER_NAME, () -> (double) (threadPoolExecutor.getTaskCount()))
77+
.tag(METRIC_POOL_NAME_TAG_NAME, threadPoolName)
78+
.tag(METRIC_TYPE_TAG_NAME, "task_count")
79+
.build();
80+
MeterFactory.gauge(METER_NAME, () -> (double) (threadPoolExecutor.getCompletedTaskCount()))
81+
.tag(METRIC_POOL_NAME_TAG_NAME, threadPoolName)
82+
.tag(METRIC_TYPE_TAG_NAME, "completed_task_count")
83+
.build();
84+
}
85+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
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.asf.dubbo;
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.enhance.ClassInstanceMethodsEnhancePluginDefine;
26+
import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
27+
28+
import static net.bytebuddy.matcher.ElementMatchers.any;
29+
import static org.apache.skywalking.apm.agent.core.plugin.match.NameMatch.byName;
30+
31+
public class AbstractServerInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
32+
private static final String ENHANCE_CLASS = "org.apache.dubbo.remoting.transport.AbstractServer";
33+
private static final String CONSTRUCTOR_INTERCEPTOR = "org.apache.skywalking.apm.plugin.asf.dubbo.AbstractServerConstructorInterceptor";
34+
35+
@Override
36+
protected ClassMatch enhanceClass() {
37+
return byName(ENHANCE_CLASS);
38+
}
39+
40+
@Override
41+
public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
42+
return new ConstructorInterceptPoint[]{
43+
new ConstructorInterceptPoint() {
44+
@Override
45+
public ElementMatcher<MethodDescription> getConstructorMatcher() {
46+
return any();
47+
}
48+
49+
@Override
50+
public String getConstructorInterceptor() {
51+
return CONSTRUCTOR_INTERCEPTOR;
52+
}
53+
}
54+
};
55+
}
56+
57+
@Override
58+
public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
59+
return new InstanceMethodsInterceptPoint[0];
60+
}
61+
}

apm-sniffer/apm-sdk-plugin/dubbo-2.7.x-plugin/src/main/resources/skywalking-plugin.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,4 @@
1515
# limitations under the License.
1616

1717
dubbo-2.7.x=org.apache.skywalking.apm.plugin.asf.dubbo.DubboInstrumentation
18+
dubbo-threadpool-2.7.x=org.apache.skywalking.apm.plugin.asf.dubbo.AbstractServerInstrumentation
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
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.dubbo;
20+
21+
import com.alibaba.dubbo.common.URL;
22+
import com.alibaba.dubbo.remoting.transport.AbstractServer;
23+
import org.apache.skywalking.apm.agent.core.meter.MeterFactory;
24+
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
25+
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceConstructorInterceptor;
26+
27+
import java.lang.reflect.Field;
28+
import java.util.concurrent.ExecutorService;
29+
import java.util.concurrent.ThreadPoolExecutor;
30+
31+
public class AbstractServerConstructorInterceptor implements InstanceConstructorInterceptor {
32+
private static final String METER_NAME = "thread_pool";
33+
private static final String METRIC_POOL_NAME_TAG_NAME = "pool_name";
34+
private static final String METRIC_TYPE_TAG_NAME = "metric_type";
35+
36+
@Override
37+
public void onConstruct(EnhancedInstance objInst, Object[] allArguments) throws Throwable {
38+
Field executorField = AbstractServer.class.getDeclaredField("executor");
39+
executorField.setAccessible(true);
40+
ExecutorService executor = (ExecutorService) executorField.get(objInst);
41+
42+
URL url = (URL) allArguments[0];
43+
int port = url.getPort();
44+
45+
if (!(executor instanceof ThreadPoolExecutor)) {
46+
return;
47+
}
48+
ThreadPoolExecutor threadPoolExecutor = (ThreadPoolExecutor) executor;
49+
// TODO String.format("DubboServerHandler-%s:%s", host, port) will be better
50+
String threadPoolName = String.format("DubboServerHandler-%s", port);
51+
52+
MeterFactory.gauge(METER_NAME, () -> (double) (threadPoolExecutor.getCorePoolSize()))
53+
.tag(METRIC_POOL_NAME_TAG_NAME, threadPoolName)
54+
.tag(METRIC_TYPE_TAG_NAME, "core_pool_size")
55+
.build();
56+
MeterFactory.gauge(METER_NAME, () -> (double) (threadPoolExecutor.getMaximumPoolSize()))
57+
.tag(METRIC_POOL_NAME_TAG_NAME, threadPoolName)
58+
.tag(METRIC_TYPE_TAG_NAME, "max_pool_size")
59+
.build();
60+
MeterFactory.gauge(METER_NAME, () -> (double) (threadPoolExecutor.getLargestPoolSize()))
61+
.tag(METRIC_POOL_NAME_TAG_NAME, threadPoolName)
62+
.tag(METRIC_TYPE_TAG_NAME, "largest_pool_size")
63+
.build();
64+
MeterFactory.gauge(METER_NAME, () -> (double) (threadPoolExecutor.getPoolSize()))
65+
.tag(METRIC_POOL_NAME_TAG_NAME, threadPoolName)
66+
.tag(METRIC_TYPE_TAG_NAME, "pool_size")
67+
.build();
68+
MeterFactory.gauge(METER_NAME, () -> (double) (threadPoolExecutor.getQueue().size()))
69+
.tag(METRIC_POOL_NAME_TAG_NAME, threadPoolName)
70+
.tag(METRIC_TYPE_TAG_NAME, "queue_size")
71+
.build();
72+
MeterFactory.gauge(METER_NAME, () -> (double) (threadPoolExecutor.getActiveCount()))
73+
.tag(METRIC_POOL_NAME_TAG_NAME, threadPoolName)
74+
.tag(METRIC_TYPE_TAG_NAME, "active_size")
75+
.build();
76+
MeterFactory.gauge(METER_NAME, () -> (double) (threadPoolExecutor.getTaskCount()))
77+
.tag(METRIC_POOL_NAME_TAG_NAME, threadPoolName)
78+
.tag(METRIC_TYPE_TAG_NAME, "task_count")
79+
.build();
80+
MeterFactory.gauge(METER_NAME, () -> (double) (threadPoolExecutor.getCompletedTaskCount()))
81+
.tag(METRIC_POOL_NAME_TAG_NAME, threadPoolName)
82+
.tag(METRIC_TYPE_TAG_NAME, "completed_task_count")
83+
.build();
84+
}
85+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
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.dubbo;
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.enhance.ClassInstanceMethodsEnhancePluginDefine;
26+
import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
27+
28+
import static net.bytebuddy.matcher.ElementMatchers.any;
29+
import static org.apache.skywalking.apm.agent.core.plugin.match.NameMatch.byName;
30+
31+
public class AbstractServerInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
32+
private static final String ENHANCE_CLASS = "com.alibaba.dubbo.remoting.transport.AbstractServer";
33+
private static final String CONSTRUCTOR_INTERCEPTOR = "org.apache.skywalking.apm.plugin.dubbo.AbstractServerConstructorInterceptor";
34+
35+
@Override
36+
protected ClassMatch enhanceClass() {
37+
return byName(ENHANCE_CLASS);
38+
}
39+
40+
@Override
41+
public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
42+
return new ConstructorInterceptPoint[]{
43+
new ConstructorInterceptPoint() {
44+
@Override
45+
public ElementMatcher<MethodDescription> getConstructorMatcher() {
46+
return any();
47+
}
48+
49+
@Override
50+
public String getConstructorInterceptor() {
51+
return CONSTRUCTOR_INTERCEPTOR;
52+
}
53+
}
54+
};
55+
}
56+
57+
@Override
58+
public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
59+
return new InstanceMethodsInterceptPoint[0];
60+
}
61+
}

apm-sniffer/apm-sdk-plugin/dubbo-plugin/src/main/resources/skywalking-plugin.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,4 @@
1515
# limitations under the License.
1616

1717
dubbo=org.apache.skywalking.apm.plugin.dubbo.DubboInstrumentation
18+
dubbo-threadpool=org.apache.skywalking.apm.plugin.dubbo.AbstractServerInstrumentation

docs/en/setup/service-agent/java-agent/Plugin-list.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
- dubbo
1616
- dubbo-2.7.x
1717
- dubbo-3.x
18+
- dubbo-threadpool
19+
- dubbo-threadpool-2.7.x
1820
- ehcache-2.x
1921
- elastic-job-2.x
2022
- elasticjob-3.x

docs/en/setup/service-agent/java-agent/Supported-list.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,7 @@ The meter plugin provides the advanced metrics collections, which are not a part
151151
* Thread Pool
152152
* [Undertow](https://github.com/undertow-io/undertow) 2.1.x -> 2.6.x
153153
* [Tomcat](https://github.com/apache/tomcat) 7.0.x -> 10.0.x
154+
* [Dubbo](https://github.com/apache/dubbo) 2.5.x -> 2.7.x
154155
___
155156
¹Due to license incompatibilities/restrictions these plugins are hosted and released in 3rd part repository,
156157
go to [SkyAPM java plugin extension repository](https://github.com/SkyAPM/java-plugin-extensions) to get these.

0 commit comments

Comments
 (0)