-
Notifications
You must be signed in to change notification settings - Fork 2.7k
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
Set a injected CDI CommandListener to the mongodb configuration. #12082
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added a few small comments.
List<ConnectionPoolListener> connectionPoolListeners = new ArrayList<>(connectionPoolListenerSuppliers.size()); | ||
for (Supplier<ConnectionPoolListener> item : connectionPoolListenerSuppliers) { | ||
connectionPoolListeners.add(item.get()); | ||
} | ||
final CommandListener commandListener = Arc.container().instance(CommandListener.class).get(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't we support multiple CommandListener
s given it looks like MongoDB supports it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree. The limitation is on my knowledge of how to retrieve the List of CDI beans of a given type. any help?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Set<Bean<?>> beans = Arc.container().beanManager().getBeans(CommandListener.class);
will return all beans of type CommandListener.
Then you can get the bean from Arc by type if the name is null or by name.
You can find an example here but there may be an easier way to do it if you don't rely on CDI but instead use Jandex and retrieve all implementors of CommandListener
.
return commandListeners; | ||
} | ||
|
||
public void setCommandListenerList(List<CommandListener> commandListenersList) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would drop this method, it's useless, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It depends on the above comment (#12082 (comment)). If we need to add a single CommandListener or a full list. But finally it should exist only the one that it's used.
} | ||
|
||
public void addCommandListener(CommandListener commandListener) { | ||
if (null != commandListener) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You already test the caller, I think we can drop this test here and consider it will be called with a non-null commandListener
.
@loicmathieu @pavolloffay WDYT about this? I wonder if we should somehow integrate things better with OpenTracing to just have a boolean configuration to enable tracing? I have the same question for the JDBC driver implementation btw. |
This PR raises two questions:
For opentracing support, I would rather prefere activating it via a boolean property (with a check to verify that smallrye-opentracing is in the classpath). For the JDBC support it's a different story as it's already configured via the inclusion of the library + some config property (JDBC driver name). |
The current approach is based on the user definition via CDI of the CommandListener that the application would like to be injected.
+1 That's another good approach, define the specific TracingCommandListener "the same way" as the metrics to the ConnectionListeners are defined. We could define more settings for the Listener or even there could be more configuration values specifying the commands to exclude from the tracing. (https://github.com/opentracing-contrib/java-mongo-driver#exclude-commands-from-tracing)
+1 to that approach ^^ |
extensions/mongodb-client/runtime/src/main/java/io/quarkus/mongodb/runtime/MongoClients.java
Outdated
Show resolved
Hide resolved
80d7036
to
b7092f2
Compare
@gsmet @loicmathieu
I've prepared another branch with the suggestions (the branch extends from the one of this PR). The tracing of the Mongo driver commands now checks the build property The comparison of the changes can be seen on: As a working example of this branch, the project mongodb-opentracing/ext-mongodb-opentracing-byconfig has the property |
You should consider that OpenTracing is basically in the maintenance mode, it will be sunsetted once OpenTelemetry is released. Maybe it's better to wait until OTEL GA is released and then do the integration? |
@pavolloffay yesterday Ken Finnigan told me that OpenTelemetry will be integrated in Quarkus by the end of the year. So it makes sense to me to integrate MongoDB with OpenTracing while waiting for OpenTelemetry support. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My main point is whether or not the CommandListener needs to comes from CDI (so we can inject dependencies in it) or from Jandex (so we can retrieve it easily but injection will not work for it).
Everything else is build from CDI for MongoDB
this.commandListeners = new ArrayList<>(); | ||
this.disableSslSupport = disableSslSupport; | ||
} | ||
|
||
public MongoClientSupport(List<String> codecProviders, List<String> bsonDiscriminators, | ||
List<ConnectionPoolListener> connectionPoolListeners, List<CommandListener> commandListeners, | ||
boolean disableSslSupport) { | ||
this.codecProviders = codecProviders; | ||
this.bsonDiscriminators = bsonDiscriminators; | ||
this.connectionPoolListeners = connectionPoolListeners; | ||
this.commandListeners = commandListeners; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this is needed to provides methods with and without the List of CommandListener. This method is only used inside the deployment module so it's signature can be modified.
if (null != commandListener) { | ||
mongoClientSupport.addCommandListener(commandListener); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should not be needed, just pass the Command listener list as we do for all other MongoDB related classes
@juazugas regarding what you done here master...juazugas:ext-mongodb-opentracing-byconfig there is no need for a CDI Command Listener so I would implement the retrieval of the Command Listener list from Jandex (as we did for BsonDiscriminators and other MongoDB related classes). |
@loicmathieu |
OK, I propose to make this in two phases. |
Ok. Search the implementors and add them after default constructor instantiation.
Super! baking new PR. 😁 |
@@ -249,6 +250,12 @@ private MongoClientSettings createMongoConfiguration(MongoClientConfig config) { | |||
CodecRegistries.fromProviders(providers)); | |||
settings.codecRegistry(registry); | |||
|
|||
List<CommandListener> listeners = new ArrayList<>(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You create a List fo CommandListener in the getCommandListener
method so this one is not needed.
assertThat(startedEvent, notNullValue()); | ||
assertThat(startedEvent.getCommandName(), anyOf(equalTo("listDatabases"), equalTo("endSessions"))); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Having the insertions here is not realy readable for a test.
Can you instead register the CommandEvent in a static List and assert in the test that the event is present inside the list ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please stash all your commits then I'll approve this PR
|
||
import com.mongodb.event.CommandListener; | ||
import com.mongodb.event.CommandStartedEvent; | ||
|
||
public class MockCommandListener implements CommandListener { | ||
|
||
private CommandStartedEvent commandStartedEvent; | ||
public static final List<String> events = new ArrayList<>(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
constants should be uppercase
7715e92
to
8a5a020
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
@gsmet this PR changed to only allow to setup a CommandListener, not via CDI as for other MongoDB component. It will then enable to implement an OpenTracing CommandListener for MongoDB. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added some comments inline.
...-client/deployment/src/main/java/io/quarkus/mongodb/deployment/CommandListenerBuildItem.java
Show resolved
Hide resolved
} | ||
|
||
@BuildStep | ||
List<ReflectiveClassBuildItem> addCodecsAndDiscriminatorsAndListenersToNative(CodecProviderBuildItem codecProviders, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe rename the method to addExtensionPointsToNative
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure
List<CommandListener> listeners = new ArrayList<>(); | ||
for (String name : classNames) { | ||
try { | ||
Class<?> clazz = Thread.currentThread().getContextClassLoader().loadClass(name); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we use Class.forName
here instead?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok. Tested on a project with the jar and the native image does not make the difference, I suppose because we do
the initialization immediately after loading the class.
@@ -249,6 +250,8 @@ private MongoClientSettings createMongoConfiguration(MongoClientConfig config) { | |||
CodecRegistries.fromProviders(providers)); | |||
settings.codecRegistry(registry); | |||
|
|||
settings.commandListenerList(getCommandListeners(mongoClientSupport.getCommandListeners())); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe call this one commandListeners
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure about this suggestion.
- The settings class is from mongodb driver (com.mongodb.MongoClientSettings.Builder)
- The MongoClientSupport class has all its fields exposed to getter methods
- The private method getCommandListeners is called after the same naming pattern as the getCodeProviders method.
It could be ... extracting the call to the getter function to a variable called commandListeners (very likely to happen in a future PR). For example:
List<CommandListeners> commandListeners = getCommandListeners(mongoClientSupport.getCommandListeners());
settings.commandListenerList(commandListeners);
Hmmm, I don't know what was merged that is causing so many conflicts but this patch will need a big rebase. Please ping me when done so that I can have a final look. Thanks! |
aee8c58
to
557b58a
Compare
Ping @gsmet, the rebase is done. |
557b58a
to
1230272
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I adjusted the Class.forName()
call a bit and squashed everything.
Looks good now, thanks!
|
||
import io.quarkus.builder.item.SimpleBuildItem; | ||
|
||
public final class CommandListenerBuildItem extends SimpleBuildItem { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you please add some Javadoc to this class? This is necessary for the All Build Items page
1230272
to
e09bd88
Compare
I added some javadoc and rebased. |
This implementation allows injecting a CommandListener to the current MongoDB client configuration via CDI bean definition.
The idea came from using the MP opentracing library and trying to include the mongodb tracing spans.
Following the instructions in the OpenTracing Mongo Driver Instrumentation there is a way to include the tracing information simply adding a CommandListener to the mongoclient settings.
I prepared an example to show the MongoDB tracing:
https://github.com/juazugas/quarkus-mongodb-opentracing/blob/master/src/main/java/com/example/mongodb/tracing/TracingCommandListenerProducer.java
on project sample https://github.com/juazugas/quarkus-mongodb-opentracing/