Skip to content

Commit 78d2eac

Browse files
garyrussellartembilan
authored andcommitted
GH-1225: Fix Log4j2 Appender Termination
Replaces #1225 `manager.stop()` was never called to destroy the connection factory, preventing JVM exit. Also protect for re-connecting after stop (both appenders). Tested with a Spring Boot application. **cherry-pick to 2.2.x, 2.1.x, 1.7.x**
1 parent e76069e commit 78d2eac

File tree

2 files changed

+24
-2
lines changed

2 files changed

+24
-2
lines changed

spring-rabbit/src/main/java/org/springframework/amqp/rabbit/log4j2/AmqpAppender.java

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
import org.apache.logging.log4j.core.layout.PatternLayout;
5454
import org.apache.logging.log4j.core.util.Integers;
5555

56+
import org.springframework.amqp.AmqpApplicationContextClosedException;
5657
import org.springframework.amqp.AmqpException;
5758
import org.springframework.amqp.core.DirectExchange;
5859
import org.springframework.amqp.core.Exchange;
@@ -72,6 +73,9 @@
7273
import org.springframework.amqp.rabbit.core.RabbitTemplate;
7374
import org.springframework.amqp.rabbit.support.RabbitExceptionTranslator;
7475
import org.springframework.amqp.utils.JavaUtils;
76+
import org.springframework.context.ApplicationContext;
77+
import org.springframework.context.event.ContextClosedEvent;
78+
import org.springframework.context.support.GenericApplicationContext;
7579
import org.springframework.core.io.Resource;
7680
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
7781
import org.springframework.retry.RetryPolicy;
@@ -354,6 +358,9 @@ protected void doSend(Event event, LogEvent logEvent, MessageProperties amqpProp
354358
message = postProcessMessageBeforeSend(message, event);
355359
this.rabbitTemplate.send(this.manager.exchangeName, routingKey, message);
356360
}
361+
catch (AmqpApplicationContextClosedException e) {
362+
getHandler().error("Could not send log message " + logEvent.getMessage() + " appender is stopped");
363+
}
357364
catch (AmqpException e) {
358365
int retries = event.incrementRetries();
359366
if (this.manager.async && retries < this.manager.maxSenderRetries) {
@@ -380,7 +387,7 @@ public void run() {
380387
@Override
381388
protected boolean stop(long timeout, TimeUnit timeUnit, boolean changeLifeCycleState) {
382389
boolean stopped = super.stop(timeout, timeUnit, changeLifeCycleState);
383-
return stopped || this.manager.stop(timeout, timeUnit);
390+
return this.manager.stop(timeout, timeUnit) || stopped;
384391
}
385392

386393
/**
@@ -449,6 +456,8 @@ protected static class AmqpManager extends AbstractManager {
449456

450457
private static final int DEFAULT_MAX_SENDER_RETRIES = 30;
451458

459+
private final ApplicationContext context = new GenericApplicationContext();
460+
452461
/**
453462
* True to send events on separate threads.
454463
*/
@@ -656,6 +665,7 @@ private boolean activateOptions() {
656665
.withNoConsoleNoAnsi(true)
657666
.build();
658667
this.connectionFactory = new CachingConnectionFactory(rabbitConnectionFactory);
668+
this.connectionFactory.setApplicationContext(this.context);
659669
if (StringUtils.hasText(this.connectionName)) {
660670
this.connectionFactory.setConnectionNameStrategy(cf -> this.connectionName);
661671
}
@@ -745,6 +755,7 @@ protected boolean releaseSub(long timeout, TimeUnit timeUnit) {
745755
this.retryTimer.cancel();
746756
this.senderPool.shutdownNow();
747757
this.connectionFactory.destroy();
758+
this.connectionFactory.onApplicationEvent(new ContextClosedEvent(this.context));
748759
try {
749760
return this.senderPool.awaitTermination(timeout, timeUnit);
750761
}

spring-rabbit/src/main/java/org/springframework/amqp/rabbit/logback/AmqpAppender.java

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2014-2019 the original author or authors.
2+
* Copyright 2014-2020 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.
@@ -32,6 +32,7 @@
3232
import java.util.concurrent.atomic.AtomicBoolean;
3333
import java.util.concurrent.atomic.AtomicInteger;
3434

35+
import org.springframework.amqp.AmqpApplicationContextClosedException;
3536
import org.springframework.amqp.AmqpException;
3637
import org.springframework.amqp.core.DirectExchange;
3738
import org.springframework.amqp.core.Exchange;
@@ -51,6 +52,9 @@
5152
import org.springframework.amqp.rabbit.core.RabbitTemplate;
5253
import org.springframework.amqp.rabbit.support.RabbitExceptionTranslator;
5354
import org.springframework.amqp.utils.JavaUtils;
55+
import org.springframework.context.ApplicationContext;
56+
import org.springframework.context.event.ContextClosedEvent;
57+
import org.springframework.context.support.GenericApplicationContext;
5458
import org.springframework.core.io.Resource;
5559
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
5660
import org.springframework.util.StringUtils;
@@ -120,6 +124,8 @@ public class AmqpAppender extends AppenderBase<ILoggingEvent> {
120124
*/
121125
public static final String THREAD_NAME = "thread";
122126

127+
private final ApplicationContext context = new GenericApplicationContext();
128+
123129
/**
124130
* Name of the exchange to publish log events to.
125131
*/
@@ -682,6 +688,7 @@ public void start() {
682688
this.locationLayout.setContext(getContext());
683689
this.locationLayout.start();
684690
this.connectionFactory = new CachingConnectionFactory(rabbitConnectionFactory);
691+
this.connectionFactory.setApplicationContext(this.context);
685692
if (StringUtils.hasText(this.connectionName)) {
686693
this.connectionFactory.setConnectionNameStrategy(cf -> this.connectionName);
687694
}
@@ -797,6 +804,7 @@ public void stop() {
797804
}
798805
if (null != this.connectionFactory) {
799806
this.connectionFactory.destroy();
807+
this.connectionFactory.onApplicationEvent(new ContextClosedEvent(this.context));
800808
}
801809
this.retryTimer.cancel();
802810
this.routingKeyLayout.stop();
@@ -956,6 +964,9 @@ private void doSend(RabbitTemplate rabbitTemplate, final Event event, ILoggingEv
956964
message = postProcessMessageBeforeSend(message, event);
957965
rabbitTemplate.send(AmqpAppender.this.exchangeName, routingKey, message);
958966
}
967+
catch (AmqpApplicationContextClosedException e) {
968+
addError("Could not send log message " + logEvent.getMessage() + " appender is stopped");
969+
}
959970
catch (AmqpException e) {
960971
int retries = event.incrementRetries();
961972
if (retries < AmqpAppender.this.maxSenderRetries) {

0 commit comments

Comments
 (0)