Add pool metrics support for Derby/Sybase/SQLite/DB2/OceanBase jdbc URL format in URLParser (#687)
diff --git a/CHANGES.md b/CHANGES.md
index fcde635..6b6c759 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -10,6 +10,7 @@
* Support for C3P0 connection pool tracing.
* Use a daemon thread to flush logs.
* Fix typos in `URLParser`.
+* Add support for `Derby`/`Sybase`/`SQLite`/`DB2`/`OceanBase` jdbc url format in `URLParser`.
All issues and pull requests are [here](https://github.com/apache/skywalking/milestone/213?closed=1)
diff --git a/apm-protocol/apm-network/src/main/java/org/apache/skywalking/apm/network/trace/component/ComponentsDefine.java b/apm-protocol/apm-network/src/main/java/org/apache/skywalking/apm/network/trace/component/ComponentsDefine.java
index 5364ff0..b7307eb 100755
--- a/apm-protocol/apm-network/src/main/java/org/apache/skywalking/apm/network/trace/component/ComponentsDefine.java
+++ b/apm-protocol/apm-network/src/main/java/org/apache/skywalking/apm/network/trace/component/ComponentsDefine.java
@@ -247,4 +247,15 @@
public static final OfficialComponent C3P0 = new OfficialComponent(152, "c3p0");
+ public static final OfficialComponent DERBY_JDBC_DRIVER = new OfficialComponent(153, "Derby-jdbc-driver");
+
+ public static final OfficialComponent SQLITE_JDBC_DRIVER = new OfficialComponent(154, "Sqlite-jdbc-driver");
+
+ public static final OfficialComponent DB2_JDBC_DRIVER = new OfficialComponent(155, "Db2-jdbc-driver");
+
+ public static final OfficialComponent SYBASE_JDBC_DRIVER = new OfficialComponent(156, "Sybase-jdbc-driver");
+
+ public static final OfficialComponent OCEANBASE_JDBC_DRIVER = new OfficialComponent(157, "OceanBase-jdbc-driver");
+
+
}
diff --git a/apm-sniffer/apm-sdk-plugin/jdbc-commons/src/main/java/org/apache/skywalking/apm/plugin/jdbc/connectionurl/parser/Db2URLParser.java b/apm-sniffer/apm-sdk-plugin/jdbc-commons/src/main/java/org/apache/skywalking/apm/plugin/jdbc/connectionurl/parser/Db2URLParser.java
new file mode 100644
index 0000000..8fe2b36
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/jdbc-commons/src/main/java/org/apache/skywalking/apm/plugin/jdbc/connectionurl/parser/Db2URLParser.java
@@ -0,0 +1,129 @@
+/*
+ * 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.jdbc.connectionurl.parser;
+
+import org.apache.skywalking.apm.network.trace.component.ComponentsDefine;
+import org.apache.skywalking.apm.plugin.jdbc.trace.ConnectionInfo;
+
+public class Db2URLParser extends AbstractURLParser {
+ private static final String DEFAULT_HOST = "localhost";
+ private static final int DEFAULT_PORT = 50000;
+ private static final String DB_TYPE = "DB2";
+ private static final String JDBC_PREFIX = "jdbc:db2:";
+
+ public Db2URLParser(String url) {
+ super(url);
+ }
+
+ @Override
+ protected URLLocation fetchDatabaseHostsIndexRange() {
+ int hostLabelStartIndex = url.indexOf("//");
+ if (hostLabelStartIndex == -1) {
+ return null;
+ }
+ int hostLabelEndIndex = url.indexOf("/", hostLabelStartIndex + 2);
+ int hostLabelEndIndexWithParameter = url.indexOf(":", hostLabelEndIndex + 1);
+ if (hostLabelEndIndex == -1) {
+ hostLabelEndIndex = hostLabelEndIndexWithParameter;
+ }
+ if (hostLabelEndIndexWithParameter < hostLabelEndIndex && hostLabelEndIndexWithParameter != -1) {
+ hostLabelEndIndex = hostLabelEndIndexWithParameter;
+ }
+ if (hostLabelEndIndex == -1) {
+ hostLabelEndIndex = url.length();
+ }
+ return new URLLocation(hostLabelStartIndex + 2, hostLabelEndIndex);
+ }
+
+ protected String fetchDatabaseNameFromURL(int startSize) {
+ URLLocation hostsLocation = fetchDatabaseNameIndexRange(startSize);
+ if (hostsLocation == null) {
+ return "";
+ }
+ return url.substring(hostsLocation.startIndex(), hostsLocation.endIndex());
+ }
+
+ protected URLLocation fetchDatabaseNameIndexRange(int startSize) {
+ int databaseStartTag = url.indexOf("/", startSize);
+ int parameterStartTag = url.indexOf(":", startSize);
+ if (parameterStartTag < databaseStartTag && parameterStartTag != -1) {
+ return null;
+ }
+ if (databaseStartTag == -1) {
+ databaseStartTag = startSize - 1;
+ }
+ int databaseEndTag = url.indexOf(":", startSize);
+ if (databaseEndTag == -1) {
+ databaseEndTag = url.length();
+ }
+ return new URLLocation(databaseStartTag + 1, databaseEndTag);
+ }
+
+ @Override
+ protected URLLocation fetchDatabaseNameIndexRange() {
+ int databaseStartTag = url.lastIndexOf("/");
+ int databaseEndTag = url.indexOf(":", databaseStartTag);
+ if (databaseEndTag == -1) {
+ databaseEndTag = url.length();
+ }
+ return new URLLocation(databaseStartTag + 1, databaseEndTag);
+ }
+
+ @Override
+ public ConnectionInfo parse() {
+ URLLocation location = fetchDatabaseHostsIndexRange();
+ if (location == null) {
+ return new ConnectionInfo(
+ ComponentsDefine.DB2_JDBC_DRIVER, DB_TYPE, DEFAULT_HOST, DEFAULT_PORT,
+ fetchDatabaseNameFromURL(JDBC_PREFIX.length())
+ );
+ }
+ String hosts = url.substring(location.startIndex(), location.endIndex());
+ String[] hostSegment = hosts.split(",");
+ if (hostSegment.length > 1) {
+ StringBuilder sb = new StringBuilder();
+ for (String host : hostSegment) {
+ if (host.split(":").length == 1) {
+ sb.append(host).append(":").append(DEFAULT_PORT).append(",");
+ } else {
+ sb.append(host).append(",");
+ }
+ }
+ return new ConnectionInfo(
+ ComponentsDefine.DB2_JDBC_DRIVER, DB_TYPE, sb.substring(0, sb.length() - 1),
+ fetchDatabaseNameFromURL()
+ );
+ } else {
+ String[] hostAndPort = hostSegment[0].split(":");
+ if (hostAndPort.length != 1) {
+ return new ConnectionInfo(
+ ComponentsDefine.DB2_JDBC_DRIVER, DB_TYPE, hostAndPort[0], Integer.valueOf(hostAndPort[1]),
+ fetchDatabaseNameFromURL(location
+ .endIndex())
+ );
+ } else {
+ return new ConnectionInfo(
+ ComponentsDefine.DB2_JDBC_DRIVER, DB_TYPE, hostAndPort[0], DEFAULT_PORT,
+ fetchDatabaseNameFromURL(location
+ .endIndex())
+ );
+ }
+ }
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/jdbc-commons/src/main/java/org/apache/skywalking/apm/plugin/jdbc/connectionurl/parser/DerbyURLParser.java b/apm-sniffer/apm-sdk-plugin/jdbc-commons/src/main/java/org/apache/skywalking/apm/plugin/jdbc/connectionurl/parser/DerbyURLParser.java
new file mode 100644
index 0000000..dd96b8e
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/jdbc-commons/src/main/java/org/apache/skywalking/apm/plugin/jdbc/connectionurl/parser/DerbyURLParser.java
@@ -0,0 +1,197 @@
+/*
+ * 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.jdbc.connectionurl.parser;
+
+import org.apache.skywalking.apm.network.trace.component.ComponentsDefine;
+import org.apache.skywalking.apm.plugin.jdbc.trace.ConnectionInfo;
+
+public class DerbyURLParser extends AbstractURLParser {
+
+ private static final String DEFAULT_HOST = "localhost";
+ private static final int DEFAULT_PORT = 1527;
+ private static final String DB_TYPE = "Derby";
+ private static final String DERBY_JDBC_URL_PREFIX = "jdbc:derby";
+ /**
+ * Flag that running with directory mode.
+ */
+ private static final String DIRECTORY_MODE_FLAG = "derby:directory";
+ /**
+ * Flag that running with memory mode.
+ */
+ private static final String MEMORY_MODE_FLAG = "derby:memory";
+ /**
+ * Flag that running with classpath mode.
+ */
+ private static final String CLASSPATH_MODE_FLAG = "derby:classpath";
+ /**
+ * Flag that running with jar mode.
+ */
+ private static final String JAR_MODE_FLAG = "derby:jar";
+
+ public DerbyURLParser(String url) {
+ super(url);
+ }
+
+ /**
+ * Fetch range index that the database name from connection url if Derby database running in client/server
+ * environment. eg: jdbc:derby://host[:port]/[databaseName][;attribute=value]*
+ *
+ * @return range index that the database name.
+ */
+ @Override
+ protected URLLocation fetchDatabaseHostsIndexRange() {
+ int hostLabelStartIndex = url.indexOf("//");
+ int hostLabelEndIndex = url.indexOf("/", hostLabelStartIndex + 2);
+ return new URLLocation(hostLabelStartIndex + 2, hostLabelEndIndex);
+ }
+
+ @Override
+ protected URLLocation fetchDatabaseNameIndexRange() {
+ int databaseEndTag = url.indexOf(";");
+ if (databaseEndTag == -1) {
+ databaseEndTag = url.length();
+ }
+ int databaseStartTag = url.lastIndexOf("\\");
+ if (databaseStartTag == -1) {
+ databaseStartTag = url.lastIndexOf("/");
+ }
+ if (url.indexOf(":", databaseStartTag) != -1) {
+ databaseStartTag = url.indexOf(":", databaseStartTag);
+ }
+ return new URLLocation(databaseStartTag + 1, databaseEndTag);
+ }
+
+ @Override
+ public ConnectionInfo parse() {
+ int[] databaseNameRangeIndex = fetchDatabaseNameRangeIndexForSubProtocol(DIRECTORY_MODE_FLAG);
+ if (databaseNameRangeIndex != null) {
+ return defaultConnection(databaseNameRangeIndex);
+ }
+ databaseNameRangeIndex = fetchDatabaseNameRangeIndexForSubProtocol(MEMORY_MODE_FLAG);
+ if (databaseNameRangeIndex != null) {
+ return defaultConnection(databaseNameRangeIndex);
+ }
+ databaseNameRangeIndex = fetchDatabaseNameRangeIndexForSubProtocol(CLASSPATH_MODE_FLAG);
+ if (databaseNameRangeIndex != null) {
+ return defaultConnection(databaseNameRangeIndex);
+ }
+ databaseNameRangeIndex = fetchDatabaseNameRangeIndexForSubProtocol(JAR_MODE_FLAG);
+ if (databaseNameRangeIndex != null) {
+ return defaultConnection(databaseNameRangeIndex);
+ }
+ databaseNameRangeIndex = fetchDatabaseNameRangeIndexWithoutHosts();
+ if (databaseNameRangeIndex != null) {
+ return defaultConnection(databaseNameRangeIndex);
+ }
+ String[] hostAndPort = fetchDatabaseHostsFromURL().split(":");
+ if (hostAndPort.length == 1) {
+ return new ConnectionInfo(
+ ComponentsDefine.DERBY_JDBC_DRIVER, DB_TYPE, hostAndPort[0], DEFAULT_PORT, fetchDatabaseNameFromURL());
+ } else {
+ return new ConnectionInfo(
+ ComponentsDefine.DERBY_JDBC_DRIVER, DB_TYPE, hostAndPort[0], Integer.valueOf(hostAndPort[1]),
+ fetchDatabaseNameFromURL()
+ );
+ }
+ }
+
+ /**
+ * Fetch range index that the database name from connection url if Derby database running in embedded environment.
+ * eg: jdbc:derby:[databaseName][;attribute=value]*
+ *
+ * @return range index that the database name.
+ */
+ private int[] fetchDatabaseNameRangeIndexWithoutHosts() {
+ if (url.contains("//")) {
+ return null;
+ }
+ int fileLabelIndex = url.indexOf(DERBY_JDBC_URL_PREFIX);
+ int parameterLabelIndex = url.indexOf(";");
+ if (parameterLabelIndex == -1) {
+ parameterLabelIndex = url.length();
+ }
+
+ if (fileLabelIndex != -1) {
+ int pathLabelIndexForLinux = url.lastIndexOf("/");
+ if (pathLabelIndexForLinux != -1 && pathLabelIndexForLinux > fileLabelIndex) {
+ return new int[] {
+ pathLabelIndexForLinux + 1,
+ parameterLabelIndex
+ };
+ }
+ int pathLabelIndexForWin = url.lastIndexOf("\\");
+ if (pathLabelIndexForWin != -1 && pathLabelIndexForWin > fileLabelIndex) {
+ return new int[] {
+ pathLabelIndexForWin + 1,
+ parameterLabelIndex
+ };
+ }
+ return new int[] {
+ fileLabelIndex + DERBY_JDBC_URL_PREFIX.length() + 1,
+ parameterLabelIndex
+ };
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Fetch range index that the database name from connection url if Derby database running with subprotocol. eg:
+ * jdbc:derby:subprotocol:[databaseName][;attribute=value]*
+ *
+ * @return range index that the database name.
+ */
+ private int[] fetchDatabaseNameRangeIndexForSubProtocol(String mode) {
+ int fileLabelIndex = url.indexOf(mode);
+ int parameterLabelIndex = url.indexOf(";", fileLabelIndex);
+ if (parameterLabelIndex == -1) {
+ parameterLabelIndex = url.length();
+ }
+
+ if (fileLabelIndex != -1) {
+ int pathLabelIndexForLinux = url.lastIndexOf("/");
+ if (pathLabelIndexForLinux != -1 && pathLabelIndexForLinux > fileLabelIndex) {
+ return new int[] {
+ pathLabelIndexForLinux + 1,
+ parameterLabelIndex
+ };
+ }
+ int pathLabelIndexForWin = url.lastIndexOf("\\");
+ if (pathLabelIndexForWin != -1 && pathLabelIndexForWin > fileLabelIndex) {
+ return new int[] {
+ pathLabelIndexForWin + 1,
+ parameterLabelIndex
+ };
+ }
+ return new int[] {
+ fileLabelIndex + mode.length() + 1,
+ parameterLabelIndex
+ };
+ } else {
+ return null;
+ }
+ }
+
+ private ConnectionInfo defaultConnection(int[] databaseNameRangeIndex) {
+ return new ConnectionInfo(
+ ComponentsDefine.DERBY_JDBC_DRIVER, DB_TYPE, DEFAULT_HOST, -1,
+ fetchDatabaseNameFromURL(databaseNameRangeIndex)
+ );
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/jdbc-commons/src/main/java/org/apache/skywalking/apm/plugin/jdbc/connectionurl/parser/OceanBaseURLParser.java b/apm-sniffer/apm-sdk-plugin/jdbc-commons/src/main/java/org/apache/skywalking/apm/plugin/jdbc/connectionurl/parser/OceanBaseURLParser.java
new file mode 100644
index 0000000..f459c26
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/jdbc-commons/src/main/java/org/apache/skywalking/apm/plugin/jdbc/connectionurl/parser/OceanBaseURLParser.java
@@ -0,0 +1,27 @@
+/*
+ * 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.jdbc.connectionurl.parser;
+
+import org.apache.skywalking.apm.network.trace.component.ComponentsDefine;
+
+public class OceanBaseURLParser extends MysqlURLParser {
+ public OceanBaseURLParser(String url) {
+ super(url, "OceanBase", ComponentsDefine.OCEANBASE_JDBC_DRIVER, 2881);
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/jdbc-commons/src/main/java/org/apache/skywalking/apm/plugin/jdbc/connectionurl/parser/SqliteURLParser.java b/apm-sniffer/apm-sdk-plugin/jdbc-commons/src/main/java/org/apache/skywalking/apm/plugin/jdbc/connectionurl/parser/SqliteURLParser.java
new file mode 100644
index 0000000..21f4449
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/jdbc-commons/src/main/java/org/apache/skywalking/apm/plugin/jdbc/connectionurl/parser/SqliteURLParser.java
@@ -0,0 +1,57 @@
+/*
+ * 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.jdbc.connectionurl.parser;
+
+import org.apache.skywalking.apm.network.trace.component.ComponentsDefine;
+import org.apache.skywalking.apm.plugin.jdbc.trace.ConnectionInfo;
+
+public class SqliteURLParser extends AbstractURLParser {
+ private static final String DEFAULT_HOST = "localhost";
+ private static final int DEFAULT_PORT = -1;
+ private static final String DB_TYPE = "Sqlite";
+
+ public SqliteURLParser(String url) {
+ super(url);
+ }
+
+ @Override
+ protected URLLocation fetchDatabaseHostsIndexRange() {
+ return null;
+ }
+
+ @Override
+ protected URLLocation fetchDatabaseNameIndexRange() {
+ int databaseStartTag = url.lastIndexOf("/");
+ if (databaseStartTag == -1) {
+ databaseStartTag = url.lastIndexOf(":");
+ }
+ int databaseEndTag = url.indexOf("?");
+ if (databaseEndTag == -1) {
+ databaseEndTag = url.length();
+ }
+
+ return new URLLocation(databaseStartTag + 1, databaseEndTag);
+ }
+
+ @Override
+ public ConnectionInfo parse() {
+ return new ConnectionInfo(
+ ComponentsDefine.SQLITE_JDBC_DRIVER, DB_TYPE, DEFAULT_HOST, DEFAULT_PORT, fetchDatabaseNameFromURL());
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/jdbc-commons/src/main/java/org/apache/skywalking/apm/plugin/jdbc/connectionurl/parser/SybaseURLParser.java b/apm-sniffer/apm-sdk-plugin/jdbc-commons/src/main/java/org/apache/skywalking/apm/plugin/jdbc/connectionurl/parser/SybaseURLParser.java
new file mode 100644
index 0000000..dfc8a57
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/jdbc-commons/src/main/java/org/apache/skywalking/apm/plugin/jdbc/connectionurl/parser/SybaseURLParser.java
@@ -0,0 +1,114 @@
+/*
+ * 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.jdbc.connectionurl.parser;
+
+import org.apache.skywalking.apm.network.trace.component.ComponentsDefine;
+import org.apache.skywalking.apm.plugin.jdbc.trace.ConnectionInfo;
+
+public class SybaseURLParser extends AbstractURLParser {
+ private static final int DEFAULT_PORT = 5000;
+ private static final String DB_TYPE = "Sybase";
+ private static final String JDBC_PREFIX = "jdbc:sybase:Tds:";
+
+ public SybaseURLParser(String url) {
+ super(url);
+ }
+
+ @Override
+ protected URLLocation fetchDatabaseHostsIndexRange() {
+ int hostLabelStartIndex = JDBC_PREFIX.length();
+ int hostLabelEndIndex = url.indexOf("/", hostLabelStartIndex);
+ int hostLabelEndIndexWithParameter = url.indexOf("?", hostLabelStartIndex);
+ if (hostLabelEndIndex == -1) {
+ hostLabelEndIndex = hostLabelEndIndexWithParameter;
+ }
+ if (hostLabelEndIndexWithParameter < hostLabelEndIndex && hostLabelEndIndexWithParameter != -1) {
+ hostLabelEndIndex = hostLabelEndIndexWithParameter;
+ }
+ if (hostLabelEndIndex == -1) {
+ hostLabelEndIndex = url.length();
+ }
+ return new URLLocation(hostLabelStartIndex, hostLabelEndIndex);
+ }
+
+ protected String fetchDatabaseNameFromURL(int startSize) {
+ URLLocation hostsLocation = fetchDatabaseNameIndexRange(startSize);
+ if (hostsLocation == null) {
+ return "";
+ }
+ return url.substring(hostsLocation.startIndex(), hostsLocation.endIndex());
+ }
+
+ protected URLLocation fetchDatabaseNameIndexRange(int startSize) {
+ int databaseStartTag = url.indexOf("/", startSize);
+ int parameterStartTag = url.indexOf("?", startSize);
+ if (parameterStartTag < databaseStartTag && parameterStartTag != -1) {
+ return null;
+ }
+ if (databaseStartTag == -1) {
+ return null;
+ }
+ int databaseEndTag = url.indexOf("?", databaseStartTag);
+ if (databaseEndTag == -1) {
+ databaseEndTag = url.length();
+ }
+ return new URLLocation(databaseStartTag + 1, databaseEndTag);
+ }
+
+ @Override
+ protected URLLocation fetchDatabaseNameIndexRange() {
+ int databaseStartTag = url.lastIndexOf("/");
+ int databaseEndTag = url.indexOf("?", databaseStartTag);
+ if (databaseEndTag == -1) {
+ databaseEndTag = url.length();
+ }
+ return new URLLocation(databaseStartTag + 1, databaseEndTag);
+ }
+
+ @Override
+ public ConnectionInfo parse() {
+ URLLocation location = fetchDatabaseHostsIndexRange();
+ String hosts = url.substring(location.startIndex(), location.endIndex());
+ String[] hostSegment = hosts.split(",");
+ if (hostSegment.length > 1) {
+ StringBuilder sb = new StringBuilder();
+ for (String host : hostSegment) {
+ if (host.split(":").length == 1) {
+ sb.append(host).append(":").append(DEFAULT_PORT).append(",");
+ } else {
+ sb.append(host).append(",");
+ }
+ }
+ return new ConnectionInfo(ComponentsDefine.SYBASE_JDBC_DRIVER, DB_TYPE, sb.substring(0, sb.length() - 1), fetchDatabaseNameFromURL());
+ } else {
+ String[] hostAndPort = hostSegment[0].split(":");
+ if (hostAndPort.length != 1) {
+ return new ConnectionInfo(
+ ComponentsDefine.SYBASE_JDBC_DRIVER, DB_TYPE, hostAndPort[0], Integer.valueOf(hostAndPort[1]),
+ fetchDatabaseNameFromURL(location
+ .endIndex())
+ );
+ } else {
+ return new ConnectionInfo(
+ ComponentsDefine.SYBASE_JDBC_DRIVER, DB_TYPE, hostAndPort[0], DEFAULT_PORT, fetchDatabaseNameFromURL(location
+ .endIndex()));
+ }
+ }
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/jdbc-commons/src/main/java/org/apache/skywalking/apm/plugin/jdbc/connectionurl/parser/URLParser.java b/apm-sniffer/apm-sdk-plugin/jdbc-commons/src/main/java/org/apache/skywalking/apm/plugin/jdbc/connectionurl/parser/URLParser.java
index eab319f..cb79d58 100644
--- a/apm-sniffer/apm-sdk-plugin/jdbc-commons/src/main/java/org/apache/skywalking/apm/plugin/jdbc/connectionurl/parser/URLParser.java
+++ b/apm-sniffer/apm-sdk-plugin/jdbc-commons/src/main/java/org/apache/skywalking/apm/plugin/jdbc/connectionurl/parser/URLParser.java
@@ -36,6 +36,11 @@
private static final String KYLIN_JDBC_URL_PREFIX = "jdbc:kylin";
private static final String IMPALA_JDBC_URL_PREFIX = "jdbc:impala";
private static final String CLICKHOUSE_JDBC_URL_PREFIX = "jdbc:clickhouse";
+ private static final String DERBY_JDBC_URL_PREFIX = "jdbc:derby:";
+ private static final String SQLITE_JDBC_URL_PREFIX = "jdbc:sqlite:";
+ private static final String DB2_JDBC_URL_PREFIIX = "jdbc:db2:";
+ private static final String SYBASE_JDBC_URL_PREFIX = "jdbc:sybase:tds:";
+ private static final String OCEANBASE_JDBC_URL_PREFIX = "jdbc:oceanbase:";
public static ConnectionInfo parser(String url) {
ConnectionURLParser parser = null;
@@ -60,6 +65,16 @@
parser = new ImpalaJdbcURLParser(url);
} else if (lowerCaseUrl.startsWith(CLICKHOUSE_JDBC_URL_PREFIX)) {
parser = new ClickHouseURLParser(url);
+ } else if (lowerCaseUrl.startsWith(DERBY_JDBC_URL_PREFIX)) {
+ parser = new DerbyURLParser(url);
+ } else if (lowerCaseUrl.startsWith(SQLITE_JDBC_URL_PREFIX)) {
+ parser = new SqliteURLParser(url);
+ } else if (lowerCaseUrl.startsWith(DB2_JDBC_URL_PREFIIX)) {
+ parser = new Db2URLParser(url);
+ } else if (lowerCaseUrl.startsWith(SYBASE_JDBC_URL_PREFIX)) {
+ parser = new SybaseURLParser(url);
+ } else if (lowerCaseUrl.startsWith(OCEANBASE_JDBC_URL_PREFIX)) {
+ parser = new OceanBaseURLParser(url);
}
return parser.parse();
}
diff --git a/apm-sniffer/apm-sdk-plugin/jdbc-commons/src/test/java/org/apache/skywalking/apm/plugin/jdbc/connectionurl/parser/URLParserTest.java b/apm-sniffer/apm-sdk-plugin/jdbc-commons/src/test/java/org/apache/skywalking/apm/plugin/jdbc/connectionurl/parser/URLParserTest.java
index f679f05..48715ad 100644
--- a/apm-sniffer/apm-sdk-plugin/jdbc-commons/src/test/java/org/apache/skywalking/apm/plugin/jdbc/connectionurl/parser/URLParserTest.java
+++ b/apm-sniffer/apm-sdk-plugin/jdbc-commons/src/test/java/org/apache/skywalking/apm/plugin/jdbc/connectionurl/parser/URLParserTest.java
@@ -280,4 +280,139 @@
assertThat(connectionInfo.getDatabaseName(), is("testdb"));
assertThat(connectionInfo.getDatabasePeer(), is("[2001:db8::1234]:5432,[2001:db8::1235]:5432"));
}
-}
+
+ @Test
+ public void testParseOceanBaseJDBCURL() {
+ ConnectionInfo connectionInfo = new URLParser().parser(
+ "jdbc:oceanbase://localhost:2881/mydb?user=root@sys&password=pass&pool=false&useBulkStmts=true&rewriteBatchedStatements=false&useServerPrepStmts=true");
+ assertThat(connectionInfo.getDBType(), is("OceanBase"));
+ assertThat(connectionInfo.getDatabaseName(), is("mydb"));
+ assertThat(connectionInfo.getDatabasePeer(), is("localhost:2881"));
+ }
+
+ @Test
+ public void testParseOceanBaseJDBCURLWithMultiHosts() {
+ ConnectionInfo connectionInfo = new URLParser().parser(
+ "jdbc:oceanbase://primaryhost:2888,secondaryhost1,secondaryhost2/mydb?user=root@sys&password=pass&pool=false&useBulkStmts=true&rewriteBatchedStatements=false&useServerPrepStmts=true");
+ assertThat(connectionInfo.getDBType(), is("OceanBase"));
+ assertThat(connectionInfo.getDatabaseName(), is("mydb"));
+ assertThat(connectionInfo.getDatabasePeer(), is("primaryhost:2888,secondaryhost1:2881,secondaryhost2:2881"));
+ }
+
+ @Test
+ public void testParseDerbyJDBCURLWithDirMode() {
+ ConnectionInfo connectionInfo = new URLParser().parser(
+ "jdbc:derby:directory:mydb");
+ assertThat(connectionInfo.getDBType(), is("Derby"));
+ assertThat(connectionInfo.getDatabaseName(), is("mydb"));
+ assertThat(connectionInfo.getDatabasePeer(), is("localhost:-1"));
+ }
+
+ @Test
+ public void testParseDerbyJDBCURLWithMemMode() {
+ ConnectionInfo connectionInfo = new URLParser().parser(
+ "jdbc:derby:memory:mydb;create=true");
+ assertThat(connectionInfo.getDBType(), is("Derby"));
+ assertThat(connectionInfo.getDatabaseName(), is("mydb"));
+ assertThat(connectionInfo.getDatabasePeer(), is("localhost:-1"));
+ }
+
+ @Test
+ public void testParseDerbyJDBCURLWithClassPathMode() {
+ ConnectionInfo connectionInfo = new URLParser().parser(
+ "jdbc:derby:classpath:/test/mydb");
+ assertThat(connectionInfo.getDBType(), is("Derby"));
+ assertThat(connectionInfo.getDatabaseName(), is("mydb"));
+ assertThat(connectionInfo.getDatabasePeer(), is("localhost:-1"));
+ }
+
+ @Test
+ public void testParseDerbyJDBCURLWithJarMode() {
+ ConnectionInfo connectionInfo = new URLParser().parser(
+ "jdbc:derby:jar:(C:/dbs.jar)test/mydb");
+ assertThat(connectionInfo.getDBType(), is("Derby"));
+ assertThat(connectionInfo.getDatabaseName(), is("mydb"));
+ assertThat(connectionInfo.getDatabasePeer(), is("localhost:-1"));
+ }
+
+ @Test
+ public void testParseDerbyJDBCURLWithEmbeddedMode() {
+ ConnectionInfo connectionInfo = new URLParser().parser(
+ "jdbc:derby:test/mydb;create=true");
+ assertThat(connectionInfo.getDBType(), is("Derby"));
+ assertThat(connectionInfo.getDatabaseName(), is("mydb"));
+ assertThat(connectionInfo.getDatabasePeer(), is("localhost:-1"));
+ }
+
+ @Test
+ public void testParseDerbyJDBCURLWithMemModeAndClientServerMode() {
+ ConnectionInfo connectionInfo = new URLParser().parser(
+ "jdbc:derby://localhost:1527/memory:/test/mydb;create=true");
+ assertThat(connectionInfo.getDBType(), is("Derby"));
+ assertThat(connectionInfo.getDatabaseName(), is("mydb"));
+ assertThat(connectionInfo.getDatabasePeer(), is("localhost:1527"));
+ }
+
+ @Test
+ public void testParseDerbyJDBCURLWithClientServerMode() {
+ ConnectionInfo connectionInfo = new URLParser().parser(
+ "jdbc:derby://localhost:1527/mydb;create=true;user=root;password=pass");
+ assertThat(connectionInfo.getDBType(), is("Derby"));
+ assertThat(connectionInfo.getDatabaseName(), is("mydb"));
+ assertThat(connectionInfo.getDatabasePeer(), is("localhost:1527"));
+ }
+
+ @Test
+ public void testParseDB2JDBCURL() {
+ ConnectionInfo connectionInfo = new URLParser().parser(
+ "jdbc:db2://localhost:50000/mydb:user=root;password=pass");
+ assertThat(connectionInfo.getDBType(), is("DB2"));
+ assertThat(connectionInfo.getDatabaseName(), is("mydb"));
+ assertThat(connectionInfo.getDatabasePeer(), is("localhost:50000"));
+ }
+
+ @Test
+ public void testParseDB2JDBCURLWithoutHost() {
+ ConnectionInfo connectionInfo = new URLParser().parser(
+ "jdbc:db2:mydb:user=root;password=pass");
+ assertThat(connectionInfo.getDBType(), is("DB2"));
+ assertThat(connectionInfo.getDatabaseName(), is("mydb"));
+ assertThat(connectionInfo.getDatabasePeer(), is("localhost:50000"));
+ }
+
+ @Test
+ public void testParseSqliteJDBCURL() {
+ ConnectionInfo connectionInfo = new URLParser().parser(
+ "jdbc:sqlite:C/test/mydb.db");
+ assertThat(connectionInfo.getDBType(), is("Sqlite"));
+ assertThat(connectionInfo.getDatabaseName(), is("mydb.db"));
+ assertThat(connectionInfo.getDatabasePeer(), is("localhost:-1"));
+ }
+
+ @Test
+ public void testParseSqliteJDBCURLWithMem() {
+ ConnectionInfo connectionInfo = new URLParser().parser(
+ "jdbc:sqlite::memory:?jdbc.explicit_readonly=true");
+ assertThat(connectionInfo.getDBType(), is("Sqlite"));
+ assertThat(connectionInfo.getDatabaseName(), is(""));
+ assertThat(connectionInfo.getDatabasePeer(), is("localhost:-1"));
+ }
+
+ @Test
+ public void testParseSqliteJDBCURLWithResource() {
+ ConnectionInfo connectionInfo = new URLParser().parser(
+ "jdbc:sqlite::resource:org/test/mydb.db");
+ assertThat(connectionInfo.getDBType(), is("Sqlite"));
+ assertThat(connectionInfo.getDatabaseName(), is("mydb.db"));
+ assertThat(connectionInfo.getDatabasePeer(), is("localhost:-1"));
+ }
+
+ @Test
+ public void testParseSybaseJDBCURL() {
+ ConnectionInfo connectionInfo = new URLParser().parser(
+ "jdbc:sybase:Tds:localhost:5000/mydb?charset=utf-8");
+ assertThat(connectionInfo.getDBType(), is("Sybase"));
+ assertThat(connectionInfo.getDatabaseName(), is("mydb"));
+ assertThat(connectionInfo.getDatabasePeer(), is("localhost:5000"));
+ }
+}
\ No newline at end of file
diff --git a/docs/en/setup/service-agent/java-agent/Supported-list.md b/docs/en/setup/service-agent/java-agent/Supported-list.md
index a51d267..9b21ea1 100644
--- a/docs/en/setup/service-agent/java-agent/Supported-list.md
+++ b/docs/en/setup/service-agent/java-agent/Supported-list.md
@@ -168,10 +168,27 @@
* [Jetty](https://github.com/eclipse/jetty.project) 9.1.x -> 11.x
* [Grizzly](https://github.com/eclipse-ee4j/grizzly) 2.3.x -> 4.x
* Connection Pool
- * [Apache Commons DBCP](https://github.com/apache/commons-dbcp) 2.x
- * [Alibaba Druid](https://github.com/alibaba/druid) 1.x
- * [HikariCP](https://github.com/brettwooldridge/HikariCP) 3.x -> 4.x
- * [C3P0](https://github.com/swaldman/c3p0) 0.9.0 -> 0.10.0
+ * Supported JDBC drviers
+ * [MySQL](https://www.mysql.com/)
+ * [Oracle](https://www.oracle.com/)
+ * [H2](https://h2database.com/html/main.html)
+ * [PostgreSQL](https://www.postgresql.org/)
+ * [MariaDB](https://mariadb.org/)
+ * [SQL Server](https://www.microsoft.com/en-us/sql-server/)
+ * [Apache Kylin](https://kylin.apache.org/)
+ * [Impala](https://impala.apache.org/)
+ * [ClickHouse](https://clickhouse.com/)
+ * [Derby](https://db.apache.org/derby/)
+ * [SQLite](https://www.sqlite.org/index.html)
+ * [DB2](https://www.ibm.com/products/db2/database)
+ * Sybase
+ * [OceanBase](https://www.oceanbase.com/)
+ * Supported Connection Pool Frameworks
+ * [Apache Commons DBCP](https://github.com/apache/commons-dbcp) 2.x
+ * [Alibaba Druid](https://github.com/alibaba/druid) 1.x
+ * [HikariCP](https://github.com/brettwooldridge/HikariCP) 3.x -> 4.x
+ * [C3P0](https://github.com/swaldman/c3p0) 0.9.0 -> 0.10.0
+
___
¹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.