Custom implementation of ILogger

monty picture monty · Nov 27, 2018 · Viewed 9.7k times · Source

In my project I often add prefixes to my log messages.

Currently I am doing this with

      logger.LogDebug(prefix + " some message");

I thought it would be a good way to implement a custom logger where I set the prefix and the logger itself attaches it every time it logs something.

So I created my custom logger class and implemented the ILogger interface. But I do not understand how to use the

    public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)

method to add the prefix (which is a member of the custom logger class).

My full code is:

      public class CustomLogger : ILogger
      {

        private readonly ILogger _logger;
        private string _logPrefix;

        public CustomLogger(ILogger logger)
        {
          _logger = logger ?? throw new ArgumentNullException(nameof(logger));
        _logPrefix = null;
        }

        public ILogger SetLogPrefix(string logPrefix)
        {
          _logPrefix = logPrefix;
          return this;
        }

        public IDisposable BeginScope<TState>(TState state)
        {
          return _logger.BeginScope(state);
        }

        public bool IsEnabled(LogLevel logLevel)
        {
          return _logger.IsEnabled(logLevel);
        }

        public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
        {
          _logger.Log(logLevel, eventId, state, exception, formatter);
        }

      }

Answer

Khai Nguyen picture Khai Nguyen · Nov 27, 2018

I think you should not call a _logger in a custom logger.

It would be a circular call on runtime and the result would be "prefix: prefix: prefix: prefix: prefix: prefix: prefix: prefix: ..."

Simply, you can create a simple logger and implement a log writter such as Console, database writter, log4net, ...

Now first, you should change your custom logger like below:

    public class CustomLogger : ILogger
    {
        private readonly string CategoryName;
        private readonly string _logPrefix;

        public CustomLogger(string categoryName, string logPrefix)
        {
            CategoryName = categoryName;
            _logPrefix = logPrefix;
        }

        public IDisposable BeginScope<TState>(TState state)
        {
            return new NoopDisposable();
        }

        public bool IsEnabled(LogLevel logLevel)
        {
            return true;
        }

        public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
        {
            string message = _logPrefix;
            if (formatter != null)
            {
                message += formatter(state, exception);
            }
            // Implement log writter as you want. I am using Console
            Console.WriteLine($"{logLevel.ToString()} - {eventId.Id} - {CategoryName} - {message}");
        }

        private class NoopDisposable : IDisposable
        {
            public void Dispose()
            {
            }
        }
    }

The second step, create a logger provider:

     public class LoggerProvider : ILoggerProvider
        {     
            public ILogger CreateLogger(string categoryName)
            {                
                return new CustomLogger(categoryName, "This is prefix: ");
            }

            public void Dispose()
            {
            }
        }

The third step, in Configure from Startup.cs:

    loggerFactory.AddProvider(new MicroserviceLoggerProvider());