From 3f77390b959279b18b4fdd51b8f7f34a6868f888 Mon Sep 17 00:00:00 2001 From: Claire Date: Sat, 11 May 2024 14:12:38 +0800 Subject: [PATCH 1/3] Add support for Derby/Sybase/SQLite/DB2/OceanBase jdbc url format in URLParser. --- CHANGES.md | 1 + .../trace/component/ComponentsDefine.java | 11 + .../connectionurl/parser/Db2URLParser.java | 129 ++++++++++++ .../connectionurl/parser/DerbyURLParser.java | 197 ++++++++++++++++++ .../parser/OceanBaseURLParser.java | 27 +++ .../connectionurl/parser/SqliteURLParser.java | 57 +++++ .../connectionurl/parser/SybaseURLParser.java | 114 ++++++++++ .../jdbc/connectionurl/parser/URLParser.java | 15 ++ .../connectionurl/parser/URLParserTest.java | 137 +++++++++++- .../java-agent/Supported-list.md | 15 ++ 10 files changed, 702 insertions(+), 1 deletion(-) create mode 100644 apm-sniffer/apm-sdk-plugin/jdbc-commons/src/main/java/org/apache/skywalking/apm/plugin/jdbc/connectionurl/parser/Db2URLParser.java create mode 100644 apm-sniffer/apm-sdk-plugin/jdbc-commons/src/main/java/org/apache/skywalking/apm/plugin/jdbc/connectionurl/parser/DerbyURLParser.java create mode 100644 apm-sniffer/apm-sdk-plugin/jdbc-commons/src/main/java/org/apache/skywalking/apm/plugin/jdbc/connectionurl/parser/OceanBaseURLParser.java create mode 100644 apm-sniffer/apm-sdk-plugin/jdbc-commons/src/main/java/org/apache/skywalking/apm/plugin/jdbc/connectionurl/parser/SqliteURLParser.java create mode 100644 apm-sniffer/apm-sdk-plugin/jdbc-commons/src/main/java/org/apache/skywalking/apm/plugin/jdbc/connectionurl/parser/SybaseURLParser.java diff --git a/CHANGES.md b/CHANGES.md index fcde635794..6b6c759ae5 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -10,6 +10,7 @@ Release Notes. * 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 5364ff0eda..b7307ebac7 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 class ComponentsDefine { 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 0000000000..8fe2b36515 --- /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 0000000000..dd96b8e06a --- /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 0000000000..f459c268e8 --- /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 0000000000..21f44492b3 --- /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 0000000000..dfc8a57519 --- /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 eab319fd7e..cb79d58b0c 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 @@ public class URLParser { 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 @@ public static ConnectionInfo parser(String url) { 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 f679f05cdf..48715ad840 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 @@ public void testParsePostgresqlJDBCURLWithMultiIpv6() { 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 a51d267460..d0e380e93f 100644 --- a/docs/en/setup/service-agent/java-agent/Supported-list.md +++ b/docs/en/setup/service-agent/java-agent/Supported-list.md @@ -172,6 +172,21 @@ The meter plugin provides the advanced metrics collections, which are not a part * [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 +* Database + * [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](https://www.sap.com/products/acquired-brands/what-is-sybase.html) + * [OceanBase](https://www.oceanbase.com/) ___ ¹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. From 4d07e422a5c2fdd3a33d8cfaf28fc20cf11999ca Mon Sep 17 00:00:00 2001 From: Claire Date: Sat, 11 May 2024 16:47:42 +0800 Subject: [PATCH 2/3] update Supported-list.md & remove deadlink. --- .../java-agent/Supported-list.md | 70 +++++++++++++++---- 1 file changed, 55 insertions(+), 15 deletions(-) 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 d0e380e93f..b6f10e90e3 100644 --- a/docs/en/setup/service-agent/java-agent/Supported-list.md +++ b/docs/en/setup/service-agent/java-agent/Supported-list.md @@ -169,24 +169,64 @@ The meter plugin provides the advanced metrics collections, which are not a part * [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 + * [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/) * [Alibaba Druid](https://github.com/alibaba/druid) 1.x + * [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/) + * [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/) * [HikariCP](https://github.com/brettwooldridge/HikariCP) 3.x -> 4.x + * [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/) * [C3P0](https://github.com/swaldman/c3p0) 0.9.0 -> 0.10.0 -* Database - * [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](https://www.sap.com/products/acquired-brands/what-is-sybase.html) - * [OceanBase](https://www.oceanbase.com/) + * [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/) ___ ¹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. From ee62b7c3c9d0fd035df59e54e8b35444aa99a5c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=90=B4=E6=99=9F=20Wu=20Sheng?= Date: Sat, 11 May 2024 20:39:39 +0800 Subject: [PATCH 3/3] Update Supported-list.md --- .../java-agent/Supported-list.md | 52 +++---------------- 1 file changed, 7 insertions(+), 45 deletions(-) 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 b6f10e90e3..9b21ea11d8 100644 --- a/docs/en/setup/service-agent/java-agent/Supported-list.md +++ b/docs/en/setup/service-agent/java-agent/Supported-list.md @@ -168,51 +168,7 @@ The meter plugin provides the advanced metrics collections, which are not a part * [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 - * [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/) - * [Alibaba Druid](https://github.com/alibaba/druid) 1.x - * [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/) - * [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/) - * [HikariCP](https://github.com/brettwooldridge/HikariCP) 3.x -> 4.x - * [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/) - * [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) @@ -227,6 +183,12 @@ The meter plugin provides the advanced metrics collections, which are not a part * [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.