Hi Pavel,
[NOTE: I am cross-posting this to `dev@logging`, since I believe it is
more appropriate there]
On 29.11.2024 10:26, PavelTurk wrote:
In the world of JPMS, there’s a service, we implement it, and we add
it. I haven’t heard of a service + PROCESSOR that needs to be used.
Can you point out any other projects that involve a service +
processor? The reasoning is that we should only need to know the
INTERFACE, and we’ll handle the IMPLEMENTATION ourselves. After all,
it’s possible to do without it—for example, by writing a PluginService
manually, which would scan the module itself and return the necessary
classes or just data(entries) about them. That’s why I said that using
a processor here seems odd to me. In general, I think code generation
should only be used as a last resort—for example, for JPA
metamodels—but that’s just my opinion.
The processor doesn't need to be used, but it is quite useful, when you
have hundreds of plugins (which is the case for Log4j Core). Feel free
to update the Plugins documentation in `3.x`[1] to make that explicit.
We do have a draft PR to update that page, but it is a little bit stale[2].
Note that currently `PluginService` fulfills multiple functions, that
could be delegated to separate classes/files:
1. It provides a mapping between (namespace, pluginName) and a class
name, so we don't need to scan the classpath/modulepath. In this role it
replaces the binary `Log4j2Plugins.dat` file, with something that IMHO
is even harder to manipulate. We could probably replace it with a Java
properties file or a JSON file like the one in [3]. The metadata could
be generated by an annotation processor.
2. In a JPMS environment, it forces HotSpot to load all the available
modules containing Log4j Core Plugins. For this to work, `PluginService`
could just be an empty interface (easy to implement ;-) ).
3. In a non-JPMS environment, it simplifies the common practice of
shading. `Log4j2Plugins.dat` files are hard to merge and many shading
tools do not handle them. On the other hand most tools know how to merge
`META-INF/services` files.
It is a little bit late in the lifecycle of 3.x to make drastic changes
to how `PluginService` works, but we could:
* Either make `PluginService` an interface. Those that prefer to
implement the interface can do it themselves, but we will provide an
annotation processor that generates a JSON file and creates a minimal
implementation that reads the JSON file.
* Or merge the functionality of
`ConfigurableInstanceFactoryPostProcessor`[4] and `PluginService`.
Strongly simplifying, what the `PluginService` does is registering a
plugin builder `Supplier<T>` for each Log4j plugin `T` using a specific
namespace and name. CIFPP does the same thing, but for "global" services
like `MessageFactory`.
The latter proposition needs to be confirmed by Matt, who wrote the
dependency injection system from scratch. Since the DI in Log4j Core is
only used in Log4j Core, personally I find that the less features it
provides, the better.
[1] https://logging.apache.org/log4j/3.x/manual/plugins.html
[2] https://github.com/apache/logging-log4j2/pull/2716
[3]
https://github.com/apache/logging-log4j-transform/blob/main/log4j-converter-plugin-descriptor/src/main/resources/Log4j2Plugins.schema.json
[4]
https://logging.apache.org/log4j/3.x/javadoc/log4j-plugins/org/apache/logging/log4j/plugins/di/spi/ConfigurableInstanceFactoryPostProcessor.html
[5]
https://logging.apache.org/log4j/3.x/javadoc/log4j-plugins/org/apache/logging/log4j/plugins/di/Key.html
I assume module-info was also generated automatically. The problem is
that it’s not present in log4j-core-3.0.0-beta3-sources.jar see [1],
but it does exist in log4j-core-3.0.0-beta3.jar see [2]. Additionally,
it’s not in the repository see [3]. So, it is not possible to see what
is in this file. Or was I looking in the wrong place?
You assume correctly. We use the JPMS Libraries plugins for BND[5] to
generate the module descriptor. There are several reasons behind this
choice:
* Last time I checked, JPMS support in IDEs was terrible, especially for
unit tests. Right now it seems better (in IntelliJ), but for a Maven
project I need to choose if `src/test` contains whitebox tests that will
run on the classpath or blackbox tests in a different package, that will
run on the module path.
* It is hard to maintain a module descriptor manually, especially to
keep track of the `transitive` attribute or unused dependencies. BND
computes that perfectly.
* We want to have OSGi descriptors perfectly aligned with the JPMS
descriptor.
Piotr
[5] https://bnd.bndtools.org/chapters/330-jpms.html