Click here to Skip to main content
13,350,486 members (67,685 online)
Click here to Skip to main content
Add your own
alternative version


95 bookmarked
Posted 15 Jul 2006

Logging Using the Composite Pattern

, 15 Jul 2006
Rate this:
Please Sign up or sign in to vote.
Allow flexiable logging using the Composite design pattern.


In this article, I will explain how I solved a common problem I used to have regarding logging within my business layer. Normally, I would have a function call from my presentation layer to my business layer; however, once in the business layer, I had no access to the presentation layer anymore. There are many ways to solve this problem. In the MFC days, a Doc / View approach based on the Observer pattern was used. In .NET, we can use custom events to notify the presentation layer that something happened. But, in this article, I will show the Composite pattern in action, and some of its nice advantages.

The Requirements

Suppose we had a function in our business layer that performs a lot of updates. It would be nice that during all these updates, we log the exact action taking place. We want to easily log a string describing the activity to one of, all of, or some of the following loggers: TextBox, ListBox, text file and/or the EventLog.

Creating the ILogger Interface

To keep the example simple, I will implement a simple ILogger interface that only requires a logger class to implement its own way of logging an activity.

public interface ILogger
    void LogMessage(string strMessage);

Creating Logger Classes

Create the following logger classes:

  • Text box logger - logs a message into a text box
  • List box logger - adds a message to the list
  • File logger - logs a message into a file
  • EventLog logger - logs a message into the system event log

ListBox Logger

Notice that the ListBox and TextBox loggers are thread safe, by using the InvokeRequired method.

class ListBoxLogger : ILogger
    ListBox m_listBox;
    public ListBoxLogger(ListBox listBox)
        m_listBox = listBox;

    public void LogMessage(string strMessage)
        MethodInvoker logDelegate = delegate 

        if (m_listBox.InvokeRequired)

TextBox Logger

class TextBoxLogger : ILogger
    private TextBox m_textBox;
    public TextBoxLogger(TextBox txtBox)
        m_textBox = txtBox;

    public void LogMessage(string strLogMessage)
        MethodInvoker logDelegate = delegate { m_textBox.Text = strLogMessage; };
        if (m_textBox.InvokeRequired)

File Logger

class FileLogger : ILogger
    private string m_strFileName;
    private object m_sync = new object();
    public FileLogger(string strFileName)
        m_strFileName = strFileName;

    public void LogMessage(string strMessage)
        lock (m_sync)
            using (StreamWriter writer = new StreamWriter(m_strFileName))

Notice that the FileLogger is thread-safe, and that it opens and closes the file before writing to it. This guarantees that the message is flushed after each call to LogMessage.

EventLog Logger

class EventLogger : ILogger
    public EventLogger()


    public void LogMessage(string strMessage)
        EventLog.WriteEntry("Logger", strMessage);

Using the ILogger Object

So far, there is nothing special here; we can have a function that takes a ILogger object and allow us to log messages. For example:

private void DoSomthing(ILogger logger)
    for(int i=0; i < 10; i++)
        logger.LogMessage("Logging a message " + i.ToString());

The client code looks like this:

// pass the File Logger
DoSomthing(new FileLogger("C://LogMessage.txt")); 
// txtBox is a text box control on the form
DoSomthing(new TextBoxLogger(textBox));

Introducing the CompositeLogger

But what if I want to log to all my loggers at the same time, or what if I want to log to only some of my loggers? To solve this requirement, I create a new logger called a Composite Logger.

// Logger of composite of loggers
class CompositeLogger : ILogger
    private ILogger[] m_loggerArray;
    // pass a ILoggers that are part of this composite logger
    public CompositeLogger(params ILogger[] loggers)
        m_loggerArray = loggers;

    public void LogMessage(string strMessage)
        // loop around all the loggers, and log the message.
        foreach (ILogger logger in m_loggerArray)

Let's Use Our Composite Logger to "Configure" Which Loggers to Use

Using all the loggers:

CompositeLogger compositeLogger =   
        new CompositeLogger(new TextBoxLogger(textBox),
                            new ListBoxLogger(listBox),
                            new FileLogger("C:\\LogPattern.txt"),
                            new EventLogger() );

Creating a composite logger with only TextBoxLogger and ListBoxLogger:

CompositeLogger compositeLogger =   
        new CompositeLogger(new TextBoxLogger(textBox),
                            new ListBoxLogger(listBox));

