From c0b19e61b552c93a78a854c3be566548b0c5c3ee Mon Sep 17 00:00:00 2001 From: Artem Bilan Date: Tue, 5 Apr 2016 12:19:27 -0400 Subject: [PATCH] INT-3977: Improve `LoggingHandler` for JavaConfig JIRA: https://jira.spring.io/browse/INT-3977 * Add `Level` ctor * Add `setLogExpression(Expression)` and `setLogExpressionString(String)` * Deprecate existing `setExpression(String)` in favor of those new * Some refactor for redundant code around `evaluationContext` * Fix tests according a new `LoggingHandler` logic * Add JavaConfig sample to the Reference Manual --- .../xml/LoggingChannelAdapterParser.java | 6 +- .../integration/handler/LoggingHandler.java | 62 +++++++++++++++---- .../handler/LoggingHandlerTests.java | 16 +++-- src/reference/asciidoc/logging-adapter.adoc | 41 ++++++++++++ 4 files changed, 108 insertions(+), 17 deletions(-) diff --git a/spring-integration-core/src/main/java/org/springframework/integration/config/xml/LoggingChannelAdapterParser.java b/spring-integration-core/src/main/java/org/springframework/integration/config/xml/LoggingChannelAdapterParser.java index 6178e0f805..4a03edbc21 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/config/xml/LoggingChannelAdapterParser.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/config/xml/LoggingChannelAdapterParser.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2014 the original author or authors. + * Copyright 2002-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -28,6 +28,8 @@ import org.springframework.util.StringUtils; * Parser for the 'logging-channel-adapter' element. * * @author Mark Fisher + * @author Artem Bilan + * * @since 1.0.1 */ public class LoggingChannelAdapterParser extends AbstractOutboundChannelAdapterParser { @@ -47,7 +49,7 @@ public class LoggingChannelAdapterParser extends AbstractOutboundChannelAdapterP builder.addPropertyValue("shouldLogFullMessage", logFullMessage); } IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "logger-name"); - IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "expression"); + IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "expression", "logExpressionString"); return builder.getBeanDefinition(); } diff --git a/spring-integration-core/src/main/java/org/springframework/integration/handler/LoggingHandler.java b/spring-integration-core/src/main/java/org/springframework/integration/handler/LoggingHandler.java index 7573c01d19..6f8bb4f1ac 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/handler/LoggingHandler.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/handler/LoggingHandler.java @@ -38,6 +38,7 @@ import org.springframework.util.StringUtils; * * @author Mark Fisher * @author Gary Russell + * @author Artem Bilan * @since 1.0.1 */ public class LoggingHandler extends AbstractMessageHandler { @@ -68,9 +69,10 @@ public class LoggingHandler extends AbstractMessageHandler { * The valid levels are: FATAL, ERROR, WARN, INFO, DEBUG, or TRACE *

