2

I am integrating Serilog into and existing multilayer library that I've create. The previous logging technique I used was simply passing a string up the layers with events. I'd like to get away from this.

I've been told for years that you should never expose children to objects on their parents level but this is the only structure I have come up with so far. Does anyone have an other structure to suggest?

simple example of the structure I am using.

class Program
{
    static void Main(string[] args)
    {
        ILogger logger = new LoggerConfiguration()
            .WriteTo.Console()
            .CreateLogger();

        A a = new A(logger);
        a.DoStuff();

    }
}

class A
{
    public ILogger logger;
    private B b;

    public A(ILogger logger)
    {
        this.logger = logger;
        b = new B(logger);
    }

    public void DoStuff()
    {
        logger.Information("blah class a");
        b.DoStuff();
    }
}

class B
{
    public ILogger logger;
    private C c;
    public B(ILogger logger)
    {
        this.logger = logger;
        c = new C(logger);
    }

    public void DoStuff()
    {
        logger.Information("blah class b");
        c.DoStuff();
    }
}

class C
{

    public ILogger logger;

    public C(ILogger logger)
    {
        this.logger = logger;
    }

    public void DoStuff()
    {
        logger.Information("blah class c");

        Thread thread = new Thread(() =>
        {
            for (int i  = 0; i  < 10; i ++)
            {
                logger.Information("In thread {i}", i);
            }

        });

        Thread thread2 = new Thread(() =>
        {
            for (int i = 0; i < 10; i++)
            {
                logger.Information("In thread {i}", i);
            }

        });

        thread.Start();
        thread2.Start();

        thread.Join();
        thread2.Join();
    }
3

Because logging is such a pervasive concern, it's often beneficial use the static Log rather than passing ILogger between components:

class Program
{
    static void Main(string[] args)
    {
        Log.Logger = new LoggerConfiguration()
            .WriteTo.Console()
            .CreateLogger();

        A a = new A();
        a.DoStuff();

        Log.CloseAndFlush();
    }
}

class A
{
    private ILogger logger = Log.ForContext<A>();
    private B b;

    public A()
    {
        b = new B();
    }

    public void DoStuff()
    {
        logger.Information("blah class a");
        b.DoStuff();
    }
}

// etc.

This style makes the more important application-specific structure of your code clearer, rather than bloating out constructors everywhere with noisy ILogger arguments.

Using this pattern also makes it possible to introduce logging into a class deep down the object hierarchy, without having to make cascading changes adding ILogger arguments to every constructor or method that creates an instance of it.

2

Each class should create its own logger instance and use that. The logger constructor should read the global logging settings the application has set, preferably from a cache so instantiating the logger is not much of an overhead.

See Log4Net as an example (and frankly, just use log4net as your logging system)

Alternatively, you can use a dependency injection to pass a single logging object into each of your objects.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.