Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Opentracing-jdbc does not work with quarkus 2.0.0.CR3 #18033

Closed
lenalebt opened this issue Jun 21, 2021 · 27 comments
Closed

Opentracing-jdbc does not work with quarkus 2.0.0.CR3 #18033

lenalebt opened this issue Jun 21, 2021 · 27 comments
Assignees
Labels
area/kotlin area/smallrye area/tracing kind/bug Something isn't working triage/upstream Used for issues which are caused by issues in upstream projects/dependency

Comments

@lenalebt
Copy link
Contributor

Describe the bug

When using the dependencies

  implementation("io.quarkus:quarkus-smallrye-opentracing")
  implementation("io.opentracing.contrib:opentracing-jdbc")

with the configuration

quarkus:
  datasource:
    db-kind: "postgresql"
    username: "foobar"
    password: "foobar"
    jdbc:
      url: "jdbc:tracing:postgresql://localhost:5432/foobar"
      driver: "io.opentracing.contrib.jdbc.TracingDriver"

I get the following error logs in the console, and the application does not work:

__  ____  __  _____   ___  __ ____  ______ 
 --/ __ \/ / / / _ | / _ \/ //_/ / / / __/ 
 -/ /_/ / /_/ / __ |/ , _/ ,< / /_/ /\ \   
--\___\_\____/_/ |_/_/|_/_/|_|\____/___/   
11:46:34.991 WARN  traceId=, parentId=, spanId=, sampled= [io.qu.config] (main) Unrecognized configuration key "quarkus.oidc.credentials.client.secret.value" was provided; it will be ignored; verify that the dependency extension for this configuration is set or that you did not make a typo
11:46:34.994 INFO  traceId=, parentId=, spanId=, sampled= [or.fl.co.in.li.VersionPrinter] (main) Flyway Community Edition 7.9.1 by Redgate
11:46:35.002 ERROR traceId=, parentId=, spanId=, sampled= [io.qu.ru.Application] (main) Failed to start application (with profile dev): com.oracle.svm.core.jdk.UnsupportedFeatureError: Proxy class defined by interfaces [interface java.sql.Wrapper, interface org.postgresql.PGConnection, interface java.sql.Connection, interface org.postgresql.core.BaseConnection, interface java.lang.AutoCloseable] not found. Generating proxy classes at runtime is not supported. Proxy classes need to be defined at image build time by specifying the list of interfaces that they implement. To define proxy classes use -H:DynamicProxyConfigurationFiles=<comma-separated-config-files> and -H:DynamicProxyConfigurationResources=<comma-separated-config-resources> options.
        at com.oracle.svm.core.util.VMError.unsupportedFeature(VMError.java:87)
        at com.oracle.svm.reflect.proxy.DynamicProxySupport.getProxyClass(DynamicProxySupport.java:113)
        at java.lang.reflect.Proxy.getProxyConstructor(Proxy.java:66)
        at java.lang.reflect.Proxy.newProxyInstance(Proxy.java:1006)
        at io.opentracing.contrib.common.WrapperProxy.wrap(WrapperProxy.java:67)
        at io.opentracing.contrib.jdbc.TracingDriver.connect(TracingDriver.java:176)
        at io.agroal.pool.ConnectionFactory.createConnection(ConnectionFactory.java:204)
        at io.agroal.pool.ConnectionPool$CreateConnectionTask.call(ConnectionPool.java:490)
        at io.agroal.pool.ConnectionPool$CreateConnectionTask.call(ConnectionPool.java:472)
        at java.util.concurrent.FutureTask.run(FutureTask.java:264)
        at io.agroal.pool.util.PriorityScheduledExecutor.beforeExecute(PriorityScheduledExecutor.java:68)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1126)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
        at java.lang.Thread.run(Thread.java:834)
        at com.oracle.svm.core.thread.JavaThreads.threadStartRoutine(JavaThreads.java:519)
        at com.oracle.svm.core.posix.thread.PosixJavaThreads.pthreadStartRoutine(PosixJavaThreads.java:192)

It does work in 1.13.7.Final.

Expected behavior

The application should start up and work as expected, no error logs.

Actual behavior

See above logs :).

To Reproduce

I don't have a reproducer yet, maybe you already know what to do? If not, I can provide one. I guess it's just some class registration missing in graalvm for for the case I do have at hand here, which I think should be done by the dependencies already?

Configuration

quarkus:
  datasource:
    db-kind: "postgresql"
    username: "foobar"
    password: "foobar"
    jdbc:
      url: "jdbc:tracing:postgresql://localhost:5432/foobar"
      driver: "io.opentracing.contrib.jdbc.TracingDriver"

Environment:

Output of uname -a or ver

Linux lena-pc 5.11.0-18-generic #19-Ubuntu SMP Fri May 7 14:22:03 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux

