GH-3555: Change logger order for errorChannel (#3949)

* GH-3555: Change logger order for errorChannel

Fixes https://github.com/spring-projects/spring-integration/issues/3555

The default global `errorChannel` has a `LoggingHandler` as a subscriber.
It is subscribed without any `order` which may lose logging messages,
when another subscriber with re-throw is present.

* Set default `LoggingHandler` on the default `errorChannel` to `Ordered.LOWEST_PRECEDENCE - 100`
to give a room for custom subscribers without an `order` and still get error logged

* Add extra note in docs about an order for custom subcribers

Co-authored-by: Gary Russell <grussell@vmware.com>

Co-authored-by: Gary Russell <grussell@vmware.com>
This commit is contained in:
Artem Bilan
2022-11-16 15:10:26 -05:00
committed by GitHub
parent e9257958fe
commit 508fb167df
3 changed files with 19 additions and 0 deletions

View File

@@ -36,12 +36,14 @@ import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.core.Ordered;
import org.springframework.core.log.LogAccessor;
import org.springframework.integration.channel.ChannelUtils;
import org.springframework.integration.channel.DefaultHeaderChannelRegistry;
import org.springframework.integration.channel.MessagePublishingErrorHandler;
import org.springframework.integration.channel.NullChannel;
import org.springframework.integration.channel.PublishSubscribeChannel;
import org.springframework.integration.config.xml.IntegrationNamespaceUtils;
import org.springframework.integration.context.IntegrationContextUtils;
import org.springframework.integration.context.IntegrationProperties;
import org.springframework.integration.handler.LoggingHandler;
@@ -221,6 +223,7 @@ public class DefaultConfiguringBeanFactoryPostProcessor
BeanDefinitionBuilder.genericBeanDefinition(LoggingHandler.class,
() -> new LoggingHandler(LoggingHandler.Level.ERROR))
.addConstructorArgValue(LoggingHandler.Level.ERROR)
.addPropertyValue(IntegrationNamespaceUtils.ORDER, Ordered.LOWEST_PRECEDENCE - 100)
.getBeanDefinition());
BeanDefinitionBuilder loggingEndpointBuilder =

View File

@@ -16,12 +16,17 @@
package org.springframework.integration.config.xml;
import java.util.Set;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.Ordered;
import org.springframework.integration.channel.PublishSubscribeChannel;
import org.springframework.integration.handler.LoggingHandler;
import org.springframework.integration.test.util.TestUtils;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.MessageHandler;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
import static org.assertj.core.api.Assertions.assertThat;
@@ -43,6 +48,15 @@ public class ErrorChannelAutoCreationTests {
.isTrue();
assertThat(TestUtils.getPropertyValue(this.errorChannel, "dispatcher.ignoreFailures", Boolean.class))
.isTrue();
@SuppressWarnings("unchecked")
Set<MessageHandler> handlers =
TestUtils.getPropertyValue(this.errorChannel, "dispatcher.handlers", Set.class);
assertThat(handlers).first()
.isInstanceOf(LoggingHandler.class)
.extracting("order")
.isEqualTo(Ordered.LOWEST_PRECEDENCE - 100);
}
}

View File

@@ -52,6 +52,8 @@ QueueChannel errorChannel() {
====
NOTE: The default error channel is a `PublishSubscribeChannel`.
By default, it has a `LoggingHandler` as a subscriber with an `ERROR` logging level and subscription order as `Ordered.LOWEST_PRECEDENCE - 100`.
If you subscribe additional consuming endpoints, that might throw an exception, and you don't want to preempt the logging, ensure that the additional handlers have a higher order.
The most important thing to understand here is that the messaging-based error handling applies only to exceptions that are thrown by a Spring Integration task that is executing within a `TaskExecutor`.
This does not apply to exceptions thrown by a handler that operates within the same thread as the sender (for example, through a `DirectChannel` as described earlier in this section).