Исключение StackOverflowException в Serilog Enricher’е

#c# #.net #asp.net-core #stack-overflow #serilog

#c# #.net #asp.net-core #переполнение стека #serilog

Вопрос:

Я пишу enricher’е для Serilog и хочу добавить свойство, которое на практике может вызвать новое событие журнала:

 public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory)
{
    ISession session = /* HttpContext.Session */;
    logEvent.AddPropertyIfAbsent(propertyFactory.CreateProperty("ValueFromSession", session.GetString("ValueFromSession")));
    /* other properties ... */
}
  

Я хочу иметь возможность добавлять значение из моего http-сеанса в свои журналы, поэтому я использую LogContext.PushProperties с пользовательским enricher’ом. ASP.NET Ядро регистрирует предупреждение всякий раз, когда считывается сеанс с истекшим сроком действия, что запускает мой enricher’а, но всякий раз, когда я пытаюсь прочитать из сеанса в enricher’е, оно предупреждает меня об истекшем сеансе, который запускает новый экземпляр моего enricher’а (до бесконечности). Это приводит к тому, StackOverflowException что, похоже, не улавливается с try блоком.

Есть ли какой-либо способ отключить ведение журнала в Enrich методе? Или я могу как-то обнаружить этот вид рекурсии (кроме разбора трассировки стека)?

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

1. внимательно проверьте, есть ли какая-либо циклическая ссылка

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

3. Исключения, создаваемые изнутри, Enrich() должны перехватываться Serilog и не приводить к запуску другого обработчика исключений верхнего уровня. Похоже, что здесь может происходить что-то еще; можете ли вы добавить трассировку стека к вопросу? Приветствия!

4. Проблема не в том, что он регистрирует выброшенное исключение, ASP.NET просто регистрирует предупреждение всякий раз, когда я обращаюсь HttpContext.Session в этом конкретном случае, что я хочу иметь возможность делать в моем enricher’е. Конечным результатом этой взаимной рекурсии является переполнение стека.

Ответ №1:

Я столкнулся с этой проблемой в своей пользовательской ILogger реализации (не используя Serilog). Это происходит всякий раз, когда осуществляется доступ к объекту сеанса. Мне удалось исправить это, добавив защиту данных с сохраненными ключами в мое приложение при запуске.

 services.AddDataProtection()
    .PersistKeysToFileSystem(new DirectoryInfo("keys"));
  

Я не слишком углублялся в детали реализации, но из того, что я вижу в коде DistributedSession, сообщение «Доступ к сеансу с истекшим сроком действия» регистрируется при обнаружении старого ключа сеанса. Проблема здесь в том, что ведение журнала происходит до того, как isAvailable флаг установлен на true , что вызывает рекурсию. Я не знаю, почему добавление DataProtection позволяет избежать этой проблемы, но возможно, что защита данных приводит к тому, что _isNewSessionKey всегда true .

Другим обходным путем, предложенным в GitHub, было бы добавление промежуточного программного обеспечения для сохранения элементов сеанса, которые вы хотите зарегистрировать в HttpContext.Товары. Затем извлеките эти элементы в своем регистраторе.