I am trying to configure a smtp appender in the log4net.config file that I have. The problem is that I have looked all over the internet and cannot find how to send an email whe
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.