Skip to content

Commit

Permalink
Add support for C3P0 connection pool tracing (#683)
Browse files Browse the repository at this point in the history
  • Loading branch information
CzyerChen authored Apr 26, 2024
1 parent 1a01047 commit d37ee27
Show file tree
Hide file tree
Showing 41 changed files with 2,229 additions and 0 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/plugins-jdk17-test.1.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ jobs:
- gateway-4.x-scenario
- httpexchange-scenario
- activemq-artemis-2.x-scenario
- c3p0-0.9.0.x-0.9.1.x-scenario
- c3p0-0.9.2.x-0.10.x-scenario
steps:
- uses: actions/checkout@v2
with:
Expand Down
1 change: 1 addition & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ Release Notes.

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

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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -244,4 +244,7 @@ public class ComponentsDefine {
public static final OfficialComponent NACOS = new OfficialComponent(150, "Nacos");

public static final OfficialComponent NETTY_HTTP = new OfficialComponent(151, "Netty-http");

public static final OfficialComponent C3P0 = new OfficialComponent(152, "c3p0");

}
49 changes: 49 additions & 0 deletions apm-sniffer/apm-sdk-plugin/c3p0-0.9.x-plugin/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ 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.
-->

<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">
<parent>
<artifactId>apm-sdk-plugin</artifactId>
<groupId>org.apache.skywalking</groupId>
<version>9.3.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

<artifactId>apm-c3p0-0.9.x-plugin</artifactId>
<packaging>jar</packaging>
<name>c3p0-0.9.x-plugin</name>

<properties>
<c3p0.version>0.9.5</c3p0.version>
</properties>

<dependencies>
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>${c3p0.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.skywalking</groupId>
<artifactId>apm-jdbc-commons</artifactId>
<version>${project.version}</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*
* 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.c3p0;

public class PoolConstants {
public static final String POOL_CONNECTION = "C3P0/Connection/";
public static final String METER_NAME = "datasource";
public static final String METER_TAG_NAME = "name";
public static final String METER_TAG_STATUS = "status";

//==================== METRICS ========================//
public static final String NUM_TOTAL_CONNECTIONS = "numTotalConnections";
public static final String NUM_BUSY_CONNECTIONS = "numBusyConnections";
public static final String NUM_IDLE_CONNECTIONS = "numIdleConnections";
public static final String MAX_IDLE_TIME = "maxIdleTime";
public static final String MIN_POOL_SIZE = "minPoolSize";
public static final String MAX_POOL_SIZE = "maxPoolSize";
public static final String INITIAL_POOL_SIZE = "initialPoolSize";
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/*
* 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.c3p0;

import org.apache.skywalking.apm.agent.core.context.ContextManager;
import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
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.network.trace.component.ComponentsDefine;

import java.lang.reflect.Method;

/**
* {@link PoolingConnectionCloseInterceptor} intercepted the method of C3P0 closing connection.
*/
public class PoolingConnectionCloseInterceptor implements InstanceMethodsAroundInterceptor {

@Override
public void beforeMethod(EnhancedInstance objInst,
Method method,
Object[] allArguments,
Class<?>[] argumentsTypes,
MethodInterceptResult result) throws Throwable {
AbstractSpan span = ContextManager.createLocalSpan(PoolConstants.POOL_CONNECTION + method.getName());
span.setComponent(ComponentsDefine.C3P0);
}

@Override
public Object afterMethod(EnhancedInstance objInst,
Method method,
Object[] allArguments,
Class<?>[] argumentsTypes,
Object ret) throws Throwable {
ContextManager.stopSpan();
return ret;
}

@Override
public void handleMethodException(EnhancedInstance objInst,
Method method,
Object[] allArguments,
Class<?>[] argumentsTypes,
Throwable t) {
ContextManager.activeSpan().errorOccurred().log(t);
}
}
Original file line number Diff line number Diff line change
@@ -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.c3p0;

import java.lang.reflect.Method;
import org.apache.skywalking.apm.agent.core.context.ContextManager;
import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
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.network.trace.component.ComponentsDefine;

/**
* {@link PoolingConnectionGetInterceptor} intercepted the method of C3P0 getting connection.
*/
public class PoolingConnectionGetInterceptor implements InstanceMethodsAroundInterceptor {

@Override
public void beforeMethod(EnhancedInstance objInst,
Method method,
Object[] allArguments,
Class<?>[] argumentsTypes,
MethodInterceptResult result) throws Throwable {
AbstractSpan span = ContextManager.createLocalSpan(PoolConstants.POOL_CONNECTION + method.getName());
span.setComponent(ComponentsDefine.C3P0);
}

@Override
public Object afterMethod(EnhancedInstance objInst,
Method method,
Object[] allArguments,
Class<?>[] argumentsTypes,
Object ret) throws Throwable {
ContextManager.stopSpan();
return ret;
}

@Override
public void handleMethodException(EnhancedInstance objInst,
Method method,
Object[] allArguments,
Class<?>[] argumentsTypes,
Throwable t) {
ContextManager.activeSpan().errorOccurred().log(t);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
/*
* 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.c3p0;

import com.mchange.v2.c3p0.C3P0Registry;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import java.lang.reflect.Method;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import java.util.function.Supplier;
import org.apache.skywalking.apm.agent.core.context.ContextManager;
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 org.apache.skywalking.apm.plugin.jdbc.connectionurl.parser.URLParser;
import org.apache.skywalking.apm.plugin.jdbc.trace.ConnectionInfo;

/**
* {@link PoolingCreationInterceptor} intercepted the method of pool creation.
*/
public class PoolingCreationInterceptor implements InstanceMethodsAroundInterceptor {
private static final Set<String> TOKEN_MAP = new HashSet<>(16);

@Override
public void beforeMethod(final EnhancedInstance enhancedInstance,
final Method method,
final Object[] objects,
final Class<?>[] classes,
final MethodInterceptResult methodInterceptResult) throws Throwable {

}

@Override
public Object afterMethod(final EnhancedInstance enhancedInstance,
final Method method,
final Object[] objects,
final Class<?>[] classes,
final Object ret) throws Throwable {
C3P0Registry.getPooledDataSources().forEach(obj -> {
ComboPooledDataSource pooledDataSource = (ComboPooledDataSource) obj;
if (!TOKEN_MAP.contains(pooledDataSource.getIdentityToken())) {
ConnectionInfo connectionInfo = URLParser.parser(pooledDataSource.getJdbcUrl());
String tagValue = connectionInfo.getDatabaseName() + "_" + connectionInfo.getDatabasePeer();
Map<String, Function<ComboPooledDataSource, Supplier<Double>>> metricMap = getMetrics();
metricMap.forEach(
(key, value) -> MeterFactory.gauge(PoolConstants.METER_NAME, value.apply(pooledDataSource))
.tag(PoolConstants.METER_TAG_NAME, tagValue)
.tag(PoolConstants.METER_TAG_STATUS, key)
.build());
TOKEN_MAP.add(pooledDataSource.getIdentityToken());
}
});
return ret;
}

@Override
public void handleMethodException(final EnhancedInstance enhancedInstance,
final Method method,
final Object[] objects,
final Class<?>[] classes,
final Throwable t) {
ContextManager.activeSpan().errorOccurred().log(t);
}

private Map<String, Function<ComboPooledDataSource, Supplier<Double>>> getMetrics() {
Map<String, Function<ComboPooledDataSource, Supplier<Double>>> metricMap = new HashMap<>();
metricMap.put(PoolConstants.NUM_TOTAL_CONNECTIONS, (ComboPooledDataSource pooledDataSource) -> () -> {
double numConnections = 0;
try {
numConnections = pooledDataSource.getNumConnections();
} catch (SQLException e) {
ContextManager.activeSpan().errorOccurred().log(e);
}
return numConnections;
});
metricMap.put(PoolConstants.NUM_BUSY_CONNECTIONS, (ComboPooledDataSource pooledDataSource) -> () -> {
double numBusyConnections = 0;
try {
numBusyConnections = pooledDataSource.getNumBusyConnections();
} catch (SQLException e) {
ContextManager.activeSpan().errorOccurred().log(e);
}
return numBusyConnections;
});
metricMap.put(PoolConstants.NUM_IDLE_CONNECTIONS, (ComboPooledDataSource pooledDataSource) -> () -> {
double numIdleConnections = 0;
try {
numIdleConnections = pooledDataSource.getNumIdleConnections();
} catch (SQLException e) {
ContextManager.activeSpan().errorOccurred().log(e);
}
return numIdleConnections;
});
metricMap.put(
PoolConstants.MAX_IDLE_TIME,
(ComboPooledDataSource pooledDataSource) -> () -> (double) pooledDataSource.getMaxIdleTime()
);
metricMap.put(
PoolConstants.MIN_POOL_SIZE,
(ComboPooledDataSource pooledDataSource) -> () -> (double) pooledDataSource.getMinPoolSize()
);
metricMap.put(
PoolConstants.MAX_POOL_SIZE,
(ComboPooledDataSource pooledDataSource) -> () -> (double) pooledDataSource.getMaxPoolSize()
);
metricMap.put(
PoolConstants.INITIAL_POOL_SIZE,
(ComboPooledDataSource pooledDataSource) -> () -> (double) pooledDataSource.getInitialPoolSize()
);
return metricMap;
}
}
Loading

0 comments on commit d37ee27

Please sign in to comment.