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 89f5f38d27..fe673efffa 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 @@ -18,6 +18,7 @@ package org.springframework.integration.handler; import java.io.PrintWriter; import java.io.StringWriter; +import java.io.Writer; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -32,33 +33,36 @@ import org.springframework.util.StringUtils; /** * MessageHandler implementation that simply logs the Message or its payload depending on the value of the - * 'shouldLogFullMessage' property. If logging the payload, and it is assignable to Throwable, it will log the stack + * 'shouldLogFullMessage' or SpEL 'logExpression' property. + * If logging the payload, and it is assignable to Throwable, it will log the stack * trace. By default, it will log the payload only. * * @author Mark Fisher * @author Gary Russell * @author Artem Bilan + * @author Andriy Kryvtsun * @since 1.0.1 */ public class LoggingHandler extends AbstractMessageHandler { public enum Level { + FATAL, ERROR, WARN, INFO, DEBUG, TRACE + } - private volatile Expression expression; - - private volatile boolean expressionSet; - - private volatile boolean shouldLogFullMessageSet; - private volatile Level level; - private volatile EvaluationContext evaluationContext; + private volatile boolean expressionSet; + + private volatile Expression expression = EXPRESSION_PARSER.parseExpression("payload"); + + private volatile EvaluationContext evaluationContext = ExpressionUtils.createStandardEvaluationContext(); + + private volatile boolean shouldLogFullMessageSet; private volatile Log messageLogger = this.logger; - /** * Create a LoggingHandler with the given log level (case-insensitive). *

@@ -68,9 +72,13 @@ public class LoggingHandler extends AbstractMessageHandler { * @see #LoggingHandler(Level) */ public LoggingHandler(String level) { + this(convertLevel(level)); + } + + private static Level convertLevel(String level) { Assert.hasText(level, "'level' cannot be empty"); try { - this.level = Level.valueOf(level.toUpperCase()); + return Level.valueOf(level.toUpperCase()); } catch (IllegalArgumentException e) { throw new IllegalArgumentException("Invalid log level '" + level @@ -85,8 +93,7 @@ public class LoggingHandler extends AbstractMessageHandler { * @since 4.3 */ public LoggingHandler(Level level) { - Assert.notNull(level, "'level' cannot be null"); - this.level = level; + doSetLevel(level); } /** @@ -125,6 +132,10 @@ public class LoggingHandler extends AbstractMessageHandler { * @param level the level. */ public void setLevel(Level level) { + doSetLevel(level); + } + + private void doSetLevel(Level level) { Assert.notNull(level, "'level' cannot be null"); this.level = level; } @@ -142,7 +153,7 @@ public class LoggingHandler extends AbstractMessageHandler { public void setShouldLogFullMessage(boolean shouldLogFullMessage) { Assert.isTrue(!(this.expressionSet), "Cannot set both 'expression' AND 'shouldLogFullMessage' properties"); this.shouldLogFullMessageSet = true; - this.expression = (shouldLogFullMessage) + this.expression = shouldLogFullMessage ? EXPRESSION_PARSER.parseExpression("#root") : EXPRESSION_PARSER.parseExpression("payload"); } @@ -156,66 +167,69 @@ public class LoggingHandler extends AbstractMessageHandler { protected void onInit() throws Exception { super.onInit(); this.evaluationContext = ExpressionUtils.createStandardEvaluationContext(getBeanFactory()); - if (this.expression == null) { - this.expression = EXPRESSION_PARSER.parseExpression("payload"); - } } @Override protected void handleMessageInternal(Message message) throws Exception { switch (this.level) { - case FATAL: - if (this.messageLogger.isFatalEnabled()) { - this.messageLogger.fatal(createLogMessage(message)); - } - break; - case ERROR: - if (this.messageLogger.isErrorEnabled()) { - this.messageLogger.error(createLogMessage(message)); - } - break; - case WARN: - if (this.messageLogger.isWarnEnabled()) { - this.messageLogger.warn(createLogMessage(message)); - } - break; - case INFO: - if (this.messageLogger.isInfoEnabled()) { - this.messageLogger.info(createLogMessage(message)); - } - break; - case DEBUG: - if (this.messageLogger.isDebugEnabled()) { - this.messageLogger.debug(createLogMessage(message)); - } - break; - case TRACE: - if (this.messageLogger.isTraceEnabled()) { - this.messageLogger.trace(createLogMessage(message)); - } - break; - default: - throw new IllegalStateException("Level '" + this.level + "' is not supported"); + case FATAL: + if (this.messageLogger.isFatalEnabled()) { + this.messageLogger.fatal(createLogMessage(message)); + } + break; + case ERROR: + if (this.messageLogger.isErrorEnabled()) { + this.messageLogger.error(createLogMessage(message)); + } + break; + case WARN: + if (this.messageLogger.isWarnEnabled()) { + this.messageLogger.warn(createLogMessage(message)); + } + break; + case INFO: + if (this.messageLogger.isInfoEnabled()) { + this.messageLogger.info(createLogMessage(message)); + } + break; + case DEBUG: + if (this.messageLogger.isDebugEnabled()) { + this.messageLogger.debug(createLogMessage(message)); + } + break; + case TRACE: + if (this.messageLogger.isTraceEnabled()) { + this.messageLogger.trace(createLogMessage(message)); + } + break; + default: + throw new IllegalStateException("Level '" + this.level + "' is not supported"); } } - private Object createLogMessage(Message message) { Object logMessage = this.expression.getValue(this.evaluationContext, message); - if (logMessage instanceof Throwable) { - StringWriter stringWriter = new StringWriter(); - if (logMessage instanceof AggregateMessageDeliveryException) { - stringWriter.append(((Throwable) logMessage).getMessage()); - for (Exception exception : ((AggregateMessageDeliveryException) logMessage).getAggregatedExceptions()) { - exception.printStackTrace(new PrintWriter(stringWriter, true)); - } + return logMessage instanceof Throwable + ? createLogMessage((Throwable) logMessage) + : logMessage; + } + + private String createLogMessage(Throwable throwable) { + StringWriter stringWriter = new StringWriter(); + if (throwable instanceof AggregateMessageDeliveryException) { + stringWriter.append(throwable.getMessage()); + for (Exception exception : ((AggregateMessageDeliveryException) throwable).getAggregatedExceptions()) { + printStackTrace(exception, stringWriter); } - else { - ((Throwable) logMessage).printStackTrace(new PrintWriter(stringWriter, true)); - } - logMessage = stringWriter.toString(); } - return logMessage; + else { + printStackTrace(throwable, stringWriter); + } + return stringWriter.toString(); + } + + private void printStackTrace(Throwable throwable, Writer writer) { + throwable.printStackTrace(new PrintWriter(writer, true)); } } 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 57cd9f9a7c..56fcb23285 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 @@ -29,22 +29,24 @@ import org.apache.commons.logging.Log; 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; +import org.springframework.integration.handler.LoggingHandler.Level; +import org.springframework.integration.support.MessageBuilder; import org.springframework.messaging.Message; import org.springframework.messaging.MessageChannel; -import org.springframework.integration.handler.LoggingHandler.Level; import org.springframework.messaging.support.GenericMessage; -import org.springframework.integration.support.MessageBuilder; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; /** * @author Mark Fisher * @author Artem Bilan + * @author Andriy Kryvtsun * @since 2.0 */ @ContextConfiguration @@ -126,6 +128,22 @@ public class LoggingHandlerTests { verify(log, times(1)).warn(Mockito.anyString()); } + @Test + public void testUsageWithoutSpringInitialization() { + LoggingHandler loggingHandler = new LoggingHandler("ERROR"); + DirectFieldAccessor accessor = new DirectFieldAccessor(loggingHandler); + Log log = (Log) accessor.getPropertyValue("messageLogger"); + log = spy(log); + accessor.setPropertyValue("messageLogger", log); + + String testPayload = "TEST_PAYLOAD"; + Message message = MessageBuilder.withPayload(testPayload).build(); + + loggingHandler.handleMessage(message); + + verify(log).error(testPayload); + } + public static class TestBean { private final String name;