Click here to Skip to main content
15,887,175 members
Articles / Programming Languages / C#
Article

Logger Pattern, How to Log Messages from the Inside of a Class

Rate me:
Please Sign up or sign in to vote.
3.14/5 (6 votes)
12 Jun 2006CPOL3 min read 29.1K   149   14   1
Sometimes you have to communicate something to the consumer of a class. This may break all your encapsulation. So, here is an approach to a new pattern, which lets you send messages outside a class without making it "project dependant".

Introduction

This is my first CodeProject article, so, do not expect too much of it! Also, English is not my first language, so, excuse me if I have made any mistakes.

Why do we need to log everything? If you need to trace some class activity, you'll need to log its steps. It is very simple to do it from the GUI, but what if I want to re-use my class in another project? Well, I will have to rewrite all logs. "No way, man!" you'll say... "Use a logger class!!"... Yes, but then your class is dependant too... I used the Snippet Compiler for my tests. This is a .NET must-have tool!

The Idea

I needed to simply log a string message from the inside of my class, without having to depend on an external class. I wanted to do something like this:

C#
class SomeClass
{
   ...
   
   void DoSomething()
   {
        ...
        LogMessage("Something to log"); 
   }
}

Where LogMessage(String) simply puts that string out of my class, and makes some other function handle it... hey, that sounds familiar to me... Callbacks! But wait, I'm talking in .NET, I have to say 'Delegates'.

The Solution

If you haven't used Delegates so far, you don't really know what a delegate is. Because all well-known 'events', are in fact delegates. Delegates are very useful when you have to pass a function as a parameter, instead an object. C++ calls this a 'Callback'. Other languages let you pass the function as it is (but we are talking about .NET!). You may find this code in the zip file as LoggerImplementation.cs. I will declare a Delegate for my logger:

C#
public delegate void LogDelegate(String msg);

And now, I will add some code to my class to handle it:

C#
private LogDelegate _log;
public  LogDelegate Logger
{
    get { return _log;  }
    set { _log = value; }
}

private void LogMessage(String msg)
{
    if( _log != null )
    {
        _log(msg);
    }
}

Cool! Now I can call LogMessage("Something!") from any method inside my class without using external objects. We first declared a private LogDelegate, and then the property to access it. Note that here it is not necessary to have the member and the property, because there is no logic in it. But it is always a good practice to do it. Then, there is a LogMessage(String) method. This is a pre-call to the Delegate, because we have to check if someone is consuming the delegate before launching it. Oh yes, who's showing the messages? I see no print sentences... Well, the one who instantiates is the one who has to tell the object what to do when a LogMessage is called. This is done like this:

C#
stuffMaker.Log += delegate ( String msg )
{
    Console.WriteLine(msg);
};

This will work only in C# 2.0. If you are using previous versions, you cannot declare anonymous methods. So, you'll have to add a new LogDelegate to Log, addressing another named method which will handle the delegate (upgrade yourself, use 2.0). So, you also want to write the message to a file? Or the Windows EventLog? No problem, delegates let you add many different handlers of a single method.

C#
stuffMaker.Log += delegate ( String msg )
{
    Console.WriteLine(msg);
};

stuffMaker.Log += delegate ( String msg )
{
    Console.WriteLine("Other log: " + msg);
};

stuffMaker.Log += delegate ( String msg )
{
    Console.WriteLine("Yes, another log: " + msg);
};

stuffMaker.Log += delegate ( String msg )
{
    // make whatever you want!!
};

A Better 'Object Oriented' Solution

Well, you may say "But I have to paste this code in every class I want to log ...". Well, yes. You're right... so, why don't we do it the OO way?? Let's define an abstract class (you may find this code in the zip file as LoggerImplementation Extender.cs).

C#
public delegate void LogDelegate(String msg);

public abstract class Logger
{
    // Logger 
    private LogDelegate _log;
    public  LogDelegate Log
    {
        get { return _log;  }
        set { _log = value; }
    }    
    
    // Callback call
    protected void LogMessage(String msg)
    {
        if( _log != null )
        {
            _log(msg);
        }
    }    
}

And now, the only thing you have to do to add logging capabilities to a class is this:

C#
public class StuffMaker : Logger

Conclusion

This is my first article and I hope you liked it. I've found this very useful in my daily work, and also for testing purposes. You may use this same approach for monitoring class' internal processes too. You may also note that this Pattern doesn't even exist... but it was a nice solution to a common problem, and I gave it a name.

History

  • 12th June, 2006: Initial post

License

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


Written By
Web Developer
Argentina Argentina
Alejandro "nSeeker" Rizzo is an advanced student of informatics engineering in Argentina. He's now working for a known security software company from Spain.

He coded under VB since he was fourteen, but a few years ago, he definitely moved to C#. He works with ASP.Net, Delphi, and C++ too.

Visit http:\\thenseeker.blogspot.com for further info about Alejandro.

Comments and Discussions

 
GeneralMy vote of 3 Pin
IAbstract29-Apr-11 6:29
IAbstract29-Apr-11 6:29 
Good for a first article!

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.