Getting Started
Architecture
NServiceBus
Transports
Persistence
ServiceInsight
ServicePulse
ServiceControl
Monitoring
Samples

Custom Logger Factory

Component: NServiceBus
NuGet Package: NServiceBus (7.x)

Introduction

Illustrates a custom implementation of a logging factory. For simplicity, this sample writes all log messages to the console.

The approach of creating a custom logging factory should not be required in the development of most business applications. This API is designed for routing NServiceBus log messages to a third-party logging library. To gain more control over logging targets it is recommended to leverage one of these logging libraries.

It is also possible to see full implementations of logging factories by looking at the code for the other logging libraries.

Logging Definition

To build a custom logging factory, create a class derived from LoggingFactoryDefinition.

using NServiceBus.Logging;

class ConsoleLoggerDefinition :
    LoggingFactoryDefinition
{
    LogLevel level = LogLevel.Info;

    public void Level(LogLevel level)
    {
        this.level = level;
    }

    protected override ILoggerFactory GetLoggingFactory()
    {
        return new ConsoleLoggerFactory(level);
    }
}

Logger Factory

The LoggingFactoryDefinition then returns an instance of ILoggerFactory

class ConsoleLoggerFactory :
    ILoggerFactory
{
    LogLevel level;

    public ConsoleLoggerFactory(LogLevel level)
    {
        this.level = level;
    }

    public ILog GetLogger(Type type)
    {
        return GetLogger(type.FullName);
    }

    public ILog GetLogger(string name)
    {
        return new ConsoleLog(name, level);
    }
}

Note that the ConsoleLoggerFactory can optionally expose extra configuration, as is illustrated in this case by a custom LogLevel() method.

Log

The logger factory then returns an ILog instance.

class ConsoleLog :
    ILog
{
    string name;
    public bool IsDebugEnabled { get; }
    public bool IsInfoEnabled { get; }
    public bool IsWarnEnabled { get; }
    public bool IsErrorEnabled { get; }
    public bool IsFatalEnabled { get; }

    public ConsoleLog(string name, LogLevel level)
    {
        this.name = name;
        IsDebugEnabled = LogLevel.Debug >= level;
        IsInfoEnabled = LogLevel.Info >= level;
        IsWarnEnabled = LogLevel.Warn >= level;
        IsErrorEnabled = LogLevel.Error >= level;
        IsFatalEnabled = LogLevel.Fatal >= level;
    }

    void Write(string level, string message, Exception exception)
    {
        Console.WriteLine($"{name}. {level}. {message}. Exception: {exception}");
    }
    void Write(string level, string message)
    {
        Console.WriteLine($"{name}. {level}. {message}.");
    }

    void Write(string level, string format, params object[] args)
    {
        format = $"{name}. {level}. {format}";
        Console.WriteLine(format, args);
    }

    public void Debug(string message)
    {
        if (IsDebugEnabled)
        {
            Write("Debug", message);
        }
    }

    public void Debug(string message, Exception exception)
    {
        if (IsDebugEnabled)
        {
            Write("Debug", message, exception);
        }
    }

    public void DebugFormat(string format, params object[] args)
    {
        if (IsDebugEnabled)
        {
            Write("Debug", format, args);
        }
    }
    // Other log methods excluded for brevity

The implementation of ILog handles writing the entries and the log filtering.

Enabling Logging

var loggerDefinition = LogManager.Use<ConsoleLoggerDefinition>();

// optionally set the log level in code or read from app.config
loggerDefinition.Level(LogLevel.Info);

// logging configuration should occur prior to endpoint configuration
var endpointConfiguration = new EndpointConfiguration("Samples.Logging.CustomFactory");

Verifying that the sample works correctly

In this sample the information at the Info level is logged to the console window.

There will be a few standard logging entries in the console window that are automatically created by NServiceBus when logging level is set to Info, for example:

 Queue [private$\error] is running with [Everyone] and [NT AUTHORITY\ANONYMOUS LOGON] permissions. Consider setting appropriate permissions, if required by the organization. For more information, consult the documentation.

There will also be a custom entry logged from inside the handler Hello from MyHandler.

Related Articles