Можно ли отключить деструктурирование на основе отражения в Serilog.Exceptions?

Пакет Serilog.Exceptions удобен для регистрации исключений. Он имеет большой список поддерживаемых типов исключений.

например, текущая настройка:

Log.Logger = new LoggerConfiguration()
    .Enrich.WithExceptionDetails()
    .CreateLogger();

В настоящее время он возвращается к "деструктурированию на основе отражения", если для типа исключения не найдено деструктурирование.

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

Я попытался настроить это с помощью DestructuringOptions, например, отключите некоторые из деструкторов по умолчанию или установите для DestructuringDepth значение 0.

К сожалению, эти варианты не работают:

  • то ReflectionBasedDestructurer отсутствует в списке деструкторов по умолчанию
  • установка DestructuringDepth к 0 не разрешено (исключение)

Есть идеи, как настроить для этого Serilog.Exceptions?

2 ответа

Решение

Это было добавлено в Serilog.Exceptions 5.4.0, см. Журнал изменений. Есть новый методWithoutReflectionBasedDestructurer.

Применение

Класс помощника

public static class LoggerEnrichmentConfigurationExtensions
{
    public static LoggerConfiguration WithExceptionDetailsWithoutReflection(
        this LoggerEnrichmentConfiguration loggerEnrichmentConfiguration)
    {
        if (loggerEnrichmentConfiguration is null)
        {
            throw new ArgumentNullException(nameof(loggerEnrichmentConfiguration));
        }
        var options = new DestructuringOptionsBuilder()
            .WithDefaultDestructurers()
            .WithoutReflectionBasedDestructurer() //new in 5.4.0!
            .WithIgnoreStackTraceAndTargetSiteExceptionFilter();
        var logEventEnricher = new ExceptionEnricher(options);
        return loggerEnrichmentConfiguration.With(logEventEnricher);
    }
}

Конфиг

Log.Logger = new LoggerConfiguration()
                .ReadFrom.Configuration(configuration)
                .Enrich.WithExceptionDetailsWithoutReflection()
                .CreateLogger();

Думаю, лучший вариант - это реализовать свой собственный ExceptionDecostructor, что-то вроде этого:

 public class FallbackExceptionDestructurer : ExceptionDestructurer
 {
        public override Type[] TargetTypes => new[]
        {
            typeof(Exception),
        };

        public override void Destructure(
            Exception exception,
            IExceptionPropertiesBag propertiesBag,
            Func<Exception, IReadOnlyDictionary<string, object>> destructureException)
        {
            base.Destructure(exception, propertiesBag, destructureException);
        }
 }

Таким образом вы сохраните все доступные деструкторы, а отражение будет проигнорировано, потому что FallbackExceptionDestructurer будет охватывать все неизвестные исключения из-за этого кода:

public override Type[] TargetTypes => new[]
{
  typeof(Exception),
};

Вот как вы регистрируете деструкторы

.Enrich.WithExceptionDetails(new DestructuringOptionsBuilder()
    .WithDefaultDestructurers()
    .WithDestructurers(new[] { new FallbackExceptionDestructurer () }))

Если вы проверите исходный код ExceptionDestructurer.Decostruct(...), он не использует никакого отражения - только хорошо известные свойства из типа Exception.

Другие вопросы по тегам