* @param level The level. + * @see LoggingHandler(Level) */ public LoggingHandler(String level) { - Assert.notNull(level, "'level' cannot be null"); + Assert.hasText(level, "'level' cannot be empty"); try { this.level = Level.valueOf(level.toUpperCase()); } @@ -79,14 +81,50 @@ public class LoggingHandler extends AbstractMessageHandler { + "'. The (case-insensitive) supported values are: " + StringUtils.arrayToCommaDelimitedString(Level.values())); } - this.evaluationContext = ExpressionUtils.createStandardEvaluationContext(); - this.expression = EXPRESSION_PARSER.parseExpression("payload"); } + /** + * Create a {@link LoggingHandler} with the given log {@link Level}. + * @param level the {@link Level} to use. + * @since 4.3 + */ + public LoggingHandler(Level level) { + Assert.notNull(level, "'level' cannot be null"); + this.level = level; + } + + /** + * Set a SpEL expression string to use. + * @param expressionString the SpEL expression string to use. + * @deprecated in favor of {@link #setLogExpressionString(String)} + */ + @Deprecated public void setExpression(String expressionString) { - Assert.isTrue(!(this.shouldLogFullMessageSet), "Cannot set both 'expression' AND 'shouldLogFullMessage' properties"); + setLogExpressionString(expressionString); + } + + /** + * Set a SpEL expression string to use. + * @param expressionString the SpEL expression string to use. + * @since 4.3 + * @see #setLogExpression(Expression) + */ + public void setLogExpressionString(String expressionString) { + Assert.hasText(expressionString, "'expressionString' must not be empty"); + setLogExpression(EXPRESSION_PARSER.parseExpression(expressionString)); + } + + /** + * Set an {@link Expression} to evaluate a log entry at runtime against the request {@link Message}. + * @param expression the {@link Expression} to use. + * @since 4.3 + * @see #setLogExpressionString(String) + */ + public void setLogExpression(Expression expression) { + Assert.isTrue(!(this.shouldLogFullMessageSet), + "Cannot set both 'expression' AND 'shouldLogFullMessage' properties"); this.expressionSet = true; - this.expression = EXPRESSION_PARSER.parseExpression(expressionString); + this.expression = expression; } /** @@ -97,8 +135,7 @@ public class LoggingHandler extends AbstractMessageHandler { } /** - * Set the logging {@link Level}. - * + * Set the logging {@link Level} to change the behavior at runtime. * @param level the level. */ public void setLevel(Level level) { @@ -114,14 +151,14 @@ public class LoggingHandler extends AbstractMessageHandler { /** * Specify whether to log the full Message. Otherwise, only the payload will be logged. This value is * false by default. - * * @param shouldLogFullMessage true if the complete message should be logged. */ public void setShouldLogFullMessage(boolean shouldLogFullMessage) { Assert.isTrue(!(this.expressionSet), "Cannot set both 'expression' AND 'shouldLogFullMessage' properties"); this.shouldLogFullMessageSet = true; - this.expression = (shouldLogFullMessage) ? EXPRESSION_PARSER.parseExpression("#root") : EXPRESSION_PARSER - .parseExpression("payload"); + this.expression = (shouldLogFullMessage) + ? EXPRESSION_PARSER.parseExpression("#root") + : EXPRESSION_PARSER.parseExpression("payload"); } @Override @@ -132,7 +169,10 @@ public class LoggingHandler extends AbstractMessageHandler { @Override protected void onInit() throws Exception { super.onInit(); - this.evaluationContext = ExpressionUtils.createStandardEvaluationContext(this.getBeanFactory()); + this.evaluationContext = ExpressionUtils.createStandardEvaluationContext(getBeanFactory()); + if (this.expression == null) { + this.expression = EXPRESSION_PARSER.parseExpression("payload"); + } } @Override diff --git a/spring-integration-core/src/test/java/org/springframework/integration/handler/LoggingHandlerTests.java b/spring-integration-core/src/test/java/org/springframework/integration/handler/LoggingHandlerTests.java index 2aabc4edf3..57cd9f9a7c 100644 --- a/spring-integration-core/src/test/java/org/springframework/integration/handler/LoggingHandlerTests.java +++ b/spring-integration-core/src/test/java/org/springframework/integration/handler/LoggingHandlerTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2014 the original author or authors. + * Copyright 2002-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,6 +18,7 @@ package org.springframework.integration.handler; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; @@ -29,6 +30,7 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mockito; import org.springframework.beans.DirectFieldAccessor; +import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.expression.EvaluationContext; import org.springframework.expression.Expression; @@ -61,7 +63,7 @@ public class LoggingHandlerTests { @Test public void assertMutuallyExclusive() { LoggingHandler loggingHandler = new LoggingHandler("INFO"); - loggingHandler.setExpression("'foo'"); + loggingHandler.setLogExpressionString("'foo'"); try { loggingHandler.setShouldLogFullMessage(true); fail("Expected IllegalArgumentException"); @@ -73,7 +75,7 @@ public class LoggingHandlerTests { loggingHandler = new LoggingHandler("INFO"); loggingHandler.setShouldLogFullMessage(true); try { - loggingHandler.setExpression("'foo'"); + loggingHandler.setLogExpressionString("'foo'"); fail("Expected IllegalArgumentException"); } catch (IllegalArgumentException e) { @@ -84,6 +86,9 @@ public class LoggingHandlerTests { @Test public void testDontEvaluateIfNotEnabled() { LoggingHandler loggingHandler = new LoggingHandler("INFO"); + loggingHandler.setBeanFactory(mock(BeanFactory.class)); + loggingHandler.afterPropertiesSet(); + DirectFieldAccessor accessor = new DirectFieldAccessor(loggingHandler); Log log = (Log) accessor.getPropertyValue("messageLogger"); log = spy(log); @@ -102,7 +107,10 @@ public class LoggingHandlerTests { @Test public void testChangeLevel() { - LoggingHandler loggingHandler = new LoggingHandler("INFO"); + LoggingHandler loggingHandler = new LoggingHandler(Level.INFO); + loggingHandler.setBeanFactory(mock(BeanFactory.class)); + loggingHandler.afterPropertiesSet(); + DirectFieldAccessor accessor = new DirectFieldAccessor(loggingHandler); Log log = (Log) accessor.getPropertyValue("messageLogger"); log = spy(log); diff --git a/src/reference/asciidoc/logging-adapter.adoc b/src/reference/asciidoc/logging-adapter.adoc index 39c9d46ed4..e822932fc1 100644 --- a/src/reference/asciidoc/logging-adapter.adoc +++ b/src/reference/asciidoc/logging-adapter.adoc @@ -40,3 +40,44 @@ This attribute cannot be specified if `expression` is specified. <5> Specifies the _name_ of the logger (known as `category` in `log4j`) used for log messages created by this adapter. This enables setting the log name (in the logging subsystem) for individual adapters. By default, all adapters will log under the name `org.springframework.integration.handler.LoggingHandler`. + +==== Configuring with Java Configuration + +The following Spring Boot application provides an example of configuring the `LoggingHandler` using Java configuration: +[source, java] +---- +@SpringBootApplication +public class LoggingJavaApplication { + + public static void main(String[] args) { + ConfigurableApplicationContext context = + new SpringApplicationBuilder(LoggingJavaApplication.class) + .web(false) + .run(args); + MyGateway gateway = context.getBean(MyGateway.class); + gateway.sendToLogger("foo"); + } + + @Bean + public MessageChannel logInputChannel() { + return new DirectChannel(); + } + + @Bean + @ServiceActivator(inputChannel = "logChannel") + public LoggingHandler logging() { + LoggingHandler adapter = new LoggingHandler(LoggingHandler.Level.DEBUG); + adapter.setLoggerName("TEST_LOGGER"); + adapter.setLogExpressionString("headers.id + ': ' + payload"); + return adapter; + } + + @MessagingGateway(defaultRequestChannel = "logChannel") + public interface MyGateway { + + void sendToLogger(String data); + + } + +} +----