问题:如何防止错误日志调用相同的追加方法来停止无限循环,从而导致应用程序停止工作。
分析:由于AppenderClass中的append方法不是线程安全的,所以创建了单独的线程来发送电子邮件。但如果电子邮件由于异常而失败,请尝试打印 log.error 消息,该消息创建记录器事件并再次调用追加方法,该方法再次创建新线程。结果,循环无限循环开始并使用所有系统资源。
已经尝试过:
尝试使用Executor Service,但由于错误日志循环,它继续使用所有线程并进入无限循环。
如果我将错误更改为警告或其他级别,则没有问题。但想打印错误日志。 (有效,但未满足要求。)
如果不创建新线程,那么它在多线程环境中再次工作,它再次失败。 (有效,但未满足要求。)
@Plugin(name = EmailErrorsAppender.PLUGIN_NAME, category = Core.CATEGORY_NAME, elementType = Appender.ELEMENT_TYPE, printObject = true)
public class EmailErrorsAppender extends AbstractPropertiesAwareAppender
{
......
@Override
public void append(LogEvent event)
{
try
{
this.sendEmailInThread(recipients, filter.getRecipientType(), subject, filter.createEmailContentFromEvent(event));
}catch(Throwable t){
logger.error("Failed to send error email.", t);
}
}
protected void sendEmailInThread(final List<String> destinationAddresses, final Message.RecipientType recipientType,final String subject, final String body)
{
final String mailHost = this.getMailHost();
final String fromAddress = this.getFromAddress();
final EmailMessageConverter messageConverter = this.messageConverter;
if(messageConverter == null || StringUtils.isBlank(mailHost) || StringUtils.isBlank(fromAddress))
throw new IllegalStateException("The message converter, mail host and from address are required to send " +
"an email. Please consult the documentation for more information.");
Thread emailThread = new Thread(new Runnable()
{
@Override
public void run()
{
Message message =null;
try
{
Properties properties = new Properties();
properties.put("mail.smtp.host", mailHost);
Session session = Session.getDefaultInstance(properties, null);
properties = session.getProperties();
properties.put("mail.smtp.host", mailHost);
message = new MimeMessage(session);
message.setFrom(new InternetAddress(fromAddress));
for(String address : destinationAddresses)
message.addRecipient(recipientType, new InternetAddress(address));
message.setSubject(subject);
message.setSentDate(new Date());
messageConverter.addBodyToMessagePart(body, message);
try
{
Transport.send(message);
}
catch(MessagingException e1)
{
logger.error("Failed to send email on first try. Waiting 10 seconds and trying once more."+ e1);
Thread.sleep(10000);
}
}
catch(MessagingException | InterruptedException e)
{
try
{
Transport.send(message);
}
catch(MessagingException e3)
{
logger.error("Failed to send email on second try. Will not try again.", e3);
}
}
}
});
emailThread.start();
}
......
}
是否可以停止再次调用append方法的错误日志,append将再创建一个线程并以1000s线程创建和系统消失而结束。
我还没测试过。
使用异步和缓冲区附加器
<Configuration status="WARN">
<Appenders>
<!-- Define SMTP Appender -->
<SMTP name="EmailAppender" subject="Log Alert"
to="[email protected]"
from="[email protected]"
smtpHost="smtp.example.com"
smtpPort="25">
<PatternLayout>
<Pattern>%d %p %c{1.} [%t] %m%n</Pattern>
</PatternLayout>
</SMTP>
<!-- Define Buffer Appender -->
<BufferingForwardingAppender name="BufferedEmailAppender" bufferSize="10">
<AppenderRef ref="EmailAppender"/>
</BufferingForwardingAppender>
<!-- Define Async Appender -->
<Async name="AsyncBufferedEmailAppender">
<AppenderRef ref="BufferedEmailAppender"/>
</Async>
</Appenders>
<Loggers>
<Root level="error">
<AppenderRef ref="AsyncBufferedEmailAppender"/>
</Root>
</Loggers>
</Configuration>