Hi,
We have a Spring boot application deployed into a tomcat instance. A tomcat instance can contain multiple webapp instances.
We noticed that Spring Boot logger system was setting system properties using System.setProperty in LoggingSystemProperties. This is very bad in our case since a system property is global to the JVM and therefore to all deployed web applications.
This looks like a major bug to us.
Is there at least a way to disable LoggingApplicationListener?
Comment From: wilkinsona
How are you configuring logging in your Spring Boot applications and which logging-related system properties are problematic?
Comment From: spring-projects-issues
If you would like us to look at this issue, please provide the requested information. If the information is not provided within the next 7 days this issue will be closed.
Comment From: reda-alaoui
Hi @wilkinsona ,
We use logback.
Here is what I found inside org.springframework.boot.logging.LoggingSystemProperties:
public void apply(LogFile logFile) {
PropertyResolver resolver = getPropertyResolver();
setSystemProperty(resolver, EXCEPTION_CONVERSION_WORD, "exception-conversion-word");
setSystemProperty(PID_KEY, new ApplicationPid().toString());
setSystemProperty(resolver, CONSOLE_LOG_PATTERN, "pattern.console");
setSystemProperty(resolver, FILE_LOG_PATTERN, "pattern.file");
setSystemProperty(resolver, FILE_CLEAN_HISTORY_ON_START, "file.clean-history-on-start");
setSystemProperty(resolver, FILE_MAX_HISTORY, "file.max-history");
setSystemProperty(resolver, FILE_MAX_SIZE, "file.max-size");
setSystemProperty(resolver, FILE_TOTAL_SIZE_CAP, "file.total-size-cap");
setSystemProperty(resolver, LOG_LEVEL_PATTERN, "pattern.level");
setSystemProperty(resolver, LOG_DATEFORMAT_PATTERN, "pattern.dateformat");
setSystemProperty(resolver, ROLLING_FILE_NAME_PATTERN, "pattern.rolling-file-name");
if (logFile != null) {
logFile.applyToSystemProperties();
}
}
private PropertyResolver getPropertyResolver() {
if (this.environment instanceof ConfigurableEnvironment) {
PropertySourcesPropertyResolver resolver = new PropertySourcesPropertyResolver(
((ConfigurableEnvironment) this.environment).getPropertySources());
resolver.setIgnoreUnresolvableNestedPlaceholders(true);
return resolver;
}
return this.environment;
}
private void setSystemProperty(PropertyResolver resolver, String systemPropertyName, String propertyName) {
setSystemProperty(systemPropertyName, resolver.getProperty("logging." + propertyName));
}
private void setSystemProperty(String name, String value) {
if (System.getProperty(name) == null && value != null) {
System.setProperty(name, value);
}
}
All these values act as global values. On one Tomcat instance, we cannot configure one value per property and per Spring boot application.
Comment From: wilkinsona
Thanks for the additional information. I asked how you were configuring logging and you didn't directly answer that. From the above, it sounds like you're using the logging.* properties to do so. This contradicts your suggestion to provide a way to disable LoggingApplicationListener as doing so would make all logging.* properties ineffective.
Given the documented behaviour of logging.* properties being transferred from the Spring environment to System properties, I don't think you should use them. You'd also have to stop using them if it was possible to disable LoggingApplicationListener and you had done so due to the becoming ineffective. Instead, I would recommend using logback.xml to configure each application's logging.
We can also consider an enhancement to disable the transfer of the logging.* properties from the Spring environment to system properties, while leaving the rest of LoggingApplicationListener's functionality intact.
Comment From: reda-alaoui
Thanks for the additional information. I asked how you were configuring logging and you didn't directly answer that. From the above, it sounds like you're using the logging.* properties to do so.
No we don't. We use a logback xml file with a custom name because we need to boot logback with the webapp context path as a variable. This variable allows logback to send a webapp logs to a directory named as the webapp context path.
We have now been using the following for years to prevent Spring Boot logging from kicking off:
public class App extends SpringBootServletInitializer {
// ...
@Override
protected WebApplicationContext run(SpringApplication application) {
List<ApplicationListener<?>> filteredListeners =
application.getListeners().stream()
.filter(
// Spring Boot logging configuration does not support multi applications JVM
// See https://github.com/spring-projects/spring-boot/issues/20304
// We exclude it
applicationListener -> !(applicationListener instanceof LoggingApplicationListener))
.filter(
applicationListener ->
!(applicationListener instanceof LoggingSystemShutdownListener))
.collect(Collectors.toList());
application.setListeners(filteredListeners);
return super.run(application);
}
// ...
}