Log4Net smtp appender only send email when error with full log(debug & info & error). Only when the application ends

余生长醉 提交于 2019-12-03 06:27:06
Pasha Immortals

SmtpAppender cannot accomplish this on its own. So what I did was create another appender that to an appender of type MemoryAppender. I set a threshold on this logger to only include messages that should trigger the SmtpAppender, e.g. Error. We use this to later determine if we want to send the email which has more levels logged.

We don't actually care about the messages in the MemoryAppender--we just care that it contains messages at the end. The messages we get via email actually come from the SmtpAppender.

At the end of my program I check the memory appender to see if its GetEvents() contains any events. If so, I do not stop the SmtpAppender from running normally.

Log4Net configs for both appenders:

<appender name="ErrorHolder" type="log4net.Appender.MemoryAppender" >
    <onlyFixPartialEventData value="true" />
    <!-- if *any* message is logged with this level, the email appender will 
         be used with its own level -->
    <threshold value="ERROR" />
</appender>

<appender name="Email" type="log4net.Appender.SmtpAppender">    
    <!-- the level you want to see in the email IF ErrorHolder finds anything -->
    <threshold value="INFO"/> 
    <bufferSize value="512" />
    <lossy value="false" /> <!-- important! -->   
    <to value="name@domain.com" />
    <from value="name@domain.com" />
    <subject value="ERROR: subject" />
    <smtpHost value="smtpserver" />    
    <layout type="log4net.Layout.PatternLayout">
      <conversionPattern value="%newline%date [%thread] %-5level %logger [%property{NDC}] - %message%newline%newline%newline" />
    </layout>    
</appender>

<root>
  <level value="ALL" />
  <appender-ref ref="ErrorHolder" />
  <appender-ref ref="Email" />
</root>

At the end of the app run this to disable the SmtpAppender if the ErrorHolder appender is empty:

// trigger loggers if errors occurred:
var memoryAppender = ((Hierarchy)LogManager.GetRepository())
    .Root.Appenders.OfType<MemoryAppender>().FirstOrDefault();

if (memoryAppender != null && memoryAppender.GetEvents().Length == 0)
{
    // there was no error so don't email anything
    var smtpAppender = ((Hierarchy)LogManager.GetRepository())
        .Root.Appenders.OfType<SmtpAppender>().FirstOrDefault();

    if (smtpAppender != null)
    {
        smtpAppender.Threshold = Level.Off;
        smtpAppender.ActivateOptions();
    }
}

This sounds like an application configuration issue rather than a log4net configuration issue. I would suggest putting a method in at the close of your application that emails you the log file if it detects that there is an error inside it. You could either detect this error by flipping a global variable from false to true in every place where you log errors or you could wait until the end of your application and then read the log file to see if it contains errors. The first method would be quicker at shutdown but it means modifying your code in multiple places. The latter would allow you to just add one method but it might take longer in a large file.

A third option would be to send errors to a second log file (so they go two places) using log4net. Then, when your application is closing and you are checking to see if you should email the log, just check for the existence of the error-only file. If it exists, delete it (so it isn't there next time) and email the full log.

change treshold to Error. Also log 4net only sends the email when the app is clodes.you can send it earlier. but than you first need to copy it ( because the org file is still in use) and than you can email the copy.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!