Output of java -version

openjdk version "11.0.10" 2021-01-19
OpenJDK Runtime Environment GraalVM CE 21.0.0.2 (build 11.0.10+8-jvmci-21.0-b06)
OpenJDK 64-Bit Server VM GraalVM CE 21.0.0.2 (build 11.0.10+8-jvmci-21.0-b06, mixed mode, sharing)

Quarkus version or git rev

2.0.0-CR3

Build tool (ie. output of mvnw --version or gradlew --version)


Gradle 7.0

Build time: 2021-04-09 22:27:31 UTC
Revision: d5661e3f0e07a8caff705f1badf79fb5df8022c4

Kotlin: 1.4.31
Groovy: 3.0.7
Ant: Apache Ant(TM) version 1.10.9 compiled on September 27 2020
JVM: 11.0.10 (GraalVM Community 11.0.10+8-jvmci-21.0-b06)
OS: Linux 5.11.0-18-generic amd64

Additional context

When I remove the dependencies and do not use the tracing, the application does start up and work as expected.

@lenalebt lenalebt added the kind/bug Something isn't working label Jun 21, 2021
@quarkus-bot
Copy link

quarkus-bot bot commented Jun 21, 2021

/cc @Ladicek, @evanchooly, @kenfinnigan

@kenfinnigan
Copy link
Member

kenfinnigan commented Jun 21, 2021

Are you running in the JVM, as this looks like an error from running in Native with GraalVM instead?

When it worked in 1.13, was that on JVM or Native?

@gsmet
Copy link
Member

gsmet commented Jun 21, 2021

@lenalebt I think a reproducer would be welcome. Thanks!

@lenalebt
Copy link
Contributor Author

lenalebt commented Jun 22, 2021

I added a reproducer here: https://github.com/lenalebt/quarkus-ticket-18033-reproducer

The initial commit is a working example with 1.13.7.Final, latest commit is the update to quarkus 2.0.0.CR3 from 1.13.7.Final. It works in JVM mode for both 1.13.7.Final and 2.0.0.CR3, but it does not in native mode for 2.0.0.CR3 (I used native mode). JVM works for 2.0.0.CR3.

There is a docker-compose.yml to start the environment (with postgres and jaeger) that you can start with docker-compose up, it's already wired for the application. Jaeger UI is available at localhost:8002.

This is the error message from the reproducer application:

 build/code-with-quarkus-1.0.0-SNAPSHOT-runner 
__  ____  __  _____   ___  __ ____  ______ 
 --/ __ \/ / / / _ | / _ \/ //_/ / / / __/ 
 -/ /_/ / /_/ / __ |/ , _/ ,< / /_/ /\ \   
--\___\_\____/_/ |_/_/|_/_/|_|\____/___/   
2021-06-22 16:05:24,506 INFO  [org.fly.cor.int.lic.VersionPrinter] (main) Flyway Community Edition 7.9.1 by Redgate
2021-06-22 16:05:24,512 ERROR [io.qua.run.Application] (main) Failed to start application (with profile prod): com.oracle.svm.core.jdk.UnsupportedFeatureError: Proxy class defined by interfaces [interface org.postgresql.PGConnection, interface org.postgresql.core.BaseConnection, interface java.sql.Wrapper, interface java.sql.Connection, interface java.lang.AutoCloseable] not found. Generating proxy classes at runtime is not supported. Proxy classes need to be defined at image build time by specifying the list of interfaces that they implement. To define proxy classes use -H:DynamicProxyConfigurationFiles=<comma-separated-config-files> and -H:DynamicProxyConfigurationResources=<comma-separated-config-resources> options.
        at com.oracle.svm.core.util.VMError.unsupportedFeature(VMError.java:87)
        at com.oracle.svm.reflect.proxy.DynamicProxySupport.getProxyClass(DynamicProxySupport.java:113)
        at java.lang.reflect.Proxy.getProxyConstructor(Proxy.java:66)
        at java.lang.reflect.Proxy.newProxyInstance(Proxy.java:1006)
        at io.opentracing.contrib.common.WrapperProxy.wrap(WrapperProxy.java:67)
        at io.opentracing.contrib.jdbc.TracingDriver.connect(TracingDriver.java:176)
        at io.agroal.pool.ConnectionFactory.createConnection(ConnectionFactory.java:204)
        at io.agroal.pool.ConnectionPool$CreateConnectionTask.call(ConnectionPool.java:490)
        at io.agroal.pool.ConnectionPool$CreateConnectionTask.call(ConnectionPool.java:472)
        at java.util.concurrent.FutureTask.run(FutureTask.java:264)
        at io.agroal.pool.util.PriorityScheduledExecutor.beforeExecute(PriorityScheduledExecutor.java:68)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1126)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
        at java.lang.Thread.run(Thread.java:834)
        at com.oracle.svm.core.thread.JavaThreads.threadStartRoutine(JavaThreads.java:519)
        at com.oracle.svm.core.posix.thread.PosixJavaThreads.pthreadStartRoutine(PosixJavaThreads.java:192)

