Уничтожение исключений в Serilog

Serilog имеет удобный способ деструктурирования объектов, как показано в этом примере:

logger.Debug(exception, "This is an {Exception} text", exception);
logger.Debug(exception, "This is an {@Exception} structure", exception);

Первая строка приводит к тому, что регистратор регистрирует исключение как обычный текст (вызывая ToString()), а вторая строка заставляет журнал регистрировать свойства исключения как отдельные поля. Но как насчет этой перегрузки:

logger.Debug(exception, "This is an exception", exception);

Это принимает исключение в качестве первого аргумента и всегда записывается как строка. То, что я хотел бы сделать возможным, заключается в том, чтобы включить исключение регистрации в структурированном виде. Можно ли настроить Serilog для этого?

ОБНОВИТЬ. Я предполагаю, что этот вопрос приводит к еще одному аспекту исключений регистрации: как я могу обеспечить, чтобы сообщения были обогащены свойствами исключений (поэтому они регистрируются структурированным способом для богатых поглотителей, таких как Elasticsearch), не записывая все свойства исключения в отображаемое текстовое сообщение ( поэтому обычные текстовые журналы не заполнены огромными кучами деталей исключения).

Ответ 1

Там обсуждается это обсуждение форума, в котором представлены несколько решений. Томас Болон создал расширение исключения, которое можно найти в Gist.

В этом случае вы используете только этот синтаксис:

logger.Debug(exception, "This is an exception");

Нет необходимости добавлять исключение в строку формата.

Чтобы исключение печаталось в текстовые раковины, просто убедитесь, что {Exception} включено в выходной шаблон. Стандартные встроенные уже имеют это, например:

outputTemplate: "{Timestamp} [{Level}] {Message}{NewLine}{Exception}";

Ответ 2

Взгляните на Serilog.Exceptions регистрирует детали исключений и настраиваемые свойства, которые не выводятся в Exception.ToString().

Эта библиотека имеет собственный код для работы с дополнительными свойствами в большинстве распространенных типов исключений и только возвращается к использованию отражения, чтобы получить дополнительную информацию, если исключение не поддерживается Serilog. Исключения внутри.

Добавьте пакет NuGet, а затем добавьте enricher так:

using Serilog;
using Serilog.Exceptions;

ILogger logger = new LoggerConfiguration()
    .Enrich.WithExceptionDetails()
    .WriteTo.Sink(new RollingFileSink(
        @"C:\logs",
        new JsonFormatter(renderMessage: true))
    .CreateLogger();

Теперь ваши журналы JSON будут дополнены подробной информацией об исключении и даже настраиваемыми свойствами исключения. Вот пример того, что происходит, когда вы регистрируете исключение DbEntityValidationException из EntityFramework (это исключение известно для наличия глубоко вложенных пользовательских свойств, которые не включены в .ToString()).

try
{
    ...
}
catch (DbEntityValidationException exception)
{
    logger.Error(exception, "Hello World");
}

В приведенном выше коде записывается следующее:

{
  "Timestamp": "2015-12-07T12:26:24.0557671+00:00",
  "Level": "Error",
  "MessageTemplate": "Hello World",
  "RenderedMessage": "Hello World",
  "Exception": "System.Data.Entity.Validation.DbEntityValidationException: Message",
  "Properties": {
    "ExceptionDetail": {
      "EntityValidationErrors": [
        {
          "Entry": null,
          "ValidationErrors": [
            {
              "PropertyName": "PropertyName",
              "ErrorMessage": "PropertyName is Required.",
              "Type": "System.Data.Entity.Validation.DbValidationError"
            }
          ],
          "IsValid": false,
          "Type": "System.Data.Entity.Validation.DbEntityValidationResult"
        }
      ],
      "Message": "Validation failed for one or more entities. See 'EntityValidationErrors' property for more details.",
      "Data": {},
      "InnerException": null,
      "TargetSite": null,
      "StackTrace": null,
      "HelpLink": null,
      "Source": null,
      "HResult": -2146232032,
      "Type": "System.Data.Entity.Validation.DbEntityValidationException"
    },
    "Source": "418169ff-e65f-456e-8b0d-42a0973c3577"
  }
}

Serilog.Exceptions поддерживает стандарт.NET и поддерживает множество распространенных типов исключений без отражения, но мы хотели бы добавить больше, поэтому, пожалуйста, не стесняйтесь вносить свой вклад.

Top Tip - отслеживаемые трассировки стека

Вы можете использовать пакет Ben.Demystifier NuGet, чтобы получить отслеживаемые пользователем трассировки стека за исключениями или пакет NuGet с серилограммой-демистифицировать, если вы используете Serilog.

Ответ 3

Этого следует избегать вообще. И ElasticSearch, и Serilog не разработаны с учетом того, что вы будете сериализовывать произвольные объекты. Запись объектов с конфликтующими фигурами приведет к отображению исключений в ElasticSearch. Если вы используете приемник ElasticSearch в NuGet, все, что приводит к конфликту с отображением, будет потеряно. Кроме того, Serilog не обрабатывает циклические отношения, поэтому это приведет к ошибкам самобога. Существует проект, который пытается решить эту проблему путем деструктурирования в словарях и передачи этого в Serilog, но вы все равно столкнетесь с беспорядочными журналами и исключениями отображения.

Serilog: https://nblumhardt.com/2016/02/serilog-tip-dont-serialize-arbitrary-objects/

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