-
Notifications
You must be signed in to change notification settings - Fork 679
[Feature] Support collecting database connection pool metric,support dbcp2/druid/hikari #96
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
27 commits
Select commit
Hold shift + click to select a range
03d2bfc
[Feature] Support collecting database connection pool metric,support …
5e89096
[Feature] Support collecting database connection pool metric,support …
e15380f
Merge branch 'apache:main' into main
sunOnly 5f6aabe
[Feature] Support collecting database connection pool metric,support …
63e68b5
Merge branch 'main' of github.com:sunOnly/skywalking-java into main
8ba0cac
Merge branch 'apache:main' into main
sunOnly 13b1aa9
:wq
6ca6867
modify format#8450
5b2f044
druid metric monitor #8450
1a4da64
Merge branch 'apache:main' into main
sunOnly 6ab8cf7
add support config params collect #96
b83653f
Merge remote-tracking branch 'origin/main' into main
499cf50
Merge branch 'main' into main
wu-sheng a2f3d9c
static field static field Enhanced class changed to interface,add tes…
c6adcf8
remove static field and log #96
15aa2ab
format #96
c08204b
optimization #96
fd9b150
remove space key #96
0e142fc
Merge branch 'main' into main
wu-sheng 1ec6f11
add tomcat metric #96
bbcfb63
Merge branch 'main' of github.com:sunOnly/skywalking-java into main
b6ee8a0
validate value change #96
820cd0f
remove datasource metric #96
aa9f446
Merge branch 'main' into main
wu-sheng 8ae7517
optimize interception point #96
25c9f46
Merge branch 'main' of github.com:sunOnly/skywalking-java into main
bee196f
Optimize interception point #96
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
71 changes: 71 additions & 0 deletions
71
...src/main/java/org/apache/skywalking/apm/plugin/dbcp/v2/PoolingJmxRegisterInterceptor.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,71 @@ | ||
| /* | ||
| * 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.dbcp.v2; | ||
|
|
||
| import org.apache.commons.dbcp2.BasicDataSourceMXBean; | ||
| 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.InstanceMethodsAroundInterceptor; | ||
| import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult; | ||
|
|
||
| import java.lang.reflect.Method; | ||
| import java.util.HashMap; | ||
| import java.util.Map; | ||
| import java.util.function.Function; | ||
| import java.util.function.Supplier; | ||
|
|
||
| /** | ||
| * {@link PoolingJmxRegisterInterceptor} intercepted the method of DBCP jmxRegister register metric monitor. | ||
| */ | ||
| public class PoolingJmxRegisterInterceptor implements InstanceMethodsAroundInterceptor { | ||
| private static final String METER_NAME = "datasource"; | ||
|
|
||
| @Override | ||
| public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, MethodInterceptResult result) throws Throwable { | ||
|
|
||
| } | ||
|
|
||
| @Override | ||
| public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, Object ret) throws Throwable { | ||
| if (objInst.getSkyWalkingDynamicField() != null) { | ||
| BasicDataSourceMXBean basicDataSource = (BasicDataSourceMXBean) objInst; | ||
| String tagValue = (String) objInst.getSkyWalkingDynamicField(); | ||
| Map<String, Function<BasicDataSourceMXBean, Supplier<Double>>> metricMap = getMetrics(); | ||
| metricMap.forEach((key, value) -> MeterFactory.gauge(METER_NAME, value.apply(basicDataSource)) | ||
| .tag("name", tagValue).tag("status", key).build()); | ||
| } | ||
| return ret; | ||
| } | ||
|
|
||
| @Override | ||
| public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, Throwable t) { | ||
|
|
||
| } | ||
|
|
||
| private Map<String, Function<BasicDataSourceMXBean, Supplier<Double>>> getMetrics() { | ||
| Map<String, Function<BasicDataSourceMXBean, Supplier<Double>>> metricMap = new HashMap(); | ||
| metricMap.put("numActive", (BasicDataSourceMXBean basicDataSource) -> () -> (double) basicDataSource.getNumActive()); | ||
| metricMap.put("maxTotal", (BasicDataSourceMXBean basicDataSource) -> () -> (double) basicDataSource.getMaxTotal()); | ||
| metricMap.put("numIdle", (BasicDataSourceMXBean basicDataSource) -> () -> (double) (basicDataSource.getNumIdle())); | ||
| metricMap.put("maxWaitMillis", (BasicDataSourceMXBean basicDataSource) -> () -> (double) basicDataSource.getMaxWaitMillis()); | ||
| metricMap.put("maxIdle", (BasicDataSourceMXBean basicDataSource) -> () -> (double) basicDataSource.getMaxIdle()); | ||
| metricMap.put("minIdle", (BasicDataSourceMXBean basicDataSource) -> () -> (double) basicDataSource.getMinIdle()); | ||
| metricMap.put("initialSize", (BasicDataSourceMXBean basicDataSource) -> () -> (double) basicDataSource.getInitialSize()); | ||
| return metricMap; | ||
| } | ||
| } |
51 changes: 51 additions & 0 deletions
51
...ugin/src/main/java/org/apache/skywalking/apm/plugin/dbcp/v2/PoolingSetUrlInterceptor.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,51 @@ | ||
| /* | ||
| * 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.dbcp.v2; | ||
|
|
||
| import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance; | ||
| import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor; | ||
| import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult; | ||
| import org.apache.skywalking.apm.plugin.jdbc.connectionurl.parser.URLParser; | ||
| import org.apache.skywalking.apm.plugin.jdbc.trace.ConnectionInfo; | ||
|
|
||
| import java.lang.reflect.Method; | ||
|
|
||
| /** | ||
| * {@link PoolingSetUrlInterceptor} intercepted the method of DBCP set url Get parameters. | ||
| */ | ||
| public class PoolingSetUrlInterceptor implements InstanceMethodsAroundInterceptor { | ||
| private static final String METER_NAME = "datasource"; | ||
|
|
||
| @Override | ||
| public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, MethodInterceptResult result) throws Throwable { | ||
|
|
||
| } | ||
|
|
||
| @Override | ||
| public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, Object ret) throws Throwable { | ||
| ConnectionInfo connectionInfo = URLParser.parser((String) allArguments[0]); | ||
| String tagValue = connectionInfo.getDatabaseName() + "_" + connectionInfo.getDatabasePeer(); | ||
| objInst.setSkyWalkingDynamicField(tagValue); | ||
| return ret; | ||
| } | ||
|
|
||
| @Override | ||
| public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, Throwable t) { | ||
|
|
||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
73 changes: 73 additions & 0 deletions
73
.../java/org/apache/skywalking/apm/plugin/druid/v1/PoolingAddDruidDataSourceInterceptor.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,73 @@ | ||
| /* | ||
| * 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.druid.v1; | ||
|
|
||
| import com.alibaba.druid.pool.DruidDataSourceMBean; | ||
| import org.apache.skywalking.apm.agent.core.meter.MeterFactory; | ||
| import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult; | ||
| import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.StaticMethodsAroundInterceptor; | ||
| import org.apache.skywalking.apm.plugin.jdbc.connectionurl.parser.URLParser; | ||
| import org.apache.skywalking.apm.plugin.jdbc.trace.ConnectionInfo; | ||
|
|
||
| import java.lang.reflect.Method; | ||
| import java.util.HashMap; | ||
| import java.util.Map; | ||
| import java.util.function.Function; | ||
| import java.util.function.Supplier; | ||
|
|
||
| /** | ||
| * {@link PoolingAddDruidDataSourceInterceptor} intercepted the method of druid addDataSource and register metric monitor. | ||
| */ | ||
| public class PoolingAddDruidDataSourceInterceptor implements StaticMethodsAroundInterceptor { | ||
| private static final String METER_NAME = "datasource"; | ||
|
|
||
| @Override | ||
| public void beforeMethod(Class clazz, Method method, Object[] allArguments, Class<?>[] parameterTypes, MethodInterceptResult result) { | ||
|
|
||
| } | ||
|
|
||
| @Override | ||
| public Object afterMethod(Class clazz, Method method, Object[] allArguments, Class<?>[] parameterTypes, Object ret) { | ||
| DruidDataSourceMBean druidDataSource = (DruidDataSourceMBean) allArguments[0]; | ||
| ConnectionInfo connectionInfo = URLParser.parser(druidDataSource.getUrl()); | ||
| String tagValue = connectionInfo.getDatabaseName() + "_" + connectionInfo.getDatabasePeer(); | ||
| Map<String, Function<DruidDataSourceMBean, Supplier<Double>>> metricMap = getMetrics(); | ||
| metricMap.forEach((key, value) -> MeterFactory.gauge(METER_NAME, value.apply(druidDataSource)) | ||
| .tag("name", tagValue).tag("status", key).build()); | ||
| return ret; | ||
| } | ||
|
|
||
| @Override | ||
| public void handleMethodException(Class clazz, Method method, Object[] allArguments, Class<?>[] parameterTypes, Throwable t) { | ||
|
|
||
| } | ||
|
|
||
| private Map<String, Function<DruidDataSourceMBean, Supplier<Double>>> getMetrics() { | ||
| Map<String, Function<DruidDataSourceMBean, Supplier<Double>>> metricMap = new HashMap(); | ||
| metricMap.put("activeCount", (DruidDataSourceMBean druidDataSource) -> () -> (double) druidDataSource.getActiveCount()); | ||
| metricMap.put("poolingCount", (DruidDataSourceMBean druidDataSource) -> () -> (double) druidDataSource.getPoolingCount()); | ||
| metricMap.put("idleCount", (DruidDataSourceMBean druidDataSource) -> () -> (double) (druidDataSource.getPoolingCount() - druidDataSource.getActiveCount())); | ||
| metricMap.put("lockQueueLength", (DruidDataSourceMBean druidDataSource) -> () -> (double) druidDataSource.getLockQueueLength()); | ||
| metricMap.put("maxWaitThreadCount", (DruidDataSourceMBean druidDataSource) -> () -> (double) druidDataSource.getMaxWaitThreadCount()); | ||
| metricMap.put("commitCount", (DruidDataSourceMBean druidDataSource) -> () -> (double) druidDataSource.getCommitCount()); | ||
| metricMap.put("connectCount", (DruidDataSourceMBean druidDataSource) -> () -> (double) druidDataSource.getConnectCount()); | ||
| metricMap.put("connectError", (DruidDataSourceMBean druidDataSource) -> () -> (double) druidDataSource.getConnectErrorCount()); | ||
| metricMap.put("createError", (DruidDataSourceMBean druidDataSource) -> () -> (double) druidDataSource.getCreateErrorCount()); | ||
| return metricMap; | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
79 changes: 79 additions & 0 deletions
79
...ache/skywalking/apm/plugin/druid/v1/define/DruidDataSourceStatManagerInstrumentation.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,79 @@ | ||
| /* | ||
| * 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.druid.v1.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.ClassStaticMethodsEnhancePluginDefine; | ||
| import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch; | ||
|
|
||
| import static net.bytebuddy.matcher.ElementMatchers.takesArguments; | ||
| import static net.bytebuddy.matcher.ElementMatchers.named; | ||
| import static org.apache.skywalking.apm.agent.core.plugin.match.NameMatch.byName; | ||
|
|
||
| /** | ||
| * Druid is a database connection pool from Alibaba inc. | ||
| * <p> | ||
| * DruidDataSource provides a "one stop" solution for database connection pool solution | ||
| * basic requirements. DruidDataSourceStatManager.addDataSource(Object dataSource, String name) | ||
| */ | ||
| public class DruidDataSourceStatManagerInstrumentation extends ClassStaticMethodsEnhancePluginDefine { | ||
| private static final String ENHANCE_CLASS = "com.alibaba.druid.stat.DruidDataSourceStatManager"; | ||
| private static final String ENHANCE_METHOD = "addDataSource"; | ||
| private static final String INTERCEPTOR_CLASS = "org.apache.skywalking.apm.plugin.druid.v1.PoolingAddDruidDataSourceInterceptor"; | ||
|
|
||
| @Override | ||
| protected ClassMatch enhanceClass() { | ||
| return byName(ENHANCE_CLASS); | ||
| } | ||
|
|
||
| @Override | ||
| public ConstructorInterceptPoint[] getConstructorsInterceptPoints() { | ||
| return new ConstructorInterceptPoint[0]; | ||
| } | ||
|
|
||
| @Override | ||
| public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() { | ||
| return new InstanceMethodsInterceptPoint[0]; | ||
| } | ||
|
|
||
| @Override | ||
| public StaticMethodsInterceptPoint[] getStaticMethodsInterceptPoints() { | ||
| return new StaticMethodsInterceptPoint[]{ | ||
| new StaticMethodsInterceptPoint() { | ||
| @Override | ||
| public ElementMatcher<MethodDescription> getMethodsMatcher() { | ||
| return named(ENHANCE_METHOD).and(takesArguments(Object.class, String.class)); | ||
| } | ||
|
|
||
| @Override | ||
| public String getMethodsInterceptor() { | ||
| return INTERCEPTOR_CLASS; | ||
| } | ||
|
|
||
| @Override | ||
| public boolean isOverrideArgs() { | ||
| return false; | ||
| } | ||
| } | ||
| }; | ||
| } | ||
| } |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just a final comment:
As I've stated before, we have to be careful with the interceptor points for
Alibaba/DruidandHikariCP. But I'am not quite familiar with thisdbcp2DataSource.So, could you please justify the choice of this interceptor point?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@sunOnly First of all, good to see the tests passed. Let's follow this one.
#setUrlis not a good point to begin the monitoring, because in the runtime, a datasource could benot-createdat this moment, even never(code bug).I was looking through the codes, it is likely
createDataSourceis a better method to begin all metrics registration and reporting. Meanwhile, I understand you intercept#setUrlis to get the URL parameter, I noticed there isgetUrlmethod in the class, but with asynchronized, which I have concerns about deadlock. So, it is better you keep thissetUrlmethod intercepting, but keep the value of URL into theEnhancedInstance#setSkyWalkingDynamicField. Then in newcreateDataSourceinterceptor, you could use#getSkyWalkingDynamicFieldto read this.This would be more robust.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about using
jmxRegister()called withincreateDataSource()(if dataSource is not created) as the interception point?Since every call to
getConnection()will invokecreateDataSource(), the performance may be impacted. It also exists from2.0.1to2.9.0.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Really? This doesn't seem reasonable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@sunOnly Could you try this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
https://github.com/apache/commons-dbcp/blob/466091e51d875d2a4499adbbb63058e32ad5a7c7/src/main/java/org/apache/commons/dbcp2/BasicDataSource.java#L732
Seems so.