Имена полей Serilog для свойств, не используемых в шаблоне сообщения

#c# #logging #serilog

#c# #ведение журнала #serilog

Вопрос:

Я тестирую Serilog, и у меня возникли некоторые проблемы с именами полей.

Я хочу добавить запись журнала с одним полем, включенным в шаблон сообщения, а другие поля просто сохраняются в журнале для выполнения запросов.

Я хотел бы сделать что-то простое вроде этого:

 logger.Debug("Recalculation performed for operation {OperationId}", 
                operationId, operationTypeId, otherId, anotherId);
  

Но это приводит к тому, что именам полей не присваиваются понятные имена, поскольку их нет в шаблоне сообщения:

 {
   "@timestamp":"2016-10-20T16:57:02.0623798 01:00",
   "level":"Debug",
   "messageTemplate":"Recalculation performed for operation {OperationId}",
   "fields":{  
      "OperationId":1024,
      "__1":16,
      "__2":32,
      "__3":256,
      "SourceContext":"SerilogTest.Worker"
   }
}
  

Я знаю, что могу поместить все поля в класс и использовать метод ForContext для включения их в запись журнала:

 internal class OperationData
{
    public int OperationId { get; set; }

    public int OperationTypeId { get; set; }

    public int OtherId { get; set; }

    public int AnotherId { get; set; }
}

var operationData = new OperationData
                {
                    OperationId = 1024,
                    OperationTypeId = 16,
                    OtherId = 32,
                    AnotherId = 256
                };

var operationLogger = logger.ForContext("OperationData", 
                        operationData, destructureObjects: true);
operationLogger.Debug("Recalculation performed for operation {OperationId}",
                         operationData.OperationId);
  

Такой вид дает мне результат, который я ищу:

 {
   "@timestamp":"2016-10-20T18:00:35.4956991 01:00",
   "level":"Debug",
   "messageTemplate":"Recalculation performed for operation {OperationId}",
   "fields":{  
      "OperationId":1024,
      "OperationData":{  
         "_typeTag":"RecalulationResult",
         "OperationId":1024,
         "OperationTypeId":16,
         "OtherId":32,
         "AnotherId":256
      },
      "SourceContext":"SerilogTest.Worker"
   }
}
  

НО, похоже, требуется приложить немало усилий, чтобы просто иметь понятные имена полей. Я должен создать новый экземпляр logger, иметь тип, который включал бы все соответствующие поля для сообщения журнала, а затем вести журнал. Есть ли более простой способ присвоения имен полям, чем этот?

Ответ №1:

Анонимные типы достигают того, что у вас есть выше, с гораздо меньшим количеством кода:

 logger
    .ForContext("Operation", new {operationTypeId, otherId, anotherId}, true)
    .Debug("Recalculation performed for operation {OperationId}", operationId);
  

Или, альтернативно, путем включения всего в событие:

 logger.Debug("Recalculation performed for operation {@Operation}", new {
        Id = operationId, TypeId = operationTypeId, OtherId = otherId, 
        AnotherId = anotherId
    });
  

Если вы обнаружите, что существует много сообщений, в которые вы хотите включить одни и те же свойства, возможно, вам лучше перенести их на LogContext :

 using (LogContext.PushProperty("OperationId", operationId))
{
    logger.Debug("Recalculation performed");

    // ...etc...

    logger.Debug("Something else");
}
  

В этом случае с обоими событиями будет OperationId связан. Вы можете добавить несколько свойств в контекст журнала. Просто не забудьте добавить Enrich.FromLogContext() в свой LoggerConfiguration , чтобы использовать этот стиль.

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

1. Я предполагал, что анонимные типы не будут работать, поскольку Serilog должен использовать отражение, а отражение плохо работает с анонимными типами. Я попробую это сделать.

2. Отражение @GlenThomas довольно хорошо работает с анонимными типами.. какие конкретные проблемы существуют?

3. @user2864740 В прошлом у меня были проблемы с использованием библиотек на основе отражения, таких как Dapper, с анонимными типами. Возможно, это была более старая версия . NET framework, но я уверен, что метаданные свойства типа недоступны или уменьшены, когда тип анонимный.