-
-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Add getConfiguration method for multiple URIs #3921
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
base: 2.x
Are you sure you want to change the base?
Conversation
log4j-core/src/main/java/org/apache/logging/log4j/core/config/ConfigurationFactory.java
Outdated
Show resolved
Hide resolved
log4j-core/src/main/java/org/apache/logging/log4j/core/config/ConfigurationFactory.java
Outdated
Show resolved
Hide resolved
9377356
to
22ba22c
Compare
Thanks for the review, @vy. I've updated the PR. If this looks good, I'll proceed with adding tests and changelog. |
@yybmion, yes, please proceed with tests and a changelog. |
...j-core-test/src/test/java/org/apache/logging/log4j/core/config/ConfigurationFactoryTest.java
Show resolved
Hide resolved
...j-core-test/src/test/java/org/apache/logging/log4j/core/config/ConfigurationFactoryTest.java
Outdated
Show resolved
Hide resolved
...j-core-test/src/test/java/org/apache/logging/log4j/core/config/ConfigurationFactoryTest.java
Outdated
Show resolved
Hide resolved
log4j-core/src/main/java/org/apache/logging/log4j/core/config/json/package-info.java
Outdated
Show resolved
Hide resolved
log4j-core/src/main/java/org/apache/logging/log4j/core/config/properties/package-info.java
Outdated
Show resolved
Hide resolved
log4j-core/src/main/java/org/apache/logging/log4j/core/config/xml/package-info.java
Outdated
Show resolved
Hide resolved
log4j-core/src/main/java/org/apache/logging/log4j/core/config/yaml/package-info.java
Outdated
Show resolved
Hide resolved
src/changelog/.2.x.x/add_getConfiguration_method_for_mulitiple_URIs.xml
Outdated
Show resolved
Hide resolved
aeda617
to
40b26ea
Compare
Thanks for the review @vy, Changes applied as requested. Added a null element check in the URI list to throw a ConfigurationException when any element is null. This ensures that for (final URI uri : uris) {
if (uri == null) {
throw new ConfigurationException("URI list contains null element");
}
... |
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.
@yybmion, thanks so much for your patience. I am happy with the last state of the PR.
@ppkarwasz, do you any remarks?
log4j-core/src/main/java/org/apache/logging/log4j/core/config/json/package-info.java
Show resolved
Hide resolved
6af187e
to
e91c25b
Compare
@yybmion, CI builds are failing. Would you mind reading the Log4j Development Guide and resolving all build failures, please? |
e91c25b
to
93819f2
Compare
@vy I think the version bumps are actually needed because the new public method in ConfigurationFactory is inherited by all its subclasses (JsonConfigurationFactory, XmlConfigurationFactory, etc.), which adds the method to those packages' public API. This is causing the build failure. I've updated the versions back to 2.26.0. |
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.
Hi @yybmion,
Thanks for the PR, and apologies for the delayed feedback: I haven’t had as much time to spend on Log4j recently as I’d like.
I like the direction of your change, but there are still a few edge cases we need to address.
In particular, I expected the PR to integrate the newly introduced method into the existing code.
For example, ConfigurationFactory.Factory#getConfiguration(LoggerContext, String, URI)
could benefit from using it: we currently have a couple of legacy mechanisms for passing multiple URIs through a single URI
parameter:
- If
uri == null
, thelog4j2.configurationFile
property is treated as a comma-separated list of file paths or URIs. - If
uri != null
, there’s a legacy (and admittedly hacky) method of cramming two URIs into one string (seeparseConfigLocations
), which unfortunately still needs to be supported.
These mechanisms are handled in getConfiguration(LoggerContext, String, URI)
, but I think we should delegate them to the newly introduced method.
* @return a Configuration created from the provided URIs | ||
* @throws NullPointerException if uris is null | ||
* @throws IllegalArgumentException if uris is empty | ||
* @throws ConfigurationException if no valid configuration could be created |
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 change introduces an inconsistency between two similarly named methods:
getConfiguration(LoggerContext, String, URI)
: returnsnull
on errorgetConfiguration(LoggerContext, String, List<URI>)
: throwsConfigurationException
on error
Personally, I prefer the exception-throwing approach since it forces the caller to handle the error explicitly.
That said, we could instead align with the existing “StatusLogger
+ return null” pattern here.
If we keep the latter approach, then LoggerContext.start(Configuration)
and LoggerContext.reconfigure(Configuration)
should defensively null-check the Configuration
argument to ensure that the call ignores null
as argument.
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.
We have discussed this earlier, and agreed that, since this is a new API, we will go with the exception-throwing approach. @ppkarwasz you can see your thumbs up in the discussion: #3839 (comment)
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're right that we discussed on dev@logging
that we should not use partially constructed configurations.
However, my concern here is slightly different: we now have two overloads with fundamentally different error-handling conventions. Java deprecated the File
API partly because it behaved inconsistently across methods and this proposal would introduce a similar inconsistency between these overloads.
I see three possible approaches:
-
Align all methods to throw on error.
This approach would make error handling explicit and predictable. Currently,getConfiguration
can already throw when an invalid properties configuration is encountered. However, most other factories behave differently: they either returnnull
when the file is missing or the factory is inactive, or return a partially constructed (broken) configuration when a parsing error occurs.
Unifying everything under the exception-throwing model would be cleaner, but we should proceed carefully, as it could introduce backward-compatibility issues for existing users. -
Align all methods to return
null
on error.
This is more consistent with current behavior, though not ideal: some callers expect a non-null configuration even whenURI
isnull
. -
Introduce a new method, e.g.
getRequiredConfiguration
, which explicitly throws on failure.
This would let us offer both behaviors without breaking existing expectations.
P.S.: A “thumbs up” on a PR announcement doesn’t necessarily mean approval: it just means I’ve seen it and plan to review when I can.
if (uris.isEmpty()) { | ||
throw new IllegalArgumentException("URI list cannot be empty"); | ||
} |
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.
If the list is empty, I’d delegate to getConfiguration(loggerContext, name, (URI) null)
. This allows the factory to either auto-detect a configuration or return null
.
Also note: the name
parameter only matters in the empty-list case. When a non-null
URI
is provided, getConfiguration(LoggerContext, String, URI)
ignores name
entirely.
So, if we decide to forbid empty lists, the name
parameter becomes unnecessary.
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 fine with delegating to getConfiguration(loggerContext, name, (URI) null)
, but don't return null
please.
if (uri == null) { | ||
throw new ConfigurationException("URI list contains null element"); | ||
} |
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.
Nit: IllegalArgumentException
seems more appropriate here. ConfigurationException
suggests an unexpected runtime failure, whereas a null-check is a precondition the caller should do himself.
if (!(config instanceof AbstractConfiguration)) { | ||
throw new ConfigurationException("Configuration at " + uri + " is not an AbstractConfiguration"); | ||
} |
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 check is only necessary when uris
has more than one element and we need to build a CompositeConfiguration
.
If uris
is a singleton, we can skip the check and just return the configuration directly.
void testGetConfigurationWithSingleUri() throws Exception { | ||
final ConfigurationFactory factory = ConfigurationFactory.getInstance(); |
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.
Since the goal is to test the basic implementation, we could use a mock that delegates to the real getConfiguration(LoggerContext, String, List<URI>)
method, while mocking only getConfiguration(LoggerContext, String, URI)
.
I realize my comments go a bit beyond the immediate scope of this PR, but the section of code below has become a real maintenance headache. It would be great if we could take the opportunity to clean it up once and for all: Lines 373 to 478 in 8a3fb53
|
Summary
Adds a new public API to ConfigurationFactory for creating configurations
from multiple URIs, automatically combining them into a CompositeConfiguration when needed.
Motivation
External frameworks like Spring Boot currently need to understand Log4j's internal implementation to create composite configurations. This new API encapsulates that complexity.
Addresses feedback from #3839
✅ Required checks
License: I confirm that my changes are submitted under the Apache License, Version 2.0.
Commit signatures: All commits are signed and verifiable. (See GitHub Docs on Commit Signature Verification).
Code formatting: The code is formatted according to the project’s style guide.
How to check and fix formatting
./mvnw spotless:check
./mvnw spotless:apply
See the build instructions for details.
Build & Test: I verified that the project builds and all unit tests pass.
How to build the project
Run:
./mvnw verify
See the build instructions for details.
🧪 Tests (select one)
📝 Changelog (select one)
src/changelog/.2.x.x
. (See Changelog Entry File Guide).