title: SpringBoot Logging - Stacktrace in every log statement
body: <p>I have been developing an emailing service in <strong>SpringBoot</strong> and for logging I am using <strong>slf4j</strong>. The application is working as expected, except for the logging part. While running it on my machine the logging is working perfectly. But once it is deployed on a server, the logging work as expected until an exception occurs. After that each log statement is printed with a "stacktrace" element in it. The stacktrace is from the last exception that occurred and doesn't change until the next exception. It doesn't matter if the level of log statement is <strong>INFO</strong>, <strong>WARN</strong> or <strong>ERROR</strong>. It has been quite frustrating since I am not able to reproduce it and neither I have any idea what is causing this issue. I have searched google and stackoverflow but no luck. I am unable to find any posts related to this issue. Following are a few of the logging setting I am using in my application along with log statements.</p>
  
  <p>Logback.xml</p>
  
  <pre><code>&lt;?xml version="1.0" encoding="UTF-8"?&gt;
  &lt;configuration&gt;
  &lt;include resource="org/springframework/boot/logging/logback/base.xml"/&gt;
  &lt;property name="PROJECT_ID" value="email-service-consumer"/&gt;
  &lt;appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender"&gt;
  &lt;encoder&gt;
  &lt;charset&gt;UTF-8&lt;/charset&gt;
  &lt;Pattern&gt;${CONSOLE_LOG_PATTERN}&lt;/Pattern&gt;
  &lt;/encoder&gt;
  &lt;/appender&gt;
  
  &lt;appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"&gt;
  &lt;file&gt;${CATALINA_HOME}/logs/${PROJECT_ID}_debug.log&lt;/file&gt;
  &lt;append&gt;true&lt;/append&gt;
  &lt;rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"&gt;
  &lt;!-- daily rollover. Make sure the path matches the one in the file element or else
  the rollover logs are placed in the working directory. --&gt;
  &lt;fileNamePattern&gt;${CATALINA_HOME}/logs/${PROJECT_ID}_debug.%d{yyyy-MM-dd}.%i.log&lt;/fileNamePattern&gt;
  
  &lt;timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"&gt;
  &lt;maxFileSize&gt;50MB&lt;/maxFileSize&gt;
  &lt;/timeBasedFileNamingAndTriggeringPolicy&gt;
  &lt;!-- keep 30 days' worth of history --&gt;
  &lt;maxHistory&gt;30&lt;/maxHistory&gt;
  &lt;/rollingPolicy&gt;
  
  &lt;encoder&gt;
  &lt;charset&gt;UTF-8&lt;/charset&gt;
  &lt;pattern&gt;${FILE_LOG_PATTERN}&lt;/pattern&gt;
  &lt;/encoder&gt;
  &lt;/appender&gt;
  
  &lt;appender name="SPLUNK_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"&gt;
  &lt;file&gt;${CATALINA_HOME}/logs/${PROJECT_ID}_splunk.log&lt;/file&gt;
  &lt;append&gt;true&lt;/append&gt;
  &lt;rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"&gt;
  &lt;!-- daily rollover. Make sure the path matches the one in the file element or else
  the rollover logs are placed in the working directory. --&gt;
  &lt;fileNamePattern&gt;${CATALINA_HOME}/logs/${PROJECT_ID}_splunk.%d{yyyy-MM-dd}.%i.log&lt;/fileNamePattern&gt;
  
  &lt;timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"&gt;
  &lt;maxFileSize&gt;5MB&lt;/maxFileSize&gt;
  &lt;/timeBasedFileNamingAndTriggeringPolicy&gt;
  &lt;!-- keep 30 days' worth of history --&gt;
  &lt;maxHistory&gt;30&lt;/maxHistory&gt;
  &lt;/rollingPolicy&gt;
  
  &lt;encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder"&gt;
  &lt;charset&gt;UTF-8&lt;/charset&gt;
  &lt;layout class="com.example.core.logging.CcSplunkLogLayout" /&gt;
  &lt;/encoder&gt;
  &lt;/appender&gt;
  
  &lt;appender name="ASYNC_DEFAULTS" class="ch.qos.logback.classic.AsyncAppender"&gt;
  &lt;queueSize&gt;500&lt;/queueSize&gt;
  &lt;discardingThreshold&gt;0&lt;/discardingThreshold&gt;
  &lt;appender-ref ref="FILE"/&gt;
  &lt;appender-ref ref="CONSOLE"/&gt;
  &lt;appender-ref ref="SPLUNK_FILE"/&gt;
  &lt;/appender&gt;
  
  &lt;springProfile name="!production"&gt;
  &lt;logger name="com.example" additivity="false" level="INFO"&gt;
  &lt;appender-ref ref="ASYNC_DEFAULTS"/&gt;
  &lt;/logger&gt;
  &lt;logger name="org.hibernate" additivity="false" level="INFO"&gt;
  &lt;appender-ref ref="ASYNC_DEFAULTS"/&gt;
  &lt;/logger&gt;
  &lt;logger name="org.springframework" additivity="false" level="INFO"&gt;
  &lt;appender-ref ref="ASYNC_DEFAULTS"/&gt;
  &lt;/logger&gt;
  &lt;root level="INFO"&gt;
  &lt;appender-ref ref="ASYNC_DEFAULTS"/&gt;
  &lt;/root&gt;
  &lt;/springProfile&gt;
  
  &lt;springProfile name="production"&gt;
  &lt;logger name="com.example" additivity="false" level="INFO"&gt;
  &lt;appender-ref ref="SPLUNK_FILE"/&gt;
  &lt;/logger&gt;
  &lt;logger name="org.hibernate" additivity="false" level="ERROR"&gt;
  &lt;appender-ref ref="SPLUNK_FILE"/&gt;
  &lt;/logger&gt;
  &lt;logger name="org.springframework" additivity="false" level="ERROR"&gt;
  &lt;appender-ref ref="SPLUNK_FILE"/&gt;
  &lt;/logger&gt;
  &lt;root level="ERROR"&gt;
  &lt;appender-ref ref="SPLUNK_FILE"/&gt;
  &lt;/root&gt;
  &lt;/springProfile&gt;
  
  &lt;springProfile name="docker-dev"&gt;
  &lt;logger name="com.example" additivity="false" level="INFO"&gt;
  &lt;appender-ref ref="SPLUNK_FILE"/&gt;
  &lt;/logger&gt;
  &lt;logger name="org.hibernate" additivity="false" level="INFO"&gt;
  &lt;appender-ref ref="FILE"/&gt;
  &lt;/logger&gt;
  &lt;logger name="org.springframework" additivity="false" level="INFO"&gt;
  &lt;appender-ref ref="FILE"/&gt;
  &lt;/logger&gt;
  &lt;root level="TRACE"&gt;
  &lt;appender-ref ref="FILE"/&gt;
  &lt;/root&gt;
  &lt;/springProfile&gt;
  &lt;/configuration&gt;
  </code></pre>
  
  <p>I also wrote a util Logging class, which contains wrapper methods for different log levels.</p>
  
  <pre><code>public class LoggingUtil {
  
  
      public static void logWarn(String message, EmailRequest emailRequest, Logger logger) {
          Map&lt;String, String&gt; identifierMap = getRequestIdentifiers(emailRequest);
          StringBuffer warnMessage = new StringBuffer(checkPunctuation(message));
          warnMessage.append(Constants.REQUEST_IDENTIFIERS);
  
          logger.warn(warnMessage.toString(), identifierMap.get(Constants.ORDERID),
                  identifierMap.get(Constants.TEMPLATENAME),
                  identifierMap.get(Constants.SESSIONID),
                  identifierMap.get(Constants.STOREID));
      }
  
      /**
       * Method to log error messages.
       * @param message
       * @param emailRequest
       * @param
       */
      public static void logInfo(String message, EmailRequest emailRequest, Logger logger) {
          Map&lt;String, String&gt; identifierMap = getRequestIdentifiers(emailRequest);
          StringBuffer infoMessage = new StringBuffer(checkPunctuation(message));
  
          infoMessage.append(Constants.REQUEST_IDENTIFIERS);
  
          logger.info(infoMessage.toString(), identifierMap.get(Constants.ORDERID),
                  identifierMap.get(Constants.TEMPLATENAME),
                  identifierMap.get(Constants.SESSIONID),
                  identifierMap.get(Constants.STOREID));
      }
  
      public static void logInfo(String message, KafkaMessage kafkaMessage, Logger logger) {
          String sessionId = null;
          String clientOriginationId = null;
          String eventId = null;
          String eventName = null;
          String timeStamp = null;
  
          StringBuilder stringBuilder = new StringBuilder(checkPunctuation(message));
          stringBuilder.append(Constants.KAFKA_MESSAGE_IDENTIFIERS);
  
          if(kafkaMessage != null &amp;&amp; kafkaMessage.getHeader() != null) {
              Header header = kafkaMessage.getHeader();
              sessionId = header.getSessionId();
              clientOriginationId = header.getClientOriginationId();
              eventId = header.getEventId();
              eventName = header.getEventName();
              timeStamp = header.getTimestamp();
          }
  
          logger.info(stringBuilder.toString(), sessionId, clientOriginationId, eventId, eventName, timeStamp);
      }
  
      /**
       * Method to log error messages.
       * @param message
       * @param emailRequest
       * @param e
       */
      public static void logError(String message, EmailRequest emailRequest, Exception e, Logger logger) {
          Map&lt;String, String&gt; identifierMap = getRequestIdentifiers(emailRequest);
  
          StringBuffer errorMessage = new StringBuffer(checkPunctuation(message));
          errorMessage.append(Constants.REQUEST_IDENTIFIERS);
  
          logger.error(errorMessage.toString(), identifierMap.get(Constants.ORDERID),
                  identifierMap.get(Constants.TEMPLATENAME),
                  identifierMap.get(Constants.SESSIONID),
                  identifierMap.get(Constants.STOREID), e.getMessage(), e);
      }
  
      /**
       * This method extracts the request identfiers from email request object
       * @param emailRequest
       * @return
       */
      private static Map&lt;String, String&gt; getRequestIdentifiers(EmailRequest emailRequest) {
          String templateName = emailRequest != null ? emailRequest.getTemplateName() : null;
          String orderId = null;
          String sessionId = null;
          String storeId = null;
          if(emailRequest != null &amp;&amp; emailRequest.getEmailVars() != null &amp;&amp; emailRequest.getEmailVars().getTemplateVarsList() != null) {
              EmailVars emailVars = emailRequest.getEmailVars();
              orderId = emailVars.getTemplateVariable(Constants.ORDERID);
              sessionId = emailVars.getTemplateVariable(Constants.SESSIONID);
              storeId = emailVars.getTemplateVariable(Constants.STOREID);
          }
          Map&lt;String, String&gt; identifierMap = new HashMap&lt;String, String&gt;();
          identifierMap.put(Constants.TEMPLATENAME, templateName);
          identifierMap.put(Constants.ORDERID, orderId);
          identifierMap.put(Constants.SESSIONID, sessionId);
          identifierMap.put(Constants.STOREID, storeId);
  
          return identifierMap;
      }
  
      /**
       * Method to add '.' to the message
       * @param message
       * @return
       */
      private static String checkPunctuation(String message) {
          if(message == null || message.length() == 0 || message.trim().length() == 0) {
              return "";
          }
          //Removing any trailing white spaces
          message = message.trim();
          StringBuilder stringBuilder = new StringBuilder(message);
  
          //checking if the message ends with a period '.'
          if(message.charAt(message.length() - 1) != '.') {
              stringBuilder.append(". ");
          }
  
          return stringBuilder.toString();
      }
  }
  </code></pre>
  
  <p>Log statment:</p>
  
  <blockquote>
    <p>2018-10-31 11:45:33.770000 -0700 LOG_LEVEL="INFO"
    apiCall="com.example.email.service.KafkaConsumer"
    stacktrace="java.lang.Exception: Invalid to-email-address     at
    com.example.email.service.KafkaConsumer.handleMessages(KafkaConsumer.java:84)
      at sun.reflect.GeneratedMethodAccessor134.invoke(Unknown Source)    at
    sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
      at java.lang.reflect.Method.invoke(Method.java:498)     at
    org.springframework.messaging.handler.invocation.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:181)
      at
    org.springframework.messaging.handler.invocation.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:114)
      at
    org.springframework.cloud.stream.binding.StreamListenerMessageHandler.handleRequestMessage(StreamListenerMessageHandler.java:55)
      at
    org.springframework.integration.handler.AbstractReplyProducingMessageHandler.handleMessageInternal(AbstractReplyProducingMessageHandler.java:109)
      at
    org.springframework.integration.handler.AbstractMessageHandler.handleMessage(AbstractMessageHandler.java:158)
      at
    org.springframework.integration.dispatcher.AbstractDispatcher.tryOptimizedDispatch(AbstractDispatcher.java:116)
      at
    org.springframework.integration.dispatcher.UnicastingDispatcher.doDispatch(UnicastingDispatcher.java:132)
      at
    org.springframework.integration.dispatcher.UnicastingDispatcher.dispatch(UnicastingDispatcher.java:105)
      at
    org.springframework.integration.channel.AbstractSubscribableChannel.doSend(AbstractSubscribableChannel.java:73)
      at
    org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:445)
      at
    org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:394)
      at
    org.springframework.messaging.core.GenericMessagingTemplate.doSend(GenericMessagingTemplate.java:181)
      at
    org.springframework.messaging.core.GenericMessagingTemplate.doSend(GenericMessagingTemplate.java:160)
      at
    org.springframework.messaging.core.GenericMessagingTemplate.doSend(GenericMessagingTemplate.java:47)
      at
    org.springframework.messaging.core.AbstractMessageSendingTemplate.send(AbstractMessageSendingTemplate.java:108)
      at
    org.springframework.integration.endpoint.MessageProducerSupport.sendMessage(MessageProducerSupport.java:203)
      at
    org.springframework.integration.kafka.inbound.KafkaMessageDrivenChannelAdapter.access$300(KafkaMessageDrivenChannelAdapter.java:70)
      at
    org.springframework.integration.kafka.inbound.KafkaMessageDrivenChannelAdapter$IntegrationRecordMessageListener.onMessage(KafkaMessageDrivenChannelAdapter.java:387)
      at
    org.springframework.integration.kafka.inbound.KafkaMessageDrivenChannelAdapter$IntegrationRecordMessageListener.onMessage(KafkaMessageDrivenChannelAdapter.java:364)
      at
    org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.doInvokeRecordListener(KafkaMessageListenerContainer.java:1071)
      at
    org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.doInvokeWithRecords(KafkaMessageListenerContainer.java:1051)
      at
    org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.invokeRecordListener(KafkaMessageListenerContainer.java:998)
      at
    org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.invokeListener(KafkaMessageListenerContainer.java:866)
      at
    org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.run(KafkaMessageListenerContainer.java:724)
      at
    java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
      at java.util.concurrent.FutureTask.run(FutureTask.java:266)     at
    java.lang.Thread.run(Thread.java:748)  " message="Time taken to
    process message is 2265ms.For orderId = 6207168, templateName =
    TERMS_CONDITIONS, sessionId = 77337650, storeId = 1892. errorMessage =
    {}"</p>
  </blockquote>
  
  <p>I suspect that the wrapper method might be the culprit, since I am passing the logger instance from the class where the exception occurred to the wrapper methods. I'm not sure though. Any help is appreciated, thank you in advance.</p>