web-dev-qa-db-fra.com

Implémentation personnalisée d'ILogger

Dans mon projet, j'ajoute souvent des préfixes à mes messages de journal.

Actuellement je fais ça avec

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

Je pensais que ce serait un bon moyen d'implémenter un enregistreur personnalisé où je définirais le préfixe et l'enregistreur lui-même l'attacherait chaque fois qu'il enregistre quelque chose.

J'ai donc créé ma classe de logger personnalisé et implémenté l'interface ILogger. Mais je ne comprends pas comment utiliser le

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

pour ajouter le préfixe (qui est membre de la classe d'enregistreur personnalisé).

Mon code complet est:

      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

Personnellement, je pense que ce n'est pas un bon moyen de le faire, "préfixe" sera dupliqué beaucoup. Pourquoi n'utilisez-vous pas Log Scopes à la place?

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

Production

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

Actuellement, vous ne pouvez pas modifier le modèle de journalisation, c'est la limitation de la journalisation de base intégrée dans Asp.net Core. Pour un plus puissant, vous pouvez essayer Serilog , continuer à utiliser l'interface ILogger et changer une ligne de code dans program.cs classe

Vous devriez également regarder ceci Avantages de la journalisation structurée par rapport à la journalisation de base

5
Hung Quach

Je pense que vous ne devriez pas appeler un _logger dans un enregistreur personnalisé.

Ce serait un appel circulaire à l'exécution et le résultat serait "prefix: prefix: prefix: prefix: prefix: prefix: prefix: prefix: ..."

Simplement, vous pouvez créer un enregistreur simple et implémenter un écrivain de journal tel que Console, écrivain de base de données, log4net, ...

Maintenant, vous devez d'abord changer votre enregistreur personnalisé comme ci-dessous:

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

La deuxième étape, créez un fournisseur d'enregistreur:

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

            public void Dispose()
            {
            }
        }

La troisième étape, dans Configurer à partir de Startup.cs:

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

Implémentez une extension pour ajouter prefix aux enregistrements de journal.

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

Utilisation:

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