6

I need to create a simple system to abstract logging platforms. The idea is that I'd like to be able to exchange or activate a logging platform (nlog, log4net, enterprise library) via some configuration (this shouldn't be a problem). I know that I would need a wrapper for each platform that I want to support that would load the necessary dll's and create the loggers.

I was thinking of creating an abstract class or an interface providing the most common methods like Log, Debug, Trace, etc.:

interface ILogger
{
    void Log(...);
    void Debug(...);
    // etc.
}

class NLogPlatform : ILogger
{
    // create nlog, load config etc.
}

class Log4NetPlatform : ILogger
{
    // create log4net, load config etc.
}

class LoggerFactory
{ 
    public static CreateLogger(...)
    {
        // read settings and create a logger.
    }
}

At first I thought of a log-provider but then I found that provider is not a pattern at all so I looked at .NET Design Patterns but nothing really seems to be suitable here. Did I miss something or is there just no pattern for it?

I haven't really started yet because this time I'd rather go in the right direction from the beginning then refactor several tools later.

Could you tell me what I should take into consideration when designing such a system and whether there is a pattern for this?

t3chb0t
  • 2,515
  • 2
  • 21
  • 34
  • 2
    http://programmers.stackexchange.com/questions/70877/are-design-patterns-really-essential-nowadays/70893#70893 – MetaFight Feb 13 '15 at 18:34
  • A good point. That's why I wrote _pattern_ in parethesees. – t3chb0t Feb 13 '15 at 18:39
  • If you're only ever going to use one logging framework at a time, the simplest thing is just a lone class in an assembly. The choice of logger and configuration would be hard-coded, but you can easily swap out the `.dll` for another between runs of the program. – Doval Feb 13 '15 at 18:54
  • @Doval Yes, I'm going to use only one logging framework at a time. Thanks for the suggestion. I'll think of it. – t3chb0t Feb 13 '15 at 19:37
  • You should not code in order to do a specific pattern. If your code end up looking like a pattern then good for you. Otherwise it's useless to try to over think simple things. – Franck Feb 13 '15 at 21:14
  • @Franck it wasn't my intention. I'm sorry that I didn't write it in my question. All I was looking for was an inspiration and some hints. Like you say it would not be very clever to try to keep to any particular pattern at all costs but it may be helpful to take one or the other ready and tested solution from them and modifiy it for you own needs. I'm glad that few people posted answers that I wasn't able to find by myself. They will definitely help me to start without re-inventing everything and make me thing about few things that I might have missed. – t3chb0t Feb 14 '15 at 14:18

3 Answers3

7

Congratulations, you have (re-)discovered the Object Adapter Pattern. You have one target interface (here: ILogger), and various adapter classes NLogPlatform, Log4NetPlatform, …. Each adapter class conforms to the target interface, and proxies all calls to the adaptee object which it contains as a member.

If you want to make the use of this pattern clearer, I would call the adapter classes NLogAdapter etc..

The usage of a factory to inject the correct log adapter is entirely orthogonal to this, and is about the Dependency Inversion principle.

amon
  • 132,749
  • 27
  • 279
  • 375
  • You're right. Now when I take another look a it the adapter pattern describes exacly what I'm trying to do. I thought so that there was something obvious that I missed. Thanks. – t3chb0t Feb 13 '15 at 19:02
  • This is much more similar to the Abstract Factory pattern... – AK_ Feb 13 '15 at 19:12
  • @AK_ We do have a factory here, but not every factory is an abstract factory. In an [abstract factory](https://en.wikipedia.org/wiki/Abstract_factory_pattern), we have an interface for creating objects. Then, we have different concrete factory classes for different product families. But there are no *abstract* factories here, unless we introduce an `ILoggerFactory` and then concrete `NLogAdapterFactory` and `Log4NetAdapterFactory` classes … which is overkill, and doesn't solve the problem of injecting the dependency in the first place. – amon Feb 13 '15 at 19:20
  • @amon the Adapter pattern talks about adjusting one interface to suite another. Abstract factory talks about on interface, different implementations. this is much closer to Abstract factory. also you are probably going to need different factories to create the Logger (at least if you want to support various loggers), and then take the logger you created and inject it into the system (probably using DI). which means another factory for the DI.... – AK_ Feb 13 '15 at 19:29
3
  1. This has nothing to do with design patterns...

  2. This is a solved problem, that has been solved over and over since .Net was invented.

  3. Just use Commons.Logging it's a small configurable liberality that does exactly what you asked: https://github.com/net-commons/common-logging

AK_
  • 744
  • 3
  • 10
  • This is a great suggestion. I'll use it as an inspiration. Generally it does the same what I am going to do. The only difference is that I must not use config files but a database (it has to be configurable remotely because we seldom have access to the config files) so I needed to make some adjustments anyway. – t3chb0t Feb 13 '15 at 19:18
  • 4
    @t3chb0t Using DB to configure logging is a very bad idea. You need logging to be the first thing to work in your application, so you will be able to log the start up process, including connecting to the DB. – AK_ Feb 13 '15 at 19:23
  • I won't contradict you... but the client machines often don't give us any access to the config files and if we need to change some settings the only way to do it is via the database which we can access remotely. They also damage the config files very often. Don't ask me how ;-) it's easier to change the settings by yourself then try to explain the other party how to do it over a telephone. – t3chb0t Feb 13 '15 at 19:28
  • OK... But you should keep the start-up thing in mind... Also if I recall correctly the Common-Logging library uses standard .Net configuration. so there are a lot of solution to load these from the DB... Honestly in your place I would have done my best to keep to existing stuff instead of developing these kind of things myself... – AK_ Feb 13 '15 at 19:34
  • Thanks, I will. I probably will have to create a simple config to be able to log _events_ at startup like unreachable database. – t3chb0t Feb 13 '15 at 19:44
  • 1
    @t3chb0t Events are a good idea... Most of the "Enterprise" Applications I did the logging for defaulted to windows events if they couldn't start the logger properly, or couldn't start at all... – AK_ Feb 13 '15 at 19:50
0

This is nothing to do it design pattern, you can just use the build-in TraceSource to log anything you want.