Unit Test Your Enterprise Library Logging Logic

Most enterprise applications need to perform logging in some form or other, and the Enterprise Library Logging Application Block provides an excellent platform for implementation. With the Logging Application Block (henceforth LAB) you don’t have to think about how to log, but you still need to implement when and what to log.

These decisions can be complex in themselves, so it might be nice to be able to unit test your logging logic. How do you test logging today? Click on the right sequence of UI elements in your application and then carefully examine the Windows Event Log? With the LAB, there’s a better way.

Logging with the LAB is easy enough in itself:

public class MyClass
    public void DoSomething()
        // Imagine that something interesting happens
        // here…
        LogEntry le = new LogEntry();
        le.Message = “Something interesting happened.”;

If you imagine that the code is a bit more complex, you may want to test that the DoSomething method logs the expected information.

Unit testing is all about automation, so you need to be able to automate the validation of log entries. One could consider using the Windows API to open the Windows Event Log and search through all the entries, carefully filtering the relevant and most recent ones out, but that is, at best, a rather error-prone approach. However, the LAB, like the rest of Enterprise Library, uses a configurable provider model, so you can configure the destination of event log entries.

It even ships with a lot of other logging destinations than the default Windows Event Log, for example a text file. Logging to a text file sounds more automatable, but you would still need to write some helper classes to clean and parse the log file for each test case.

Since the provider model is extensible, why not go all the way? I’ll write a custom trace listener that I’ll use to configure the LAB. Instead of writing the log entries to some external data store, this trace listener will just add a log entry to an in-memory list of log entries. After I exercise the code in DoSomething, I can retrieve the list of log entries and validate it.

Here’s the custom trace listener in all its gory detail (excluding namespace imports):

public class StubTraceListener : CustomTraceListener
    private readonly static List<LogEntry> logEntries_ =
        new List<LogEntry>();
    private readonly static List<string> logMessages_ =
        new List<string>();
    public override void Write(string message)
    public override void WriteLine(string message)
    public override void TraceData(TraceEventCache eventCache,
        string source, TraceEventType eventType, int id,
        object data)
        LogEntry le = data as LogEntry;
        if (le != null)
            if (this.Formatter != null)
        base.TraceData(eventCache, source, eventType, id, data);
    internal static IList<string> GetLogMessages()
        return new ReadOnlyCollection<string>
    internal static IList<LogEntry> GetLogEntries()
        return new ReadOnlyCollection<LogEntry>
    internal static void Reset()

To create a custom trace listener, you must first derive a class from CustomTraceListener and set the ConfigurationElementType attribute. That’s just a bit of Enterprise Library infrastructure, so I will leave it at that. CustomTraceListener is an abstract class, so to derive from that, I need to at least implement the Write and WriteLine methods. As you can see, I just add the messages to a static list of messages.

The real fun happens in the TraceData method, though. This is a virtual method that you don’t have to override, but it’s really the core of any trace listener. The base implementation of this method uses a pre-defined formatter to format the data parameter into a string, with which it then calls the Write or WriteLine methods. If you want to change this behavior, this is the place to do it. In this method, I cast the data parameter to a LogEntry instance and add that LogEntry to another static list. This is the same LogEntry instance that was originally created by the logging application (such as in the DoSomething method above), so keeping this instance around allows for very rich testing.

If there’s a formatter configured for the StubTraceListener, I use that formatter to format a text string from the LogEntry, whereafter I return from the method to prevent the base implementation from also calling the Write method.

The GetLogMessages, GetLogEntries, and Reset methods enable me to use StubTraceListener in a unit test:

