static void parseMySqlFlavor()

in apm-agent-plugins/apm-jdbc-plugin/src/main/java/co/elastic/apm/agent/jdbc/helper/ConnectionMetaData.java [642:767]


        static void parseMySqlFlavor(String vendorUrl, Builder builder) {
            // https://dev.mysql.com/doc/connector-j/8.0/en/connector-j-reference-jdbc-url-format.html
            // General structure:
            // protocol//[hosts][/database][?properties]

            // Single host:
            // jdbc:mysql://host1:33060/sakila
            // jdbc:mysql://host1:33060/sakila?prop=val
            // jdbc:mysql://host1:33060?prop=val
            // jdbc:mysql://address=(host=myhost)(port=1111)(key1=value1)/db
            // jdbc:mysql://(host=myhost,port=1111,key1=value1)/db

            // Multiple hosts:
            // jdbc:mysql://myhost1:1111,myhost2:2222/db
            // jdbc:mysql://address=(host=myhost1)(port=1111)(key1=value1),address=(host=myhost2)(port=2222)(key2=value2)/db
            // jdbc:mysql://(host=myhost1,port=1111,key1=value1),(host=myhost2,port=2222,key2=value2)/db
            // jdbc:mysql://myhost1:1111,(host=myhost2,port=2222,key2=value2)/db
            // jdbc:mysql://sandy:secret@[myhost1:1111,myhost2:2222]/db
            // jdbc:mysql://sandy:secret@[address=(host=myhost1)(port=1111)(key1=value1),address=(host=myhost2)(port=2222)(key2=value2)]/db
            // jdbc:mysql://sandy:secret@[myhost1:1111,address=(host=myhost2)(port=2222)(key2=value2)]/db

            vendorUrl = vendorUrl.toLowerCase().trim();
            final Pattern pattern = Pattern.compile("//([^/?]+)(.*)$");
            Matcher matcher = pattern.matcher(vendorUrl);
            if (matcher.find()) {
                String hostsPart = matcher.group(1);
                String afterHost = matcher.group(2);
                if (afterHost.startsWith("/")) {
                    int propertiesStart = afterHost.indexOf('?');
                    String db = afterHost.substring(1, propertiesStart < 0 ? afterHost.length() : propertiesStart);
                    builder.withInstance(db);
                }

                // splitting to hosts, watching out from the "key-value" form: (host=myhost1,port=1111,key1=value1)
                List<String> hosts = new ArrayList<>();
                String[] parts = hostsPart.toLowerCase().trim().split(",");
                StringBuilder sb = new StringBuilder();
                for (String part : parts) {
                    if (part.lastIndexOf(')') < part.lastIndexOf('(')) {
                        // we are in the middle of a "key-value" form, we need to concatenate the next part
                        sb.append(part).append(',');
                    } else {
                        boolean isWithinKeyValuePart = sb.length() > 0;
                        sb.append(part);
                        if (isWithinKeyValuePart && !part.contains(")")) {
                            // key-value part not finished yet
                            sb.append(',');
                            continue;
                        }
                        hosts.add(sb.toString());
                        sb.setLength(0);
                    }
                }

                String firstHost = hosts.get(0);

                // the "address-equals" form: address=(host=myhost1)(port=1111)(key1=value1)
                String addressKey = "address=";
                int indexOfAddress = firstHost.indexOf(addressKey);
                if (indexOfAddress >= 0) {
                    String tmp = firstHost.substring(indexOfAddress + addressKey.length());
                    Matcher hostMatcher = Pattern.compile("\\s*host\\s*=\\s*([^)]+)\\s*").matcher(tmp);
                    if (hostMatcher.find()) {
                        String host = hostMatcher.group(1).trim();
                        int port = -1;
                        Matcher portMatcher = Pattern.compile("\\s*port\\s*=\\s*([^)]+)\\s*").matcher(tmp);
                        if (portMatcher.find()) {
                            port = toNumericPort(vendorUrl, portMatcher.group(1).trim());
                        }
                        builder.withHost(host).withPort(port);
                        return;
                    } else {
                        logger.warn("Failed to parse address from a connection URL: {}", vendorUrl);
                        builder.withParsingError();
                    }
                }

                // the "key-value" form: (host=myhost1,port=1111,key1=value1) - address form shouldn't arrive here
                Matcher keyValueMatcher = Pattern.compile("\\(([^)]+)\\)").matcher(firstHost);
                if (keyValueMatcher.find()) {
                    String keyValuePart = keyValueMatcher.group(1).trim();
                    parts = keyValuePart.split(",");
                    String host = null;
                    int port = -1;
                    for (String part : parts) {
                        String[] keyValue = part.split("=");
                        if (keyValue.length == 2) {
                            if (keyValue[0].trim().equals("host")) {
                                host = keyValue[1].trim();
                            } else if (keyValue[0].trim().equals("port")) {
                                port = toNumericPort(vendorUrl, keyValue[1].trim());
                            }
                        }
                    }
                    if (host != null) {
                        builder.withHost(host).withPort(port);
                        return;
                    } else {
                        logger.warn("Failed to parse address from a connection URL: {}", vendorUrl);
                        builder.withParsingError();
                        return;
                    }
                }

                int indexOfSquareBracket = firstHost.indexOf('[');
                if (indexOfSquareBracket >= 0) {
                    if (!firstHost.contains("]") || firstHost.lastIndexOf('[') != indexOfSquareBracket) {
                        // not IPv6, probably the "sublist" format, trim up to it
                        firstHost = firstHost.substring(indexOfSquareBracket + 1);
                    }
                }

                // trim user part, if set
                int indexOfUserDetailsEnd = firstHost.indexOf('@');
                if (indexOfUserDetailsEnd >= 0) {
                    if (firstHost.length() > indexOfUserDetailsEnd + 1) {
                        firstHost = firstHost.substring(indexOfUserDetailsEnd + 1).trim();
                    } else {
                        return;
                    }
                }

                parseAuthority(firstHost.trim(), builder);
            }

        }