Skip to content

Commit ef69ae6

Browse files
committed
Ensure logging filters are removed on cleanup
Update `Log4J2LoggingSystem` and `LogbackLoggingSystem` to ensure that filters are removed when the `cleanUp` method is called. Prior to this commit application failures would not remove the filter and no log messages would appear. The `LoggingApplicationListener` has also been updated since it previously failed to handle `ApplicationFailureEvents`. Finally `EventPublishingRunListener` and `DelegatingApplicationListener` have been updated to deal with `null` parameters and to cope with listener errors. Fixes gh-7758
1 parent 2cf93f8 commit ef69ae6

File tree

7 files changed

+74
-33
lines changed

7 files changed

+74
-33
lines changed

spring-boot/src/main/java/org/springframework/boot/SpringApplication.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2016 the original author or authors.
2+
* Copyright 2012-2017 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -1233,7 +1233,6 @@ public static int exit(ApplicationContext context,
12331233
finally {
12341234
close(context);
12351235
}
1236-
12371236
}
12381237
catch (Exception ex) {
12391238
ex.printStackTrace();

spring-boot/src/main/java/org/springframework/boot/context/config/DelegatingApplicationListener.java

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2014 the original author or authors.
2+
* Copyright 2012-2017 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -17,6 +17,7 @@
1717
package org.springframework.boot.context.config;
1818

1919
import java.util.ArrayList;
20+
import java.util.Collections;
2021
import java.util.List;
2122

2223
import org.springframework.beans.BeanUtils;
@@ -70,8 +71,11 @@ public void onApplicationEvent(ApplicationEvent event) {
7071

7172
@SuppressWarnings("unchecked")
7273
private List<ApplicationListener<ApplicationEvent>> getListeners(
73-
ConfigurableEnvironment env) {
74-
String classNames = env.getProperty(PROPERTY_NAME);
74+
ConfigurableEnvironment environment) {
75+
if (environment == null) {
76+
return Collections.emptyList();
77+
}
78+
String classNames = environment.getProperty(PROPERTY_NAME);
7579
List<ApplicationListener<ApplicationEvent>> listeners = new ArrayList<ApplicationListener<ApplicationEvent>>();
7680
if (StringUtils.hasLength(classNames)) {
7781
for (String className : StringUtils.commaDelimitedListToSet(classNames)) {

spring-boot/src/main/java/org/springframework/boot/context/event/EventPublishingRunListener.java

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2016 the original author or authors.
2+
* Copyright 2012-2017 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -16,6 +16,9 @@
1616

1717
package org.springframework.boot.context.event;
1818

19+
import org.apache.commons.logging.Log;
20+
import org.apache.commons.logging.LogFactory;
21+
1922
import org.springframework.boot.SpringApplication;
2023
import org.springframework.boot.SpringApplicationRunListener;
2124
import org.springframework.context.ApplicationContextAware;
@@ -25,6 +28,7 @@
2528
import org.springframework.context.event.SimpleApplicationEventMulticaster;
2629
import org.springframework.core.Ordered;
2730
import org.springframework.core.env.ConfigurableEnvironment;
31+
import org.springframework.util.ErrorHandler;
2832

2933
/**
3034
* {@link SpringApplicationRunListener} to publish {@link SpringApplicationEvent}s.
@@ -41,7 +45,7 @@ public class EventPublishingRunListener implements SpringApplicationRunListener,
4145

4246
private final String[] args;
4347

44-
private final ApplicationEventMulticaster initialMulticaster;
48+
private final SimpleApplicationEventMulticaster initialMulticaster;
4549

4650
public EventPublishingRunListener(SpringApplication application, String[] args) {
4751
this.application = application;
@@ -88,9 +92,18 @@ public void contextLoaded(ConfigurableApplicationContext context) {
8892

8993
@Override
9094
public void finished(ConfigurableApplicationContext context, Throwable exception) {
91-
// Listeners have been registered to the application context so we should
92-
// use it at this point
93-
context.publishEvent(getFinishedEvent(context, exception));
95+
SpringApplicationEvent event = getFinishedEvent(context, exception);
96+
if (context != null) {
97+
// Listeners have been registered to the application context so we should
98+
// use it at this point if we can
99+
context.publishEvent(event);
100+
}
101+
else {
102+
if (event instanceof ApplicationFailedEvent) {
103+
this.initialMulticaster.setErrorHandler(new LoggingErrorHandler());
104+
}
105+
this.initialMulticaster.multicastEvent(event);
106+
}
94107
}
95108

96109
private SpringApplicationEvent getFinishedEvent(
@@ -102,4 +115,15 @@ private SpringApplicationEvent getFinishedEvent(
102115
return new ApplicationReadyEvent(this.application, this.args, context);
103116
}
104117

118+
private static class LoggingErrorHandler implements ErrorHandler {
119+
120+
private static Log logger = LogFactory.getLog(EventPublishingRunListener.class);
121+
122+
@Override
123+
public void handleError(Throwable throwable) {
124+
logger.warn("Error calling ApplicationEventListener", throwable);
125+
}
126+
127+
}
128+
105129
}

spring-boot/src/main/java/org/springframework/boot/logging/LoggingApplicationListener.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2016 the original author or authors.
2+
* Copyright 2012-2017 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -163,7 +163,7 @@ public class LoggingApplicationListener implements GenericApplicationListener {
163163

164164
private static Class<?>[] EVENT_TYPES = { ApplicationStartedEvent.class,
165165
ApplicationEnvironmentPreparedEvent.class, ApplicationPreparedEvent.class,
166-
ContextClosedEvent.class };
166+
ContextClosedEvent.class, ApplicationFailedEvent.class };
167167

168168
private static Class<?>[] SOURCE_TYPES = { SpringApplication.class,
169169
ApplicationContext.class };

spring-boot/src/main/java/org/springframework/boot/logging/log4j2/Log4J2LoggingSystem.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2016 the original author or authors.
2+
* Copyright 2012-2017 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -218,6 +218,7 @@ public void cleanUp() {
218218
super.cleanUp();
219219
LoggerContext loggerContext = getLoggerContext();
220220
markAsUninitialized(loggerContext);
221+
loggerContext.getConfiguration().removeFilter(FILTER);
221222
}
222223

223224
private LoggerConfig getLoggerConfig(String name) {

spring-boot/src/main/java/org/springframework/boot/logging/logback/LogbackLoggingSystem.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2016 the original author or authors.
2+
* Copyright 2012-2017 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -193,9 +193,11 @@ private void addLevelChangePropagator(LoggerContext loggerContext) {
193193

194194
@Override
195195
public void cleanUp() {
196-
markAsUninitialized(getLoggerContext());
196+
LoggerContext context = getLoggerContext();
197+
markAsUninitialized(context);
197198
super.cleanUp();
198-
getLoggerContext().getStatusManager().clear();
199+
context.getStatusManager().clear();
200+
context.getTurboFilterList().remove(FILTER);
199201
}
200202

201203
@Override

spring-boot/src/test/java/org/springframework/boot/logging/LoggingApplicationListenerTests.java

Lines changed: 28 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2016 the original author or authors.
2+
* Copyright 2012-2017 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -41,7 +41,10 @@
4141
import org.springframework.boot.context.event.ApplicationStartedEvent;
4242
import org.springframework.boot.logging.java.JavaLoggingSystem;
4343
import org.springframework.boot.testutil.InternalOutputCapture;
44+
import org.springframework.context.ApplicationEvent;
45+
import org.springframework.context.ApplicationListener;
4446
import org.springframework.context.event.ContextClosedEvent;
47+
import org.springframework.context.event.SimpleApplicationEventMulticaster;
4548
import org.springframework.context.support.GenericApplicationContext;
4649
import org.springframework.test.context.support.TestPropertySourceUtils;
4750
import org.springframework.test.util.ReflectionTestUtils;
@@ -83,8 +86,7 @@ public class LoggingApplicationListenerTests {
8386
public void init() throws SecurityException, IOException {
8487
LogManager.getLogManager().readConfiguration(
8588
JavaLoggingSystem.class.getResourceAsStream("logging.properties"));
86-
this.initializer.onApplicationEvent(
87-
new ApplicationStartedEvent(new SpringApplication(), NO_ARGS));
89+
multicastEvent(new ApplicationStartedEvent(new SpringApplication(), NO_ARGS));
8890
new File("target/foo.log").delete();
8991
new File(tmpDir() + "/spring.log").delete();
9092
}
@@ -352,8 +354,8 @@ public void parseArgsDisabled() throws Exception {
352354
public void parseArgsDoesntReplace() throws Exception {
353355
this.initializer.setSpringBootLogging(LogLevel.ERROR);
354356
this.initializer.setParseArgs(false);
355-
this.initializer.onApplicationEvent(new ApplicationStartedEvent(
356-
this.springApplication, new String[] { "--debug" }));
357+
multicastEvent(new ApplicationStartedEvent(this.springApplication,
358+
new String[] { "--debug" }));
357359
this.initializer.initialize(this.context.getEnvironment(),
358360
this.context.getClassLoader());
359361
this.logger.debug("testatdebug");
@@ -363,7 +365,7 @@ public void parseArgsDoesntReplace() throws Exception {
363365
@Test
364366
public void bridgeHandlerLifecycle() throws Exception {
365367
assertThat(bridgeHandlerInstalled()).isTrue();
366-
this.initializer.onApplicationEvent(new ContextClosedEvent(this.context));
368+
multicastEvent(new ContextClosedEvent(this.context));
367369
assertThat(bridgeHandlerInstalled()).isFalse();
368370
}
369371

@@ -396,7 +398,7 @@ public void shutdownHookIsNotRegisteredByDefault() throws Exception {
396398
TestLoggingApplicationListener listener = new TestLoggingApplicationListener();
397399
System.setProperty(LoggingSystem.class.getName(),
398400
TestShutdownHandlerLoggingSystem.class.getName());
399-
listener.onApplicationEvent(
401+
multicastEvent(listener,
400402
new ApplicationStartedEvent(new SpringApplication(), NO_ARGS));
401403
listener.initialize(this.context.getEnvironment(), this.context.getClassLoader());
402404
assertThat(listener.shutdownHook).isNull();
@@ -409,7 +411,7 @@ public void shutdownHookCanBeRegistered() throws Exception {
409411
TestShutdownHandlerLoggingSystem.class.getName());
410412
TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.context,
411413
"logging.register_shutdown_hook=true");
412-
listener.onApplicationEvent(
414+
multicastEvent(listener,
413415
new ApplicationStartedEvent(new SpringApplication(), NO_ARGS));
414416
listener.initialize(this.context.getEnvironment(), this.context.getClassLoader());
415417
assertThat(listener.shutdownHook).isNotNull();
@@ -422,29 +424,29 @@ public void shutdownHookCanBeRegistered() throws Exception {
422424
public void closingContextCleansUpLoggingSystem() {
423425
System.setProperty(LoggingSystem.SYSTEM_PROPERTY,
424426
TestCleanupLoggingSystem.class.getName());
425-
this.initializer.onApplicationEvent(
427+
multicastEvent(
426428
new ApplicationStartedEvent(this.springApplication, new String[0]));
427429
TestCleanupLoggingSystem loggingSystem = (TestCleanupLoggingSystem) ReflectionTestUtils
428430
.getField(this.initializer, "loggingSystem");
429431
assertThat(loggingSystem.cleanedUp).isFalse();
430-
this.initializer.onApplicationEvent(new ContextClosedEvent(this.context));
432+
multicastEvent(new ContextClosedEvent(this.context));
431433
assertThat(loggingSystem.cleanedUp).isTrue();
432434
}
433435

434436
@Test
435437
public void closingChildContextDoesNotCleanUpLoggingSystem() {
436438
System.setProperty(LoggingSystem.SYSTEM_PROPERTY,
437439
TestCleanupLoggingSystem.class.getName());
438-
this.initializer.onApplicationEvent(
440+
multicastEvent(
439441
new ApplicationStartedEvent(this.springApplication, new String[0]));
440442
TestCleanupLoggingSystem loggingSystem = (TestCleanupLoggingSystem) ReflectionTestUtils
441443
.getField(this.initializer, "loggingSystem");
442444
assertThat(loggingSystem.cleanedUp).isFalse();
443445
GenericApplicationContext childContext = new GenericApplicationContext();
444446
childContext.setParent(this.context);
445-
this.initializer.onApplicationEvent(new ContextClosedEvent(childContext));
447+
multicastEvent(new ContextClosedEvent(childContext));
446448
assertThat(loggingSystem.cleanedUp).isFalse();
447-
this.initializer.onApplicationEvent(new ContextClosedEvent(this.context));
449+
multicastEvent(new ContextClosedEvent(this.context));
448450
assertThat(loggingSystem.cleanedUp).isTrue();
449451
childContext.close();
450452
}
@@ -491,17 +493,26 @@ public void logFilePropertiesCanReferenceSystemProperties() {
491493
public void applicationFailedEventCleansUpLoggingSystem() {
492494
System.setProperty(LoggingSystem.SYSTEM_PROPERTY,
493495
TestCleanupLoggingSystem.class.getName());
494-
this.initializer.onApplicationEvent(
496+
multicastEvent(
495497
new ApplicationStartedEvent(this.springApplication, new String[0]));
496498
TestCleanupLoggingSystem loggingSystem = (TestCleanupLoggingSystem) ReflectionTestUtils
497499
.getField(this.initializer, "loggingSystem");
498500
assertThat(loggingSystem.cleanedUp).isFalse();
499-
this.initializer
500-
.onApplicationEvent(new ApplicationFailedEvent(this.springApplication,
501-
new String[0], new GenericApplicationContext(), new Exception()));
501+
multicastEvent(new ApplicationFailedEvent(this.springApplication, new String[0],
502+
new GenericApplicationContext(), new Exception()));
502503
assertThat(loggingSystem.cleanedUp).isTrue();
503504
}
504505

506+
private void multicastEvent(ApplicationEvent event) {
507+
multicastEvent(this.initializer, event);
508+
}
509+
510+
private void multicastEvent(ApplicationListener<?> listener, ApplicationEvent event) {
511+
SimpleApplicationEventMulticaster multicaster = new SimpleApplicationEventMulticaster();
512+
multicaster.addApplicationListener(listener);
513+
multicaster.multicastEvent(event);
514+
}
515+
505516
private boolean bridgeHandlerInstalled() {
506517
Logger rootLogger = LogManager.getLogManager().getLogger("");
507518
Handler[] handlers = rootLogger.getHandlers();

0 commit comments

Comments
 (0)