Я занимаюсь разработкой службы электронной почты в 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 =
{} "
Я подозреваю, что виновником может быть метод-обертка, поскольку я передаю экземпляр регистратора из класса, в котором произошло исключение, в методы-обертки. Я не уверен, хотя. Любая помощь приветствуется, спасибо заранее.