If there is anything more I can provide, I'll do that :).

@kenfinnigan
Copy link
Member

It definitely looks like some classes were removed from the Native Image that shouldn't have.

However, I'm not sure why it's happening.

@gsmet
Copy link
Member

gsmet commented Jun 22, 2021

@kenfinnigan it's not complaining about a missing class AFAICS but about a missing GraalVM proxy definition (i.e. with NativeImageProxyDefinitionBuildItem).

I think we will need to add some additional magic to the Agroal extension.

I'll have a look but it's too late for 2.0.0.Final.

@kenfinnigan
Copy link
Member

Ah yes, you're right.

@luneo7
Copy link
Contributor

luneo7 commented Jun 22, 2021

This mainly happened because there was a version bump in the opentracing-jdbc lib in 2.0.0, with the bump from 0.0.12 to 0.2.12, a new class WrapperProxy was added that is doing dynamic proxy...

@loicmathieu
Copy link
Contributor

@luneo7 this change appears to have been added to 0.2.8, can you try with 0.2.7 to see if it works ?
@kenfinnigan maybe we can downgrade to 0.2.7 while waiting to fix the proxy issue ?

We don't have a native test with the opentracing contrib JDBC tracer so we must be careful when upgrading it (and test it manually)!

@luneo7
Copy link
Contributor

luneo7 commented Jun 23, 2021

I've done some tests... to make it work in native mode I had to do all possible permutations of the interfaces for the PostgreSQL classes (PgConnection, PgStatemet, PgPreparedStatement, PgCallableStatement) to build a proxy config for GraalVM.... WrapperProxy is using Classes.getAllInterfaces and it does not guarantee the order of the returning classes array... so it ended up being a huge proxy-config.json with all possible permutations (https://gist.github.com/luneo7/453ea0bd0d51a48c6c4377237e8ad831), and the build time was hugely increased...

Using the 0.2.7 version doesn't help, just because it has a DynamicProxy class that does the same thing as the WrapperProxy... so the same problem happens... The only "newer" version that is not using dynamic proxy is the 0.2.4 version...

If you change the gradle dependency config to:

[...]
    implementation("io.opentracing.contrib:opentracing-jdbc:0.2.4!!") {
        isForce = true
    }
[...]

It will definitely work... so this is a workaround for Quarkus 2.0.0 for now....

@kenfinnigan
Copy link
Member

Thanks for the investigations @luneo7, appreciated!

@loicmathieu
Copy link
Contributor

So I think we need to downgrade to 0.2.4 inside our BOM and open an issue upstream to discuss native support. @kenfinnigan do you want to take care of it or do you want me to take over ?

As I understand you need to configure all possible interfaces combinations, which can be very challenging as we also need to include the driver custom interfaces (Postgres interfaces in your case).

@ghost
Copy link

ghost commented Jun 24, 2021

Same issue here. A downgrade of io.opentracing.contrib:opentracing-jdbc to 0.2.4 solved the problem.

@loicmathieu
Copy link
Contributor

As it's not the first time we had an issue, I'll try to add the usage of the tracing driver in an integration-test to avoid such issue in the future, @kenfinnigan WDYT ? I can work on it tomorrow.

@loicmathieu
Copy link
Contributor

I provided a PR to downgrade the driver to a working version, see #18128

I'll open an issue and write something in the migration guide later this day or tomorrow

@loicmathieu
Copy link
Contributor

Upstream issue: opentracing-contrib/java-jdbc#116

@loicmathieu loicmathieu added the triage/upstream Used for issues which are caused by issues in upstream projects/dependency label Jun 24, 2021
@loicmathieu loicmathieu self-assigned this Jun 24, 2021
@lenalebt
Copy link
Contributor Author

Wow, I really appreciate this being taken care of so quickly! I can live with that workaround for now. Thank you all <3!

@luneo7
Copy link
Contributor

luneo7 commented Jun 24, 2021

So I also opened up an upstream PR opentracing-contrib/java-common#2 so we have a predictable interfaces array to configure the proxy, after this one is merged, we have to bump the common lib version in the jdbc lib... and just after that we have to go through Quarkus's JDBC libs adding the proxy configuration if it is a native build and has the OpenTracing feature enabled.... and we should be good to go with the newer versions 🎉

@loicmathieu
Copy link
Contributor

@luneo7 thanks for making an upsteam improvement by using an ordered collection. This will make things easier and we could add to the documentation how the user of the tracing driver can do it.

