SpringBoot Logging - Stacktrace в каждом операторе журнала - PullRequest
0 голосов
/ 31 октября 2018

Я занимаюсь разработкой службы электронной почты в SpringBoot , и для ведения журнала я использую slf4j . Приложение работает должным образом, за исключением части регистрации. При запуске его на моей машине регистрация работает отлично. Но после развертывания на сервере ведение журнала работает, как и ожидалось, до возникновения исключения. После этого каждый оператор журнала печатается с элементом «stacktrace». Трассировка стека происходит от последнего возникшего исключения и не изменяется до следующего исключения. Не имеет значения, является ли уровень оператора журнала INFO , WARN или ERROR . Это было довольно неприятно, так как я не могу воспроизвести его, и я не имею ни малейшего представления, что является причиной этой проблемы. Я искал Google и StackOverflow, но не повезло. Я не могу найти какие-либо сообщения, связанные с этой проблемой. Ниже приведены некоторые настройки журнала, которые я использую в своем приложении вместе с инструкциями журнала.

Logback.xml

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<include resource="org/springframework/boot/logging/logback/base.xml"/>
<property name="PROJECT_ID" value="email-service-consumer"/>
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<charset>UTF-8</charset>
<Pattern>${CONSOLE_LOG_PATTERN}</Pattern>
</encoder>
</appender>

<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${CATALINA_HOME}/logs/${PROJECT_ID}_debug.log</file>
<append>true</append>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- daily rollover. Make sure the path matches the one in the file element or else
the rollover logs are placed in the working directory. -->
<fileNamePattern>${CATALINA_HOME}/logs/${PROJECT_ID}_debug.%d{yyyy-MM-dd}.%i.log</fileNamePattern>

<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>50MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!-- keep 30 days' worth of history -->
<maxHistory>30</maxHistory>
</rollingPolicy>

<encoder>
<charset>UTF-8</charset>
<pattern>${FILE_LOG_PATTERN}</pattern>
</encoder>
</appender>

<appender name="SPLUNK_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${CATALINA_HOME}/logs/${PROJECT_ID}_splunk.log</file>
<append>true</append>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- daily rollover. Make sure the path matches the one in the file element or else
the rollover logs are placed in the working directory. -->
<fileNamePattern>${CATALINA_HOME}/logs/${PROJECT_ID}_splunk.%d{yyyy-MM-dd}.%i.log</fileNamePattern>

<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>5MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!-- keep 30 days' worth of history -->
<maxHistory>30</maxHistory>
</rollingPolicy>

<encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
<charset>UTF-8</charset>
<layout class="com.example.core.logging.CcSplunkLogLayout" />
</encoder>
</appender>

<appender name="ASYNC_DEFAULTS" class="ch.qos.logback.classic.AsyncAppender">
<queueSize>500</queueSize>
<discardingThreshold>0</discardingThreshold>
<appender-ref ref="FILE"/>
<appender-ref ref="CONSOLE"/>
<appender-ref ref="SPLUNK_FILE"/>
</appender>

<springProfile name="!production">
<logger name="com.example" additivity="false" level="INFO">
<appender-ref ref="ASYNC_DEFAULTS"/>
</logger>
<logger name="org.hibernate" additivity="false" level="INFO">
<appender-ref ref="ASYNC_DEFAULTS"/>
</logger>
<logger name="org.springframework" additivity="false" level="INFO">
<appender-ref ref="ASYNC_DEFAULTS"/>
</logger>
<root level="INFO">
<appender-ref ref="ASYNC_DEFAULTS"/>
</root>
</springProfile>

<springProfile name="production">
<logger name="com.example" additivity="false" level="INFO">
<appender-ref ref="SPLUNK_FILE"/>
</logger>
<logger name="org.hibernate" additivity="false" level="ERROR">
<appender-ref ref="SPLUNK_FILE"/>
</logger>
<logger name="org.springframework" additivity="false" level="ERROR">
<appender-ref ref="SPLUNK_FILE"/>
</logger>
<root level="ERROR">
<appender-ref ref="SPLUNK_FILE"/>
</root>
</springProfile>

<springProfile name="docker-dev">
<logger name="com.example" additivity="false" level="INFO">
<appender-ref ref="SPLUNK_FILE"/>
</logger>
<logger name="org.hibernate" additivity="false" level="INFO">
<appender-ref ref="FILE"/>
</logger>
<logger name="org.springframework" additivity="false" level="INFO">
<appender-ref ref="FILE"/>
</logger>
<root level="TRACE">
<appender-ref ref="FILE"/>
</root>
</springProfile>
</configuration>

Я также написал утилитарный класс Logging, который содержит методы-оболочки для разных уровней журнала.

public class LoggingUtil {


