#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, но я уверен, что метаданные свойства типа недоступны или уменьшены, когда тип анонимный.