web-dev-qa-db-ja.com

ILoggerのカスタム実装

私のプロジェクトでは、ログメッセージにプレフィックスを追加することがよくあります。

現在私はこれをやっています

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

プレフィックスを設定し、ロガー自体が何かをログに記録するたびにそれを付加するカスタムロガーを実装するのに良い方法だと思いました。

そこで、カスタムロガークラスを作成し、ILoggerインターフェイスを実装しました。しかし、私は使用方法がわかりません

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

プレフィックス(カスタムロガークラスのメンバー)を追加するメソッド。

私の完全なコードは:

      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);
        }

      }
5
monty

個人的には、それを行うのは良い方法ではないと思います。「プレフィックス」はたくさん複製されます。代わりに Log Scopes を使用しないのはなぜですか?

public IActionResult GetById(string id)
{
    TodoItem item;
    using (_logger.BeginScope("Message attached to logs created in the using block"))
    {
        _logger.LogInformation(LoggingEvents.GetItem, "Getting item {ID}", id);
        item = _todoRepository.Find(id);
        if (item == null)
        {
            _logger.LogWarning(LoggingEvents.GetItemNotFound, "GetById({ID}) NOT FOUND", id);
            return NotFound();
        }
    }
    return new ObjectResult(item);
}

出力

info: TodoApi.Controllers.TodoController[1002]
      => RequestId:0HKV9C49II9CK RequestPath:/api/todo/0 => TodoApi.Controllers.TodoController.GetById (TodoApi) => Message attached to logs created in the using block
      Getting item 0
warn: TodoApi.Controllers.TodoController[4000]
      => RequestId:0HKV9C49II9CK RequestPath:/api/todo/0 => TodoApi.Controllers.TodoController.GetById (TodoApi) => Message attached to logs created in the using block
      GetById(0) NOT FOUND

現在、ロギングテンプレートを変更することはできません。これは、Asp.net Coreに組み込まれている基本的なロギングの制限です。より強力なものについては、 Serilog を試して、ILoggerインターフェイスを引き続き使用し、program.csクラスのコード行をいくつか変更することができます

これも見てください 構造化ロギングの利点と基本的なロギングの利点

5
Hung Quach

カスタムロガーで_loggerを呼び出さないでください。

これは実行時の循環呼び出しとなり、結果は「プレフィックス:プレフィックス:プレフィックス:プレフィックス:プレフィックス:プレフィックス:プレフィックス:プレフィックス:...」となります。

単純に、シンプルなロガーを作成し、コンソール、データベースライター、log4netなどのログライターを実装できます。

まず、カスタムロガーを次のように変更する必要があります。

    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()
            {
            }
        }
    }

2番目のステップでは、ロガープロバイダーを作成します。

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

            public void Dispose()
            {
            }
        }

Startup.csから構成の3番目のステップ:

    loggerFactory.AddProvider(new MicroserviceLoggerProvider());
5
Khai Nguyen

ログレコードにprefixを追加するための拡張機能を実装します。

    public static class LogExtensions
    {
        public static void PrefixLogDebug(this ILogger logger, string message, string prefix = "Edward", params object[] args)
        {
            logger.LogDebug($"{prefix} {message}");
        }
    }

使用法:

        _log.PrefixLogDebug("Log From Prefix extension");
        _log.PrefixLogDebug("Log From Prefix extension", "New Prefix");
1
Edward