Because our composite logger implements ILogger like all the other loggers, we can pass it to a function that expects an ILogger object type.


Testing the Composite Logger in a Thread

Let’s test our composite logger in a separate thread, just to make sure we can update the UI from a thread other than the UI-thread.

// create a composite logger with all the loggers
CompositeLogger compositeLogger =
    new CompositeLogger(
            new TextBoxLogger(textBox),
            new ListBoxLogger(listBox),
            new FileLogger("C:\\LogPattern.txt"),
            new EventLogger());

// create a anonymous function to call DoSomthing
ParameterizedThreadStart threadDelegate = delegate(object obj)
    ILogger logger = (ILogger)obj;

// Do Somthing in a thread
Thread t = new Thread(threadDelegate);


Notice that I am now able to pass an ILogger object to a method within the business layer or to the data layer, and provide an easy way to log a message. This is done by using the ILogger interface, and therefore, your business layer or data layer requires no extra references to File.Io, or Windows.Forms, it only needs to have a reference to ILogger. It is also nice that you can easily add and remove loggers by using your composite Logger. Thank you for reading, have a good day!


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


About the Author

Web Developer
Canada Canada
I am currently working as a team leader with a group of amazing .NET programmers. I love coding with .NET, and I love to apply design patterns into my work. Lately I had some free time, so I decided to write some articles, hoping I will spare someone frustration and anxiety.

You may also be interested in...


Comments and Discussions

QuestionThank you Pin
sankargeet4-Sep-12 2:57
membersankargeet4-Sep-12 2:57 
NewsMore Pin
mikeperetz16-Nov-07 2:43
membermikeperetz16-Nov-07 2:43 
GeneralRe: More Pin
RickyJiao7-Nov-11 16:57
memberRickyJiao7-Nov-11 16:57 
GeneralAnother method ... Pin
david_k1328-Aug-07 11:32
memberdavid_k1328-Aug-07 11:32 
GeneralNice easy-going article Pin
david_k1330-May-07 8:51
memberdavid_k1330-May-07 8:51 
GeneralHi Pin
zuboss_826-Aug-06 4:48
memberzuboss_826-Aug-06 4:48 
GeneralNice example for composite pattern Pin
ColonelSender25-Jul-06 11:46
memberColonelSender25-Jul-06 11:46 
GeneralI like it... Pin
BoneSoft25-Jul-06 5:12
memberBoneSoft25-Jul-06 5:12 
GeneralCompare to built in logging Pin
bri189b18-Jul-06 16:11
memberbri189b18-Jul-06 16:11 
For those of use who may not know, what are the advantages of doing this versus using the built in logging in the .NET framework?
GeneralWell done Pin
jonavi18-Jul-06 10:25
memberjonavi18-Jul-06 10:25 
GeneralRe: Well done Pin
mikeperetz18-Jul-06 11:20
membermikeperetz18-Jul-06 11:20 
QuestionCombine with Provider? Pin
Mike Ellison18-Jul-06 7:46
memberMike Ellison18-Jul-06 7:46 
AnswerRe: Combine with Provider? Pin
mikeperetz18-Jul-06 11:19
membermikeperetz18-Jul-06 11:19 
AnswerRe: Combine with Provider? Pin
mikeperetz18-Jul-06 11:34
membermikeperetz18-Jul-06 11:34 
QuestionWhy not log4net? Pin
MikeP_AIS18-Jul-06 6:51
memberMikeP_AIS18-Jul-06 6:51 
AnswerRe: Why not log4net? Pin
mikeperetz18-Jul-06 11:41
membermikeperetz18-Jul-06 11:41 
GeneralRe: Why not log4net? Pin
bri189b18-Jul-06 16:10
memberbri189b18-Jul-06 16:10 
GeneralRe: Why not log4net? Pin
MikeP_AIS19-Jul-06 12:02
memberMikeP_AIS19-Jul-06 12:02 
GeneralRe: Why not log4net? Pin
bri189b19-Jul-06 13:53
memberbri189b19-Jul-06 13:53 
GeneralRe: Why not log4net? Pin
MikeP_AIS20-Jul-06 5:48
memberMikeP_AIS20-Jul-06 5:48 

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.

Permalink | Advertise | Privacy | Terms of Use | Mobile
Web01 | 2.8.180111.1 | Last Updated 15 Jul 2006
Article Copyright 2006 by mikeperetz
Everything else Copyright © CodeProject, 1999-2018
Layout: fixed | fluid