However, the best is to avoid proxy creation, if possible, as, at Quarkus side, we cannot deal with all the possible databases interface list easily.

@gsmet
Copy link
Member

gsmet commented Jun 25, 2021

@luneo7 the funny part will be to get the specific classes involved for each supported JDBC driver :).

@loicmathieu
Copy link
Contributor

I added a section on the 2.0.0 migration guide: https://github.com/quarkusio/quarkus/wiki/Migration-Guide-2.0#opentracing-jdbc-instrumentation

@gsmet maybe you want to have a look for typos ;)

@loicmathieu
Copy link
Contributor

I created a PR to add an integration test so we might be able to catch those issue before releasing an RC: #18169

@luneo7
Copy link
Contributor

luneo7 commented Jun 25, 2021

@gsmet it is fun, but when you use https://github.com/ronmamo/reflections is quite easy 😃

import io.opentracing.contrib.common.Classes;
import org.reflections.Reflections;

import java.lang.reflect.Modifier;
import java.sql.Connection;
import java.sql.Statement;
import java.util.Arrays;
import java.util.Comparator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

public class ProxyConfig {

    private static String getProxyConfig(String driverPackage) {
        Reflections reflections = new Reflections(driverPackage);

        StringBuilder stringBuilder = new StringBuilder("[\n");

        appendInterfaces(reflections.getSubTypesOf(Connection.class), stringBuilder);

        appendInterfaces(reflections.getSubTypesOf(Statement.class), stringBuilder);

        stringBuilder.append("\n]");

        return stringBuilder.toString();
    }

    private static <T> void appendInterfaces(Set<Class<? extends T>> classes, StringBuilder stringBuilder) {
        classes.stream()
               .filter(clazz -> !Modifier.isAbstract(clazz.getModifiers()) && !Modifier.isInterface(clazz.getModifiers()))
               .sorted(Comparator.comparing(Class::getName))
               .map(clazz -> "\t[" + Arrays.stream(Classes.getAllInterfaces(clazz))
                                           .map(c -> "\"" + c.getName() + "\"")
                                           .collect(Collectors.joining(",")) + "]")
               .collect(Collectors.toCollection(LinkedHashSet::new))
               .forEach(item -> stringBuilder.append(stringBuilder.length() == 2 ? item : ",\n" + item));
    }

    public static void main(String[] args) {
        List<String> driverPackagePrefixes = Arrays.asList("org.postgresql",
                                                           "com.mysql",
                                                           "org.mariadb.jdbc",
                                                           "com.microsoft.sqlserver.jdbc",
                                                           "oracle",
                                                           "org.h2",
                                                           "org.apache.derby",
                                                           "com.ibm.db2");

        driverPackagePrefixes.stream()
                             .collect(Collectors.toMap(k -> k, ProxyConfig::getProxyConfig))
                             .forEach((driverPackage, proxyConfig) -> {
                                 System.out.println("----");
                                 System.out.println("Driver package " + driverPackage + " proxy config:\n");
                                 System.out.println(proxyConfig);
                             });
    }
}

So if the PR is merged upstream and we were to do for the JDBC drivers supported by Quarkus the proxy config for each driver would be as in this gist: https://gist.github.com/luneo7/8d4b6fbebc3d16576f1e56e31c3a7050

The opentracing jdbc lib just does proxy for the java.sql.Connection and java.sql.Statement implementations =]

I've built this gist using the drivers from Quarkus BOM =]

There are ways of doing this discovery and proxy config creation automatically in the opentracing deployment lib or somewhere else, and there is also the way of adding that to the deployment lib of each supported JDBC driver, or creating aa new lib for opentracing jdbc (quarkiverse?) for it... hahaha there are multiple ways of handling it =]

@luneo7
Copy link
Contributor

luneo7 commented Jun 26, 2021

@kenfinnigan @gsmet I can create one extension in Quarkiverse for OpenTracing JDBC contrib lib that does the native configuration for it automatically and also does the class substitution so the method behaves in a predictable manner and we don't wouldn't need to wait for the upstream merge to have it working, what do you guys think?

@kenfinnigan
Copy link
Member

I think that's reasonable

@loicmathieu
Copy link
Contributor

Maybe wait for some feedback from the upstream issue I created. If we can avoid the creation of a new extension it would be better.
If not, you plan sounds good.

@radcortez
Copy link
Member

Upstream PR never replied, indicating that OpenTracing is abandoned.

Closing this because we are no longer supporting OpenTracing.

@radcortez radcortez closed this as not planned Won't fix, can't repro, duplicate, stale Feb 6, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area/kotlin area/smallrye area/tracing kind/bug Something isn't working triage/upstream Used for issues which are caused by issues in upstream projects/dependency
Projects
None yet
Development

No branches or pull requests

6 participants