我试图使用Logback
与SMTPAppender
作为我的日志解决方案。我有一个评估附加到appender
触发电子邮件发送每100个错误记录。在大多数情况下,这是正确的,但我注意到,如果我在一个循环中快速创建错误以触发多封电子邮件,那么只有最后一封电子邮件发送了正确的内容。这似乎是一个竞争条件,第一个电子邮件还没有完成创建/发送,第二个电子邮件覆盖了第一个创建。其他人有过这样的经历或找到了解决方案吗?我的logback配置附在下面。
<configuration>
<appender name="emailAppender" class="${logback.emailAppenderClass}">
<evaluator class="com.wdp.common.logging.logback.evaluators.CountingLoggerEvaulator">
<limit>100</limit>
</evaluator>
<to>${logback.emailNotificationRecipientStr}</to>
<from>${logback.emailNotificationFromStr}</from>
<smtpHost>${logback.smtpHost}</smtpHost>
<subject>Logback logs for facebook-ads-processes</subject>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<layout class="ch.qos.logback.classic.PatternLayout">
<pattern>%d [Thread:%t] %p [%c] - %m%n</pattern>
</layout>
<cyclicBufferTracker class="ch.qos.logback.core.spi.CyclicBufferTracker">
<bufferSize>${logback.cyclicBufferSize}</bufferSize>
</cyclicBufferTracker>
</appender>
</configuration>
这是求值器:
public class CountingLoggerEvaulator extends EventEvaluatorBase<ILoggingEvent> implements EventEvaluator<ILoggingEvent> {
//if limit is not set in configuration, this will cause it to send one email for each message received.
private int limit = 100;
private int counter = 0;
public void setLimit(int limit) {
this.limit = limit;
}
public int getLimit() {
return limit;
}
@Override
public boolean evaluate(ILoggingEvent expr) throws NullPointerException, EvaluationException {
counter++;
if (counter == limit) {
counter = 0;
return true;
} else {
return false;
}
}
}
SMTPAppender的asynchronousSending属性默认为true。处理步骤我把它设为false,它就能正常工作了
您应该使您的评估器线程安全-例如使用AtomicInteger
:
public class CountingLoggerEvaulator extends EventEvaluatorBase<ILoggingEvent> implements EventEvaluator<ILoggingEvent> {
//if limit is not set in configuration, this will cause it to send one email for each message received.
private int limit = 100;
private AtomicInteger counter = new AtomicInteger();
public void setLimit(int limit) {
this.limit = limit;
}
public int getLimit() {
return limit;
}
@Override
public boolean evaluate(ILoggingEvent expr) throws NullPointerException, EvaluationException {
int curValue = counter.incrementAndGet();
if (curValue >= limit) {
return counter.compareAndSet(curValue, 0);
} else {
return false;
}
}
}