Skip to content

Fix 1799 and Spring 33450 #2062

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

Merged
merged 1 commit into from
Dec 5, 2023
Merged

Fix 1799 and Spring 33450 #2062

merged 1 commit into from
Dec 5, 2023

Conversation

rgoers
Copy link
Member

@rgoers rgoers commented Dec 5, 2023

Fix #1799

When errors are encountered creating a LoggerContext Log4j will return a SimpleLoggerContext. This usually fails as it doesn't extend LoggerContext in log4j-core. This change creates an InternalLoggerContext that is a wrapper to SimpleLoggerContext to avaoid this problem.

spring-projects/spring-boot#33450

During Shutdown a call to PropertiesUtil is made which calls the SpringPropertySource. However the Spring environment has already shutdown so an exception is thrown. This change handles the exception and ignores the ProeprtySource.

…- Spring shutdown fails due to IllegalStateException
try {
return source.getProperty(contextName, key);
} catch (Throwable ex) {
return null;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't we better dump ex using the StatusLogger or something else?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think so. The issue that was reported simply causes error messages to be logged. The application is shutting down so an error during shutdown is irritating. Changing that to a warning doesn't really help much.

Comment on lines +129 to +131
public static AuthorizationProvider authorizationProvider(final PropertiesUtil props) {
return AuthorizationProvider.getAuthorizationProvider((PropertyEnvironment) props);
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not really sure if ConfigurationFactory is the right place to provide the AuthorizationProvider. Does it really need to be placed here? I mean, the call site can themselves issue AuthorizationProvider.getAuthorizationProvider() too, ain't so?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree that the method should not be duplicated.

Also, in order to make this PR back-portable to 2.x (it is a requirement, isn't it?), I would use LoggerContext as parameter.

Unless I am mistaken, all HTTP/HTTPS accesses are performed after a LoggerContext is created and the context is passed to the ConfigurationFactory as a parameter (since 2.7). This change would allow 3.x to configure separate credentials for separate web applications.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The authorization provider is always created based on properties, partly because it can be used to authenticate with a remote source that provides your logging config.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jvz,

Yes, but it could use a different PropertyEnvironment for each LoggerContext.

Anyway the reason @rgoers "introduced" this method in 3.x is that it was already present in 2.x, but disappeared from 3.x or was never ported to main.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ppkarwasz Correct. It is NOT a new method. Matt removed it a few weeks before I made this fix.

startContext(ctx, classLoader);
}
} catch (IllegalStateException ex) {
return internalContext;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rgoers, there are several points introduced in this PR that swallow exceptions. I would appreciate it if you can reconsider "Don't we need to communicate anything to the user at this point?" and if not, add some comments explaining why it is safe to swallow.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree on the need to log a WARN message or even an ERROR message.

In these kind of situations users are really clueless on why their Log4j configuration is not working. Problems concerning multiple LoggerContexts are the hardest to debug. Users usually don't know that multiple logger contexts are possible (this is almost exclusive to Log4j Core).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Previously the error was propagated back to LogManager. It would log a Warn message and then promptly get a ClassCastException as it returned the LoggerContext from logj-api, not a LoggerContext compatible with log4j-core. I think I might have a better way to deal with this so I will look into it.

import org.apache.logging.log4j.spi.ExtendedLogger;

/**
* Creates a SimpleLoggerContext compatible with log4j-core. This class is internal to Log4j.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would you mind explaining why do we need this? Where does SLC fall short? etc.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

org.apache.logging.log4j.simple.SimpleLoggerContext cannot be cast to org.apache.logging.log4j.core.LoggerContext, which is what the caller expects.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[For future reference, the caller is this code in Spring Boot

private LoggerContext getLoggerContext() {
	return (LoggerContext) LogManager.getContext(false);
}

]

@rgoers: looking at this again, I don't think it is a good idea to add a new public method to LoggerContextFactory and an entire dummy class, just because Spring Boot did an unchecked cast.

Do you mind if I remove this class and fix the Spring Boot code instead?

Copy link
Contributor

@ppkarwasz ppkarwasz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The changes in the public API look good to me. I am not a big fan of exposing util.PropertiesUtil to the public, but that ship has sailed a long time ago.

We might however deprecate all the public methods that are not used by Spring Boot.

startContext(ctx, classLoader);
}
} catch (IllegalStateException ex) {
return internalContext;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree on the need to log a WARN message or even an ERROR message.

In these kind of situations users are really clueless on why their Log4j configuration is not working. Problems concerning multiple LoggerContexts are the hardest to debug. Users usually don't know that multiple logger contexts are possible (this is almost exclusive to Log4j Core).

Comment on lines +129 to +131
public static AuthorizationProvider authorizationProvider(final PropertiesUtil props) {
return AuthorizationProvider.getAuthorizationProvider((PropertyEnvironment) props);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree that the method should not be duplicated.

Also, in order to make this PR back-portable to 2.x (it is a requirement, isn't it?), I would use LoggerContext as parameter.

Unless I am mistaken, all HTTP/HTTPS accesses are performed after a LoggerContext is created and the context is passed to the ConfigurationFactory as a parameter (since 2.7). This change would allow 3.x to configure separate credentials for separate web applications.

ppkarwasz pushed a commit that referenced this pull request Aug 16, 2024
This commit includes fixes for:

 - Spring 33450 - Spring shutdown fails due to IllegalStateException (#2062)
 - [LOG4J2-3618] Fix property source comparator

and review suggestions from #2454.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants