Click here to Skip to main content
14,774,518 members
Articles » Languages » C# » Utilities
Article
Posted 20 Oct 2009

Tagged as

Stats

29.5K views
9 bookmarked

Extending log4net's SmtpAppender to customize subjects.

Rate me:
Please Sign up or sign in to vote.
4.00/5 (1 vote)
21 Oct 2009CPOL
Log4net, the excellent logging framework, has the capability to send emails, but without customizing subjects, the feature is somehow less useful. Here is a simple way to extend it.

Introduction

Log4net is an excellent logging framework, and is widely used in various applications. I enjoyed very much its capability to decided where to send logging info, one of them is the SmtpAppender, which will send emails base on your logging item, so you don't have to compose email seperately, which is nice to a lazy guy like me. But right now there is no way to change the email subject on the fly, and this make it painful to the email readers. I googled around to look for solutions without one to my satisfaction. So I decide to try my way. (I saw mail archives saying log4j, the origin of log4net is planning such a capability, but I did not see any info on this to log4net. )

Background

The reason behind log4net's limitation to customizing subject is, SmtpAppender is base on the idea that it is buffered appender, with possibly multiple logging items in buffer when email is about to be sent. So there is no better way of deciding how the subject should look like. But to me, I would like to see the most important info in the events as the subject. Also the buffering stragegey of SmtpAppender is not satisfying me, it will always wait for the buffer to be full before it sends out mails, which make the buffer almost useless: the reason why we want emails to be sent out is, when there is something emergent happening, we get immediate alert! But without buffering, you will receive too many emails with 1 logging item in each message, which is also not so nice.

On the other hand, the SmtpAppender is a powerful appender which has a lot of features to customize, and I don't feel good to loss them or create the wheel again. So a good way is to extend it. A good design should be open to extension, so let's see if there is a good design here:).

The Subject property is not virtual, so we have to figure out another way. Luckily the SendBuffer method is virtual, which allowes us to prepare the Subject before sending. Thus the code:

public class NoBufferSmtpAppender : SmtpAppender
{
    protected override void SendBuffer(LoggingEvent[] events)
    {
        prepareSubject(events); // customize subject before call base.

        base.SendBuffer(events);
    }
    protected virtual void prepareSubject(ICollection<LoggingEvent> events)
    {
        Subject = null;
        foreach (LoggingEvent evt in events)
        {
            if (evt.Level >= _TriggerSendingLevel)
            {
                string msg = evt.ExceptionObject == null ? evt.RenderedMessage : evt.ExceptionObject.Message;

                Subject = string.Format("[{0}] {1}", evt.Level, msg);

                break;
            }
        }
        if (Subject == null)
            Subject = string.Format("{0} logging items...(beleow [{1}] level)", events.Count, _TriggerSendingLevel);
    }
}

I need email to be sent out when some message with "tiggering level" coming in, so a property with reasonable intial value is necessary:

private Level _TriggerSendingLevel = Level.Warn;
public Level TriggerSendingLevel { get { return _TriggerSendingLevel; } set { _TriggerSendingLevel = value; } }

So if there is a logging item with Level higher than the trigger level, the email will be sent out immediately.

Now is the question: how to decide the subject? I hard coded a strategy I personally found useful: if sending message contains an item with higher level than the trigger level, it's message will be used as subject, or a simple summary like "[16] logging items... (below WARN level)" is used as subject. As the extension point is opened, feel free to customize it by your self.

Using the code

I favor config log4net per xml file, so here is how I used the code in my config file:

  <appender name="SmtpAppender" type="Ifx.Mit.MapService.Server.Util.log4net.NoBufferSmtpAppender">
    <to <a href="%22mailto:value=someone@somecompany.com%22/%3E%22">value="</a><a href="%22mailto:value=someone@somecompany.com%22">someone@somecompany.com</a>" />
</a />    <from value="<a href="%22mailto:someapp@somecompany.com%22">someapp@somecompany.com</a>" />
    <smtpHost value="your.host" />
    <bufferSize value="10" />
    <filter type="log4net.Filter.StringMatchFilter">
      <stringToMatch value="[email]"/>
      <acceptOnMatch value="true"/>
    </filter>
    <filter type="log4net.Filter.LevelRangeFilter">
      <levelMin value="INFO"/>
      <levelMax value="FATAL"/>
      <acceptOnMatch value="true"/>
    </filter>
    <filter type="log4net.Filter.DenyAllFilter"/>
    <layout type="log4net.Layout.PatternLayout">
      <conversionPattern value="%newline%date [%thread] %-5level %logger [%property{NDC}] - %newline ===> %message%newline%newline" />
    </layout>
  </appender>

enjoy!

History

20/10/2009, Initial post

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

techfun
Web Developer
Singapore Singapore
No Biography provided

Comments and Discussions

 
GeneralEmail groups Pin
Varnam5-Mar-11 14:10
MemberVarnam5-Mar-11 14:10 
Generalever looked at the NonBufferedSmtpAppenderWithSubjectLayout Pin
DaBuddhaMan21-Oct-09 5:56
MemberDaBuddhaMan21-Oct-09 5:56 
GeneralRe: ever looked at the NonBufferedSmtpAppenderWithSubjectLayout Pin
monstercorp14-Jun-10 4:58
Membermonstercorp14-Jun-10 4:58 
GeneralRe: ever looked at the NonBufferedSmtpAppenderWithSubjectLayout Pin
DaBuddhaMan14-Jun-10 23:52
MemberDaBuddhaMan14-Jun-10 23:52 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.