public void TestInitialize()
public void ValidateLogging()
    MyClass mc = new MyClass();
    IList<LogEntry> logEntries =
    Assert.AreEqual<int>(1, logEntries.Count);
    LogEntry le = logEntries[0];
    Assert.AreEqual<string>(“Something interesting happened.”,
    Assert.AreEqual<int>(1, le.Categories.Count);

Since test cases should be independent, I make sure to call the Reset method before each test. This clears out all the log entries from the StubTraceListener.

In the test method, it’s simply a matter of exercising the code that generates log entries, and then subsequently retrieve the log entries from the StubTraceListener and validate that everything is as expected.

This test suite is going to fail until you create a configuration for the LAB. The easiest way to do this is to add an empty app.config file to the test project, and then use the Enterprise Library Configuration application to configure the LAB. The default LAB configuration uses a Windows Event Log trace listener, so you’ll need to remove that and add the StubTraceListener instead.

Once that is done, you have a working unit test suite, and you can unit test logging logic of arbitrary complexity without having to manually check anything.

Most of Enterprise Library uses a similar provider model, so this principle of stubbing out a provider for an application block can be used in many other ways, for other application blocks.


Comments (17)

  1. stevenR2 says:

    Cool – i’ve just started looking into this today so this example just helped some things "click".

    I spent the morning looking into WMI/MOM so i’d like to see more about how LAB links in with that and also how to use custom data sources -i thought they’d be supported out of the box :). The into page in the associated documentation sure makes it sound that way.

  2. tomholl says:

    Hi Steven –

    The Logging Application Block ships with a WMI TraceListener that can fire logging events over WMI, ready to be consumed by tools such as MOM. This works out of the box, and if you build your own classes that derive from LogEntry and register them as WMI schemas then the WMI TraceListener will send your registered type to WMI.

    If there are any other capabilities around WMI/MOM you would like to see in the next version, please let me know.

    Tom Hollander

    Microsoft patterns & practices

  3. An Phu says:


    How did you get VSTS to copy your configuration file to its TestResults folder each time the test run.

    VSTS does not copy my config file so every time I run, I get a configurationErrorException.

    It’s frustrating.  Maybe I am forgetting something?



  4. ploeh says:

    Hello An Phu

    Thank you for asking. I don’t really do anything to copy my configuration file to the TestResults folder. When you add an App.config file to your project, Visual Studio will automatically deploy it and rename it to <output_name>.exe|dll.config.

    However, as far as I’ve been able to tell, VSTS only does this if the file is called "App.config", i.e. if it’s called "myProject.config", it doesn’t get copied unless you specify it as a deployment item.

    Could it be that your configuration file has another name than "App.config"?

  5. An Phu says:

    You were right.  I see my mistake. The file was named "Web.config".  It looks like the configuration file has to be "App.config".

    Thank you for your help.

  6. ploeh says:

    Hello An Phu

    I’m happy I was able to help :)

  7. phuhn says:

    I have built the StubTraceListener seperately.  Referenced the dll.  But, I am not getting the app.config file just right.  I seems like it is not being used by Enterprise Library logging.  This is my simplified (template) config file.



       <section name="loggingConfiguration" type="Microsoft.Practices.EnterpriseLibrary.Logging.Configuration.LoggingSettings, Microsoft.Practices.EnterpriseLibrary.Logging, Version=, Culture=neutral, PublicKeyToken=null" />


     <loggingConfiguration name="Logging Application Block" tracingEnabled="true"

       defaultCategory="General" logWarningsWhenNoCategoriesMatch="true">


         <add listenerDataType="Microsoft.Practices.EnterpriseLibrary.Logging.Configuration.CustomTraceListenerData, Microsoft.Practices.EnterpriseLibrary.Logging, Version=, Culture=neutral, PublicKeyToken=null"

           traceOutputOptions="None" type="TestingTraceListener.StubTraceListener, LoggingTraceListener, Version=, Culture=neutral, PublicKeyToken=null"

           name="CustomTraceListener" initializeData="" />



         <add template="Timestamp: {timestamp}, Message: {message}, Category: {category} &#xD;&#xA; )}"

           type="Microsoft.Practices.EnterpriseLibrary.Logging.Formatters.TextFormatter, Microsoft.Practices.EnterpriseLibrary.Logging, Version=, Culture=neutral, PublicKeyToken=null"

           name="Text Formatter" />



         <add switchValue="All" name="General">


             <add name="CustomTraceListener" />





         <allEvents switchValue="All" name="All Events">


             <add name="CustomTraceListener" />



         <notProcessed switchValue="All" name="Unprocessed Category" />

         <errors switchValue="All" name="Logging Errors &amp; Warnings" />




  8. ploeh says:

    Hi phuhn

    Thank you for writing.

    How does your problem manifest itself? Are you getting an exception?

  9. phuhn says:

    The problem was nothing was showing up in the generic lists.  I removed the WMI stuff place in the app.config file produced by Enterprise Library Configuration application and then data started showing up.

    PS I added the following (taken from MockTraceListener) (Note: I use prefix _, not postfix):

    public static int GetEntriesCount


       get { return _logEntries.Count; }


    public static LogEntry LastEntry




           return _logEntries.Count > 0 ?

         _logEntries[_logEntries.Count – 1] : null;



    public static string LastMessage


       get { return _logEntries.Count > 0 ?

           _logEntries[_logEntries.Count – 1].Message : null; }


  10. ploeh says:

    Hi phuhn

    Okay, so your issue is solved now?

  11. phuhn says:

    Can Enterprise Library and StubTraceListener be used to extend the Trace.Write and Trace.Warn? i.e.

    StubTraceListener.Reset( );

    Trace.Write( "method name", "message" );

    Assert.AreEqual( 1, StubTraceListener.GetLogEntries().Count );

  12. ploeh says:

    Hi phuhn

    I don’t see why not. According to the documentation, Trace.Write writes to each configured TraceListener’s Write method.

    Since StubTracelistener derives from TraceListener, you’d just need to add it to the Listeners property of the Trace class.

  13. ploeh blog says:

    One of the nice things about the Enterprise Library Logging Application Block (LAB) is that it’s so darned

  14. Sandra says:

    How do I create a new eventlog  other than the application log. I changed the Source to my custom eventlog name and it didn’t work. any ideas?

  15. ploeh says:

    Hi Sandra

    Thank you for your question. Before you can write to a custom event log, you have to create it. This requires Administrator privileges, and should usually be done at deployment time.

    If you are using the Enterprise Library Logging Application Block, this post may be of some help to you: http://blogs.msdn.com/ploeh/archive/2007/09/20/InstallingEventSourcesForTheLoggingApplicationBlock.aspx


  16. Thank you for writing this post, it really helped a lot to think upfront of a strategy to unit test a logging mechanism within our system using LAP.  Your solution proved to be more than inspirational in this situation.

  17. ploeh blog says:

    Lots of applications write to the Windows Event Log. When TDD’ing, event logging is part of an application’s