log4netlog4net-appender

Change subject of SmtpAppender programmatically


I have an SmtpAppender like this:

<appender name="SmtpAppender" type="log4net.Appender.SmtpAppender">
    <to value="MyEmail@example.org" />
    <from value="SenderEmail@example.org" />
    <subject type="log4net.Util.PatternString" value="This is a subject" />
    <smtpHost value="smtp.host.value" />
    <authentication value="Basic" />
    <port value="587" />
    <username value="Username" />
    <password value="Password" />
    <bufferSize value="1" />
    <EnableSsl value="true"/>
    <lossy value="false" />
    <threshold value="ERROR" />
    <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%date [%3thread] %-5level [%class].[%method] - %message%newline" />
    </layout>
</appender>

I would like to change the subject of the log mail in my code to a string I would specify so it suits my needs better than a standard subject.

Right now I achieve it like this. First, I find the SmtpAppender by name:

public static IAppender FindAppenderByName(string name) 
{
    ILoggerRepository rootRep = LogManager.GetRepository();
    foreach (IAppender iApp in rootRep.GetAppenders()) {
        if (string.Compare(name, iApp.Name, true) == 0) {
            return iApp;
        }
    }
    return null;
}

and then I can change the subject like this:

IAppender appender = FindAppenderByName("SmtpAppender");
SmtpAppender smtpAppender = (SmtpAppender)appender;
smtpAppender.Subject = "An error occured trying to convert the values";
log.Error("Error message");

But this seems to be a bit too complicated since every time I send an error mail I first have to find the appender by name and I don't want to use a global IAppender object as well as that seems like bad practice to me.

Is there a way to use the user-specified error message as a subject or is there an extension method I could use?


Solution

  • My proposal is as follows :

    public class CustomSmtpAppender : SmtpAppender
    {
        protected override void SendBuffer(LoggingEvent[] events)
        {
            PrepareSubject(events);
            base.SendBuffer(events);
        }
    
        protected virtual void PrepareSubject(IEnumerable<LoggingEvent> events)
        {
            //here you can eval events and set base.Subject
        }
    }