Click here to Skip to main content
11,930,449 members (55,465 online)
Click here to Skip to main content
Add your own
alternative version


93 bookmarked

Logging Using the Composite Pattern

, 15 Jul 2006 CPOL
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 
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.

| Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.151126.1 | Last Updated 15 Jul 2006
Article Copyright 2006 by mikeperetz
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid