Support collecting dubbo thread pool metrics (#382)

This commit is contained in:
Stephen Ni 2022-11-17 09:56:19 +08:00 committed by GitHub
parent 615aa8eab4
commit 7eb796bd28
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 416 additions and 10 deletions

View File

@ -8,6 +8,7 @@ Release Notes.
* Polish test framework to support `arm64/v8` platforms
* 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**.
* Rename `JDBI` to `JDBC`
* Support collecting dubbo thread pool metrics
#### Documentation

View File

@ -0,0 +1,85 @@
/*
* 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.asf.dubbo;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.remoting.transport.AbstractServer;
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 java.lang.reflect.Field;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ThreadPoolExecutor;
public class AbstractServerConstructorInterceptor implements InstanceConstructorInterceptor {
private static final String METER_NAME = "thread_pool";
private static final String METRIC_POOL_NAME_TAG_NAME = "pool_name";
private static final String METRIC_TYPE_TAG_NAME = "metric_type";
@Override
public void onConstruct(EnhancedInstance objInst, Object[] allArguments) throws Throwable {
Field executorField = AbstractServer.class.getDeclaredField("executor");
executorField.setAccessible(true);
ExecutorService executor = (ExecutorService) executorField.get(objInst);
URL url = (URL) allArguments[0];
int port = url.getPort();
if (!(executor instanceof ThreadPoolExecutor)) {
return;
}
ThreadPoolExecutor threadPoolExecutor = (ThreadPoolExecutor) executor;
// TODO String.format("DubboServerHandler-%s:%s", host, port) will be better
String threadPoolName = String.format("DubboServerHandler-%s", port);
MeterFactory.gauge(METER_NAME, () -> (double) (threadPoolExecutor.getCorePoolSize()))
.tag(METRIC_POOL_NAME_TAG_NAME, threadPoolName)
.tag(METRIC_TYPE_TAG_NAME, "core_pool_size")
.build();
MeterFactory.gauge(METER_NAME, () -> (double) (threadPoolExecutor.getMaximumPoolSize()))
.tag(METRIC_POOL_NAME_TAG_NAME, threadPoolName)
.tag(METRIC_TYPE_TAG_NAME, "max_pool_size")
.build();
MeterFactory.gauge(METER_NAME, () -> (double) (threadPoolExecutor.getLargestPoolSize()))
.tag(METRIC_POOL_NAME_TAG_NAME, threadPoolName)
.tag(METRIC_TYPE_TAG_NAME, "largest_pool_size")
.build();
MeterFactory.gauge(METER_NAME, () -> (double) (threadPoolExecutor.getPoolSize()))
.tag(METRIC_POOL_NAME_TAG_NAME, threadPoolName)
.tag(METRIC_TYPE_TAG_NAME, "pool_size")
.build();
MeterFactory.gauge(METER_NAME, () -> (double) (threadPoolExecutor.getQueue().size()))
.tag(METRIC_POOL_NAME_TAG_NAME, threadPoolName)
.tag(METRIC_TYPE_TAG_NAME, "queue_size")
.build();
MeterFactory.gauge(METER_NAME, () -> (double) (threadPoolExecutor.getActiveCount()))
.tag(METRIC_POOL_NAME_TAG_NAME, threadPoolName)
.tag(METRIC_TYPE_TAG_NAME, "active_size")
.build();
MeterFactory.gauge(METER_NAME, () -> (double) (threadPoolExecutor.getTaskCount()))
.tag(METRIC_POOL_NAME_TAG_NAME, threadPoolName)
.tag(METRIC_TYPE_TAG_NAME, "task_count")
.build();
MeterFactory.gauge(METER_NAME, () -> (double) (threadPoolExecutor.getCompletedTaskCount()))
.tag(METRIC_POOL_NAME_TAG_NAME, threadPoolName)
.tag(METRIC_TYPE_TAG_NAME, "completed_task_count")
.build();
}
}

View File

@ -0,0 +1,61 @@
/*
* 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.asf.dubbo;
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.enhance.ClassInstanceMethodsEnhancePluginDefine;
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;
public class AbstractServerInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
private static final String ENHANCE_CLASS = "org.apache.dubbo.remoting.transport.AbstractServer";
private static final String CONSTRUCTOR_INTERCEPTOR = "org.apache.skywalking.apm.plugin.asf.dubbo.AbstractServerConstructorInterceptor";
@Override
protected ClassMatch enhanceClass() {
return byName(ENHANCE_CLASS);
}
@Override
public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
return new ConstructorInterceptPoint[]{
new ConstructorInterceptPoint() {
@Override
public ElementMatcher<MethodDescription> getConstructorMatcher() {
return any();
}
@Override
public String getConstructorInterceptor() {
return CONSTRUCTOR_INTERCEPTOR;
}
}
};
}
@Override
public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
return new InstanceMethodsInterceptPoint[0];
}
}

View File

@ -15,3 +15,4 @@
# limitations under the License.
dubbo-2.7.x=org.apache.skywalking.apm.plugin.asf.dubbo.DubboInstrumentation
dubbo-threadpool-2.7.x=org.apache.skywalking.apm.plugin.asf.dubbo.AbstractServerInstrumentation

View File

@ -0,0 +1,85 @@
/*
* 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.dubbo;
import com.alibaba.dubbo.common.URL;
import com.alibaba.dubbo.remoting.transport.AbstractServer;
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 java.lang.reflect.Field;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ThreadPoolExecutor;
public class AbstractServerConstructorInterceptor implements InstanceConstructorInterceptor {
private static final String METER_NAME = "thread_pool";
private static final String METRIC_POOL_NAME_TAG_NAME = "pool_name";
private static final String METRIC_TYPE_TAG_NAME = "metric_type";
@Override
public void onConstruct(EnhancedInstance objInst, Object[] allArguments) throws Throwable {
Field executorField = AbstractServer.class.getDeclaredField("executor");
executorField.setAccessible(true);
ExecutorService executor = (ExecutorService) executorField.get(objInst);
URL url = (URL) allArguments[0];
int port = url.getPort();
if (!(executor instanceof ThreadPoolExecutor)) {
return;
}
ThreadPoolExecutor threadPoolExecutor = (ThreadPoolExecutor) executor;
// TODO String.format("DubboServerHandler-%s:%s", host, port) will be better
String threadPoolName = String.format("DubboServerHandler-%s", port);
MeterFactory.gauge(METER_NAME, () -> (double) (threadPoolExecutor.getCorePoolSize()))
.tag(METRIC_POOL_NAME_TAG_NAME, threadPoolName)
.tag(METRIC_TYPE_TAG_NAME, "core_pool_size")
.build();
MeterFactory.gauge(METER_NAME, () -> (double) (threadPoolExecutor.getMaximumPoolSize()))
.tag(METRIC_POOL_NAME_TAG_NAME, threadPoolName)
.tag(METRIC_TYPE_TAG_NAME, "max_pool_size")
.build();
MeterFactory.gauge(METER_NAME, () -> (double) (threadPoolExecutor.getLargestPoolSize()))
.tag(METRIC_POOL_NAME_TAG_NAME, threadPoolName)
.tag(METRIC_TYPE_TAG_NAME, "largest_pool_size")
.build();
MeterFactory.gauge(METER_NAME, () -> (double) (threadPoolExecutor.getPoolSize()))
.tag(METRIC_POOL_NAME_TAG_NAME, threadPoolName)
.tag(METRIC_TYPE_TAG_NAME, "pool_size")
.build();
MeterFactory.gauge(METER_NAME, () -> (double) (threadPoolExecutor.getQueue().size()))
.tag(METRIC_POOL_NAME_TAG_NAME, threadPoolName)
.tag(METRIC_TYPE_TAG_NAME, "queue_size")
.build();
MeterFactory.gauge(METER_NAME, () -> (double) (threadPoolExecutor.getActiveCount()))
.tag(METRIC_POOL_NAME_TAG_NAME, threadPoolName)
.tag(METRIC_TYPE_TAG_NAME, "active_size")
.build();
MeterFactory.gauge(METER_NAME, () -> (double) (threadPoolExecutor.getTaskCount()))
.tag(METRIC_POOL_NAME_TAG_NAME, threadPoolName)
.tag(METRIC_TYPE_TAG_NAME, "task_count")
.build();
MeterFactory.gauge(METER_NAME, () -> (double) (threadPoolExecutor.getCompletedTaskCount()))
.tag(METRIC_POOL_NAME_TAG_NAME, threadPoolName)
.tag(METRIC_TYPE_TAG_NAME, "completed_task_count")
.build();
}
}

View File

@ -0,0 +1,61 @@
/*
* 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.dubbo;
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.enhance.ClassInstanceMethodsEnhancePluginDefine;
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;
public class AbstractServerInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
private static final String ENHANCE_CLASS = "com.alibaba.dubbo.remoting.transport.AbstractServer";
private static final String CONSTRUCTOR_INTERCEPTOR = "org.apache.skywalking.apm.plugin.dubbo.AbstractServerConstructorInterceptor";
@Override
protected ClassMatch enhanceClass() {
return byName(ENHANCE_CLASS);
}
@Override
public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
return new ConstructorInterceptPoint[]{
new ConstructorInterceptPoint() {
@Override
public ElementMatcher<MethodDescription> getConstructorMatcher() {
return any();
}
@Override
public String getConstructorInterceptor() {
return CONSTRUCTOR_INTERCEPTOR;
}
}
};
}
@Override
public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
return new InstanceMethodsInterceptPoint[0];
}
}

View File

@ -15,3 +15,4 @@
# limitations under the License.
dubbo=org.apache.skywalking.apm.plugin.dubbo.DubboInstrumentation
dubbo-threadpool=org.apache.skywalking.apm.plugin.dubbo.AbstractServerInstrumentation

View File

@ -15,6 +15,8 @@
- dubbo
- dubbo-2.7.x
- dubbo-3.x
- dubbo-threadpool
- dubbo-threadpool-2.7.x
- ehcache-2.x
- elastic-job-2.x
- elasticjob-3.x

View File

@ -151,6 +151,7 @@ The meter plugin provides the advanced metrics collections, which are not a part
* Thread Pool
* [Undertow](https://github.com/undertow-io/undertow) 2.1.x -> 2.6.x
* [Tomcat](https://github.com/apache/tomcat) 7.0.x -> 10.0.x
* [Dubbo](https://github.com/apache/dubbo) 2.5.x -> 2.7.x
___
¹Due to license incompatibilities/restrictions these plugins are hosted and released in 3rd part repository,
go to [SkyAPM java plugin extension repository](https://github.com/SkyAPM/java-plugin-extensions) to get these.

View File

@ -32,7 +32,7 @@ segmentItems:
tags:
- {key: url, value: not null}
refs:
- {parentEndpoint: GET:/dubbo-2.5.x-scenario/case/dubbo, networkAddress: 'localhost:20080',
- {parentEndpoint: GET:/dubbo-2.5.x-scenario/case/dubbo, networkAddress: 'localhost:20880',
refType: CrossProcess, parentSpanId: 1, parentTraceSegmentId: not null, parentServiceInstance: not
null, parentService: dubbo-2.5.x-scenario, traceId: not null}
skipAnalysis: 'false'
@ -47,9 +47,9 @@ segmentItems:
componentId: 3
isError: false
spanType: Exit
peer: localhost:20080
peer: localhost:20880
tags:
- {key: url, value: 'dubbo://localhost:20080/org.apache.skywalking.apm.testcase.dubbo.services.GreetService.doBusiness()'}
- {key: url, value: 'dubbo://localhost:20880/org.apache.skywalking.apm.testcase.dubbo.services.GreetService.doBusiness()'}
skipAnalysis: 'false'
- operationName: GET:/dubbo-2.5.x-scenario/case/dubbo
parentSpanId: -1
@ -66,3 +66,55 @@ segmentItems:
- {key: http.method, value: GET}
- {key: http.status_code, value: '200'}
skipAnalysis: 'false'
meterItems:
- serviceName: dubbo-2.5.x-scenario
meterSize: ge 8
meters:
- meterId:
name: thread_pool
tags:
- {name: metric_type, value: core_pool_size}
- {name: pool_name, value: DubboServerHandler-20880}
singleValue: ge 1
- meterId:
name: thread_pool
tags:
- {name: metric_type, value: max_pool_size}
- {name: pool_name, value: DubboServerHandler-20880}
singleValue: ge 1
- meterId:
name: thread_pool
tags:
- {name: metric_type, value: largest_pool_size}
- {name: pool_name, value: DubboServerHandler-20880}
singleValue: ge 1
- meterId:
name: thread_pool
tags:
- {name: metric_type, value: pool_size}
- {name: pool_name, value: DubboServerHandler-20880}
singleValue: ge 0
- meterId:
name: thread_pool
tags:
- {name: metric_type, value: queue_size}
- {name: pool_name, value: DubboServerHandler-20880}
singleValue: ge 0
- meterId:
name: thread_pool
tags:
- {name: metric_type, value: active_size}
- {name: pool_name, value: DubboServerHandler-20880}
singleValue: ge 0
- meterId:
name: thread_pool
tags:
- {name: metric_type, value: task_count}
- {name: pool_name, value: DubboServerHandler-20880}
singleValue: ge 0
- meterId:
name: thread_pool
tags:
- {name: metric_type, value: completed_task_count}
- {name: pool_name, value: DubboServerHandler-20880}
singleValue: ge 0

View File

@ -18,3 +18,5 @@ type: jvm
entryService: http://localhost:8080/dubbo-2.5.x-scenario/case/dubbo
healthCheck: http://localhost:8080/dubbo-2.5.x-scenario/case/healthCheck
startScript: ./bin/startup.sh
environment:
- SW_METER_REPORT_INTERVAL=1

View File

@ -44,7 +44,7 @@ public class Application {
private RegistryConfig registryConfig = new RegistryConfig("N/A");
private ProtocolConfig protocolConfig = new ProtocolConfig("dubbo", 20080);
private ProtocolConfig protocolConfig = new ProtocolConfig("dubbo", 20880);
@Bean(destroyMethod = "unexport")
public ServiceConfig<GreetService> service() {
@ -65,7 +65,7 @@ public class Application {
referenceConfig.setApplication(applicationConfig);
referenceConfig.setInterface(GreetService.class);
referenceConfig.setUrl("dubbo://localhost:20080");
referenceConfig.setUrl("dubbo://localhost:20880");
return referenceConfig;
}

View File

@ -34,7 +34,7 @@ segmentItems:
- {key: url, value: not null}
- {key: arguments, value: helloWorld}
refs:
- {parentEndpoint: GET:/dubbo-2.7.x-scenario/case/dubbo, networkAddress: 'localhost:20080',
- {parentEndpoint: GET:/dubbo-2.7.x-scenario/case/dubbo, networkAddress: 'localhost:20880',
refType: CrossProcess, parentSpanId: 1, parentTraceSegmentId: not null,
parentServiceInstance: not null, parentService: dubbo-2.7.x-scenario, traceId: not null}
skipAnalysis: 'false'
@ -49,9 +49,9 @@ segmentItems:
componentId: 3
isError: false
spanType: Exit
peer: localhost:20080
peer: localhost:20880
tags:
- {key: url, value: 'dubbo://localhost:20080/org.apache.skywalking.apm.testcase.dubbo.services.GreetService.doBusiness(String)'}
- {key: url, value: 'dubbo://localhost:20880/org.apache.skywalking.apm.testcase.dubbo.services.GreetService.doBusiness(String)'}
- {key: arguments, value: helloWorld}
skipAnalysis: 'false'
- operationName: GET:/dubbo-2.7.x-scenario/case/dubbo
@ -69,3 +69,55 @@ segmentItems:
- {key: http.method, value: GET}
- {key: http.status_code, value: '200'}
skipAnalysis: 'false'
meterItems:
- serviceName: dubbo-2.7.x-scenario
meterSize: ge 8
meters:
- meterId:
name: thread_pool
tags:
- {name: metric_type, value: core_pool_size}
- {name: pool_name, value: DubboServerHandler-20880}
singleValue: ge 1
- meterId:
name: thread_pool
tags:
- {name: metric_type, value: max_pool_size}
- {name: pool_name, value: DubboServerHandler-20880}
singleValue: ge 1
- meterId:
name: thread_pool
tags:
- {name: metric_type, value: largest_pool_size}
- {name: pool_name, value: DubboServerHandler-20880}
singleValue: ge 1
- meterId:
name: thread_pool
tags:
- {name: metric_type, value: pool_size}
- {name: pool_name, value: DubboServerHandler-20880}
singleValue: ge 0
- meterId:
name: thread_pool
tags:
- {name: metric_type, value: queue_size}
- {name: pool_name, value: DubboServerHandler-20880}
singleValue: ge 0
- meterId:
name: thread_pool
tags:
- {name: metric_type, value: active_size}
- {name: pool_name, value: DubboServerHandler-20880}
singleValue: ge 0
- meterId:
name: thread_pool
tags:
- {name: metric_type, value: task_count}
- {name: pool_name, value: DubboServerHandler-20880}
singleValue: ge 0
- meterId:
name: thread_pool
tags:
- {name: metric_type, value: completed_task_count}
- {name: pool_name, value: DubboServerHandler-20880}
singleValue: ge 0

View File

@ -18,3 +18,5 @@ type: jvm
entryService: http://localhost:8080/dubbo-2.7.x-scenario/case/dubbo
healthCheck: http://localhost:8080/dubbo-2.7.x-scenario/case/healthCheck
startScript: ./bin/startup.sh
environment:
- SW_METER_REPORT_INTERVAL=1

View File

@ -44,7 +44,7 @@ public class Application {
private RegistryConfig registryConfig = new RegistryConfig("N/A");
private ProtocolConfig protocolConfig = new ProtocolConfig("dubbo", 20080);
private ProtocolConfig protocolConfig = new ProtocolConfig("dubbo", 20880);
@Bean(destroyMethod = "unexport")
public ServiceConfig<GreetService> service() {
@ -65,7 +65,7 @@ public class Application {
referenceConfig.setApplication(applicationConfig);
referenceConfig.setInterface(GreetService.class);
referenceConfig.setUrl("dubbo://localhost:20080");
referenceConfig.setUrl("dubbo://localhost:20880");
return referenceConfig;
}