#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.Товары. Затем извлеките эти элементы в своем регистраторе.