Skip to content

Commit d37ee27

Browse files
authored
Add support for C3P0 connection pool tracing (#683)
1 parent 1a01047 commit d37ee27

File tree

41 files changed

+2229
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+2229
-0
lines changed

.github/workflows/plugins-jdk17-test.1.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@ jobs:
6060
- gateway-4.x-scenario
6161
- httpexchange-scenario
6262
- activemq-artemis-2.x-scenario
63+
- c3p0-0.9.0.x-0.9.1.x-scenario
64+
- c3p0-0.9.2.x-0.10.x-scenario
6365
steps:
6466
- uses: actions/checkout@v2
6567
with:

CHANGES.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ Release Notes.
77

88
* Remove `idleCount` tag in Alibaba Druid meter plugin.
99
* Fix NPE in handleMethodException method of apm-jdk-threadpool-plugin.
10+
* Support for C3P0 connection pool tracing.
1011

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

apm-protocol/apm-network/src/main/java/org/apache/skywalking/apm/network/trace/component/ComponentsDefine.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,4 +244,7 @@ public class ComponentsDefine {
244244
public static final OfficialComponent NACOS = new OfficialComponent(150, "Nacos");
245245

246246
public static final OfficialComponent NETTY_HTTP = new OfficialComponent(151, "Netty-http");
247+
248+
public static final OfficialComponent C3P0 = new OfficialComponent(152, "c3p0");
249+
247250
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!--
3+
~ Licensed to the Apache Software Foundation (ASF) under one or more
4+
~ contributor license agreements. See the NOTICE file distributed with
5+
~ this work for additional information regarding copyright ownership.
6+
~ The ASF licenses this file to You under the Apache License, Version 2.0
7+
~ (the "License"); you may not use this file except in compliance with
8+
~ the License. You may obtain a copy of the License at
9+
~
10+
~ http://www.apache.org/licenses/LICENSE-2.0
11+
~
12+
~ Unless required by applicable law or agreed to in writing, software
13+
~ distributed under the License is distributed on an "AS IS" BASIS,
14+
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
~ See the License for the specific language governing permissions and
16+
~ limitations under the License.
17+
-->
18+
19+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
20+
<parent>
21+
<artifactId>apm-sdk-plugin</artifactId>
22+
<groupId>org.apache.skywalking</groupId>
23+
<version>9.3.0-SNAPSHOT</version>
24+
</parent>
25+
<modelVersion>4.0.0</modelVersion>
26+
27+
<artifactId>apm-c3p0-0.9.x-plugin</artifactId>
28+
<packaging>jar</packaging>
29+
<name>c3p0-0.9.x-plugin</name>
30+
31+
<properties>
32+
<c3p0.version>0.9.5</c3p0.version>
33+
</properties>
34+
35+
<dependencies>
36+
<dependency>
37+
<groupId>com.mchange</groupId>
38+
<artifactId>c3p0</artifactId>
39+
<version>${c3p0.version}</version>
40+
<scope>provided</scope>
41+
</dependency>
42+
<dependency>
43+
<groupId>org.apache.skywalking</groupId>
44+
<artifactId>apm-jdbc-commons</artifactId>
45+
<version>${project.version}</version>
46+
<scope>provided</scope>
47+
</dependency>
48+
</dependencies>
49+
</project>
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
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+
package org.apache.skywalking.apm.plugin.c3p0;
19+
20+
public class PoolConstants {
21+
public static final String POOL_CONNECTION = "C3P0/Connection/";
22+
public static final String METER_NAME = "datasource";
23+
public static final String METER_TAG_NAME = "name";
24+
public static final String METER_TAG_STATUS = "status";
25+
26+
//==================== METRICS ========================//
27+
public static final String NUM_TOTAL_CONNECTIONS = "numTotalConnections";
28+
public static final String NUM_BUSY_CONNECTIONS = "numBusyConnections";
29+
public static final String NUM_IDLE_CONNECTIONS = "numIdleConnections";
30+
public static final String MAX_IDLE_TIME = "maxIdleTime";
31+
public static final String MIN_POOL_SIZE = "minPoolSize";
32+
public static final String MAX_POOL_SIZE = "maxPoolSize";
33+
public static final String INITIAL_POOL_SIZE = "initialPoolSize";
34+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
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+
package org.apache.skywalking.apm.plugin.c3p0;
19+
20+
import org.apache.skywalking.apm.agent.core.context.ContextManager;
21+
import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
22+
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
23+
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
24+
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
25+
import org.apache.skywalking.apm.network.trace.component.ComponentsDefine;
26+
27+
import java.lang.reflect.Method;
28+
29+
/**
30+
* {@link PoolingConnectionCloseInterceptor} intercepted the method of C3P0 closing connection.
31+
*/
32+
public class PoolingConnectionCloseInterceptor implements InstanceMethodsAroundInterceptor {
33+
34+
@Override
35+
public void beforeMethod(EnhancedInstance objInst,
36+
Method method,
37+
Object[] allArguments,
38+
Class<?>[] argumentsTypes,
39+
MethodInterceptResult result) throws Throwable {
40+
AbstractSpan span = ContextManager.createLocalSpan(PoolConstants.POOL_CONNECTION + method.getName());
41+
span.setComponent(ComponentsDefine.C3P0);
42+
}
43+
44+
@Override
45+
public Object afterMethod(EnhancedInstance objInst,
46+
Method method,
47+
Object[] allArguments,
48+
Class<?>[] argumentsTypes,
49+
Object ret) throws Throwable {
50+
ContextManager.stopSpan();
51+
return ret;
52+
}
53+
54+
@Override
55+
public void handleMethodException(EnhancedInstance objInst,
56+
Method method,
57+
Object[] allArguments,
58+
Class<?>[] argumentsTypes,
59+
Throwable t) {
60+
ContextManager.activeSpan().errorOccurred().log(t);
61+
}
62+
}
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+
package org.apache.skywalking.apm.plugin.c3p0;
19+
20+
import java.lang.reflect.Method;
21+
import org.apache.skywalking.apm.agent.core.context.ContextManager;
22+
import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
23+
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
24+
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
25+
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
26+
import org.apache.skywalking.apm.network.trace.component.ComponentsDefine;
27+
28+
/**
29+
* {@link PoolingConnectionGetInterceptor} intercepted the method of C3P0 getting connection.
30+
*/
31+
public class PoolingConnectionGetInterceptor implements InstanceMethodsAroundInterceptor {
32+
33+
@Override
34+
public void beforeMethod(EnhancedInstance objInst,
35+
Method method,
36+
Object[] allArguments,
37+
Class<?>[] argumentsTypes,
38+
MethodInterceptResult result) throws Throwable {
39+
AbstractSpan span = ContextManager.createLocalSpan(PoolConstants.POOL_CONNECTION + method.getName());
40+
span.setComponent(ComponentsDefine.C3P0);
41+
}
42+
43+
@Override
44+
public Object afterMethod(EnhancedInstance objInst,
45+
Method method,
46+
Object[] allArguments,
47+
Class<?>[] argumentsTypes,
48+
Object ret) throws Throwable {
49+
ContextManager.stopSpan();
50+
return ret;
51+
}
52+
53+
@Override
54+
public void handleMethodException(EnhancedInstance objInst,
55+
Method method,
56+
Object[] allArguments,
57+
Class<?>[] argumentsTypes,
58+
Throwable t) {
59+
ContextManager.activeSpan().errorOccurred().log(t);
60+
}
61+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
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+
package org.apache.skywalking.apm.plugin.c3p0;
19+
20+
import com.mchange.v2.c3p0.C3P0Registry;
21+
import com.mchange.v2.c3p0.ComboPooledDataSource;
22+
import java.lang.reflect.Method;
23+
import java.sql.SQLException;
24+
import java.util.HashMap;
25+
import java.util.HashSet;
26+
import java.util.Map;
27+
import java.util.Set;
28+
import java.util.function.Function;
29+
import java.util.function.Supplier;
30+
import org.apache.skywalking.apm.agent.core.context.ContextManager;
31+
import org.apache.skywalking.apm.agent.core.meter.MeterFactory;
32+
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
33+
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
34+
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
35+
import org.apache.skywalking.apm.plugin.jdbc.connectionurl.parser.URLParser;
36+
import org.apache.skywalking.apm.plugin.jdbc.trace.ConnectionInfo;
37+
38+
/**
39+
* {@link PoolingCreationInterceptor} intercepted the method of pool creation.
40+
*/
41+
public class PoolingCreationInterceptor implements InstanceMethodsAroundInterceptor {
42+
private static final Set<String> TOKEN_MAP = new HashSet<>(16);
43+
44+
@Override
45+
public void beforeMethod(final EnhancedInstance enhancedInstance,
46+
final Method method,
47+
final Object[] objects,
48+
final Class<?>[] classes,
49+
final MethodInterceptResult methodInterceptResult) throws Throwable {
50+
51+
}
52+
53+
@Override
54+
public Object afterMethod(final EnhancedInstance enhancedInstance,
55+
final Method method,
56+
final Object[] objects,
57+
final Class<?>[] classes,
58+
final Object ret) throws Throwable {
59+
C3P0Registry.getPooledDataSources().forEach(obj -> {
60+
ComboPooledDataSource pooledDataSource = (ComboPooledDataSource) obj;
61+
if (!TOKEN_MAP.contains(pooledDataSource.getIdentityToken())) {
62+
ConnectionInfo connectionInfo = URLParser.parser(pooledDataSource.getJdbcUrl());
63+
String tagValue = connectionInfo.getDatabaseName() + "_" + connectionInfo.getDatabasePeer();
64+
Map<String, Function<ComboPooledDataSource, Supplier<Double>>> metricMap = getMetrics();
65+
metricMap.forEach(
66+
(key, value) -> MeterFactory.gauge(PoolConstants.METER_NAME, value.apply(pooledDataSource))
67+
.tag(PoolConstants.METER_TAG_NAME, tagValue)
68+
.tag(PoolConstants.METER_TAG_STATUS, key)
69+
.build());
70+
TOKEN_MAP.add(pooledDataSource.getIdentityToken());
71+
}
72+
});
73+
return ret;
74+
}
75+
76+
@Override
77+
public void handleMethodException(final EnhancedInstance enhancedInstance,
78+
final Method method,
79+
final Object[] objects,
80+
final Class<?>[] classes,
81+
final Throwable t) {
82+
ContextManager.activeSpan().errorOccurred().log(t);
83+
}
84+
85+
private Map<String, Function<ComboPooledDataSource, Supplier<Double>>> getMetrics() {
86+
Map<String, Function<ComboPooledDataSource, Supplier<Double>>> metricMap = new HashMap<>();
87+
metricMap.put(PoolConstants.NUM_TOTAL_CONNECTIONS, (ComboPooledDataSource pooledDataSource) -> () -> {
88+
double numConnections = 0;
89+
try {
90+
numConnections = pooledDataSource.getNumConnections();
91+
} catch (SQLException e) {
92+
ContextManager.activeSpan().errorOccurred().log(e);
93+
}
94+
return numConnections;
95+
});
96+
metricMap.put(PoolConstants.NUM_BUSY_CONNECTIONS, (ComboPooledDataSource pooledDataSource) -> () -> {
97+
double numBusyConnections = 0;
98+
try {
99+
numBusyConnections = pooledDataSource.getNumBusyConnections();
100+
} catch (SQLException e) {
101+
ContextManager.activeSpan().errorOccurred().log(e);
102+
}
103+
return numBusyConnections;
104+
});
105+
metricMap.put(PoolConstants.NUM_IDLE_CONNECTIONS, (ComboPooledDataSource pooledDataSource) -> () -> {
106+
double numIdleConnections = 0;
107+
try {
108+
numIdleConnections = pooledDataSource.getNumIdleConnections();
109+
} catch (SQLException e) {
110+
ContextManager.activeSpan().errorOccurred().log(e);
111+
}
112+
return numIdleConnections;
113+
});
114+
metricMap.put(
115+
PoolConstants.MAX_IDLE_TIME,
116+
(ComboPooledDataSource pooledDataSource) -> () -> (double) pooledDataSource.getMaxIdleTime()
117+
);
118+
metricMap.put(
119+
PoolConstants.MIN_POOL_SIZE,
120+
(ComboPooledDataSource pooledDataSource) -> () -> (double) pooledDataSource.getMinPoolSize()
121+
);
122+
metricMap.put(
123+
PoolConstants.MAX_POOL_SIZE,
124+
(ComboPooledDataSource pooledDataSource) -> () -> (double) pooledDataSource.getMaxPoolSize()
125+
);
126+
metricMap.put(
127+
PoolConstants.INITIAL_POOL_SIZE,
128+
(ComboPooledDataSource pooledDataSource) -> () -> (double) pooledDataSource.getInitialPoolSize()
129+
);
130+
return metricMap;
131+
}
132+
}

0 commit comments

Comments
 (0)