    public static void logWarn(String message, EmailRequest emailRequest, Logger logger) {
        Map<String, String> 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<String, String> 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 && 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<String, String> 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<String, String> getRequestIdentifiers(EmailRequest emailRequest) {
        String templateName = emailRequest != null ? emailRequest.getTemplateName() : null;
        String orderId = null;
        String sessionId = null;
        String storeId = null;
        if(emailRequest != null && emailRequest.getEmailVars() != null && emailRequest.getEmailVars().getTemplateVarsList() != null) {
            EmailVars emailVars = emailRequest.getEmailVars();
            orderId = emailVars.getTemplateVariable(Constants.ORDERID);
            sessionId = emailVars.getTemplateVariable(Constants.SESSIONID);
            storeId = emailVars.getTemplateVariable(Constants.STOREID);
        }
        Map<String, String> identifierMap = new HashMap<String, String>();
        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();
    }
}

Журнал учета:

2018-10-31 11: 45: 33.770000 -0700 LOG_LEVEL = "INFO" apiCall = "com.example.email.service.KafkaConsumer" stacktrace = "java.lang.Exception: неверный адрес электронной почты в com.example.email.service.KafkaConsumer.handleMessages (KafkaConsumer.java:84) at sun.reflect.GeneratedMethodAccessor134.invoke (неизвестный источник) в sun.reflect.DelegatingMethodAccessorImpl.invoke (DelegatingMethodAccessorImpl.java:43) в java.lang.reflect.Method.invoke (Method.java:498) в org.springframework.messaging.handler.invocation.InvocableHandlerMethod.doInvoke (InvocableHandlerMethod.java:181) в org.springframework.messaging.handler.invocation.InvocableHandlerMethod.invoke (InvocableHandlerMethod.java:114) в org.springframework.cloud.stream.binding.StreamListenerMessageHandler.handleRequestMessage (StreamListenerMessageHandler.java:55) в org.springframework.integration.handler.AbstractReplyProducingMessageHandler.handleMessageInternal (AbstractReplyProducingMessageHandler.java:109) в org.springframework.integration.handler.AbstractMessageHandler.handleMessage (AbstractMessageHandler.java:158) в org.springframework.integration.dispatcher.AbstractDispatcher.tryOptimizedDispatch (AbstractDispatcher.java:116) в org.springframework.integration.dispatcher.UnicastingDispatcher.doDispatch (UnicastingDispatcher.java:132) в org.springframework.integration.dispatcher.UnicastingDispatcher.dispatch (UnicastingDispatcher.java:105) в org.springframework.integration.channel.AbstractSubscribableChannel.doSend (AbstractSubscribableChannel.java:73) в org.springframework.integration.channel.AbstractMessageChannel.send (AbstractMessageChannel.java:445) в org.springframework.integration.channel.AbstractMessageChannel.send (AbstractMessageChannel.java:394) в org.springframework.messaging.core.GenericMessagingTemplate.doSend (GenericMessagingTemplate.java:181) в org.springframework.messaging.core.GenericMessagingTemplate.doSend (GenericMessagingTemplate.java:160) в org.springframework.messaging.core.GenericMessagingTemplate.doSend (GenericMessagingTemplate.java:47) в org.springframework.messaging.core.AbstractMessageSendingTemplate.send (AbstractMessageSendingTemplate.java:108) в org.springframework.integration.endpoint.MessageProducerSupport.sendMessage (MessageProducerSupport.java:203) в org.springframework.integration.kafka.inbound.KafkaMessageDrivenChannelAdapter.access $ 300 (KafkaMessageDrivenChannelAdapter.java:70) в org.springframework.integration.kafka.inbound.KafkaMessageDrivenChannelAdapter $ IntegrationRecordMessageListener.onMessage (KafkaMessageDrivenChannelAdapter.java:387) вorg.springframework.integration.kafka.inbound.KafkaMessageDrivenChannelAdapter $ IntegrationRecordMessageListener.onMessage (KafkaMessageDrivenChannelAdapter.java:364) в org.springframework.kafka.listener.KafkaMessageListenerContainer $ ListenerConsumer.doInvokeRecordListener (KafkaMessageListenerContainer.java:1071) в org.springframework.kafka.listener.KafkaMessageListenerContainer $ ListenerConsumer.doInvokeWithRecords (KafkaMessageListenerContainer.java:1051) в org.springframework.kafka.listener.KafkaMessageListenerContainer $ ListenerConsumer.invokeRecordListener (KafkaMessageListenerContainer.java:998) в org.springframework.kafka.listener.KafkaMessageListenerContainer $ ListenerConsumer.invokeListener (KafkaMessageListenerContainer.java:866) в org.springframework.kafka.listener.KafkaMessageListenerContainer $ ListenerConsumer.run (KafkaMessageListenerContainer.java:724) в java.util.concurrent.Executors $ RunnableAdapter.call (Executors.java:511) в java.util.concurrent.FutureTask.run (FutureTask.java:266) в java.lang.Thread.run (Thread.java:748) "message =" Время, необходимое для сообщение об обработке - 2265 мс. Для orderId = 6207168, templateName = TERMS_CONDITIONS, sessionId = 77337650, storeId = 1892. errorMessage = {} "

Я подозреваю, что виновником может быть метод-обертка, поскольку я передаю экземпляр регистратора из класса, в котором произошло исключение, в методы-обертки. Я не уверен, хотя. Любая помощь приветствуется, спасибо заранее.

...