ILogger, получающий доступ к аргументам параметров в журнале функций (LogLevel LogLevel

#c# #asp.net-core #.net-core

#c# #asp.net-core #.net-ядро

Вопрос:

Я внедряю пользовательский ILogger в .Net Core 3.1. Класс должен реализовать следующий контракт

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

Я запускаю функцию LogDebug и передаю список аргументов кортежа (ключ, значение) следующим образом:

 logger.LogDebug("MyDebugMessage", ("arg1Key", "arg2Value"), ("arg2Key", "arg2Value"), ("arg3Key", "arg3Value"));
  

Запускается функция журнала ILogger, и первый параметр — сообщение «MyDebugMessage» — передается в параметр состояния. Однако в функции ILogger нет переменной для списка аргументов.
Как я могу получить доступ к списку аргументов?

Комментарии:

1. Попробуйте что-то вроде этого: Список <Ключевая пара<строка, строка>> значения = новый список <Ключевая пара <строка, строка>>() { новая ключевая пара <строка, строка> («arg1Key», «arg2Value»), новая ключевая пара <строка, строка> («arg2Key», «arg2Value»), new KeyValuePair<строка,строка>(«arg3Key», «arg3Value») }; строковое сообщение = строка. Join(«;», значения. Выберите(x => строка. Формат(«{0},{1}», x.Ключ, x.Значение)));

2. Спасибо @jdweng за ваш ответ. Как я могу получить доступ к значениям внутри общедоступного метода void Log<TState> ?

3. Результаты работы регистратора помещаются в файл.

4. Я использую пользовательский регистратор, поэтому я реализовал метод ILogger внутри пользовательского класса. Когда происходит ведение журнала, этот метод вызывается внутри пользовательского регистратора. Но я не могу получить доступ к переданным значениям. Следовательно, мой вопрос в том, как я могу получить доступ к переданным значениям внутри пользовательского класса.

5. Это словарь. См . : learn.microsoft.com/en-us/aspnet/core/fundamentals/logging /…

Ответ №1:

До сих пор я обнаружил, что единственный способ — использовать отражение, чтобы получить закрытый член _values состояния TState.

   public class ApiLogger : ILogger
  {
       // more code 

       public async void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
       {  
               
           FieldInfo[] fieldsInfo = state.GetType().GetFields(BindingFlags.NonPublic | BindingFlags.Instance);
           FieldInfo props = fieldsInfo.FirstOrDefault(o => o.Name == "_values");
           object[] values = (object[])props?.GetValue(state);

           // more code 
       }

       // more code 
}
  

Ответ №2:

Объектом по умолчанию, переданным в «состояние TState», является Microsoft.Расширения.Ведение журнала.Formattedlog values

который является производным от типа IReadOnlyList<KeyValuePair<строка, объект>>

из него можно получить список аргументов kvp

Ответ №3:

Хак с отражением, описанный Хьюго, больше не работает в .net core 7

Я думаю, что ‘params object[]? параметр args никогда не предназначался для передачи дополнительных данных вашему ILogger.Реализация журнала, но предназначена только для форматирования сообщения.

Поэтому я придумал альтернативное решение.

Я использую параметр EventID, который я обычно не использую. EventID — это объект с идентификатором int и свойством string Name . Это свойство Name может быть заполнено любой строкой, которая вам нравится. Я просто создаю типизированный объект и сериализую его в json. Создайте экземпляр класса EventID с нерелевантным свойством Id и именем, присвоенным my json.

В вашем ILogger.Реализация журнала Я просто десериализую идентификатор события.Назовите его типизированный класс, и я ввел доступ к данным, которые я хочу передать.

Вы могли бы использовать свойство Id, чтобы сообщить принимающей стороне, какой объект можно десериализовать из свойства Name . Таким образом, вы можете передавать серверные типы объектов.

Комментарии:

1. Согласен, я думал о том же и реализовал с использованием EventID . Спасибо!