Исключение без трассировки стека - как?
У нас есть служба, которая будет регистрировать необработанные исключения на уровне домена приложения (через Log4net).
Мы вошли в систему:
2014-01-28 16: 49: 19,636 ОШИБКА [49] FeedWrapperService - необработанный System.NullReferenceException: ссылка на объект не установлена в экземпляр объекта.
В этом исключении нет трассировки стека. Как это возможно без каких-либо сумасшедших вещей для объекта исключения?
Наш код обработки:
AppDomain.CurrentDomain.UnhandledException += LogAnyExceptions;
private void LogAnyExceptions(object sender, UnhandledExceptionEventArgs e)
{
log.Error("unhandled", (Exception)e.ExceptionObject);
throw (Exception)e.ExceptionObject;
}
Мне кажется, что повторный бросок здесь бессмыслен, потому что AppDomain все равно будет с ним работать, но я не думаю, что это влияет на нашу ситуацию.
Средство просмотра событий приложения Windows также показывает только это исключение null ref и отсутствие трассировки.
Я проверил ведение журнала обработчиков исключений, и он успешно регистрирует трассировку стека и любое внутреннее исключение. Если бы он был брошен нашим кодом, мы увидели бы трассировку стека. Если он был брошен третьей библиотекой С#, то снова мы увидим трассировку стека хотя бы одного метода (будь то повторное исключение или нет). Здесь мы видим управляемое исключение без трассировки стека. Я не знаю, как это возможно.
Глядя на декомпилированную стороннюю библиотеку, он говорит о неуправляемом коде, и событие, вызвавшее это исключение, скорее всего, находится на неуправляемой земле, но как могла такая ситуация вызвать исключение исключенного исключения без стека?
Причина этой проблемы прерывистая. Мы запускаем этот код в производстве в течение нескольких месяцев и видим, как он это делает. Это довольно странно.
Общий консенсус заключается в том, что система, ответственная за эту проблему, должна быть отброшена в дочерний процесс, чтобы мы могли справиться с проблемой и перезапустить безопасно и автоматически, но было бы хорошо знать, что происходит.
Изменить для включения информации о комментариях ниже:
Мое исключение не является стандартным повторным броском, потому что трассировка стека является пустой или пустой. В нем нет имени метода повторного броска. Копаясь дальше, класс Exception может быть построен из сериализованной информации, и похоже, что сериализованная информация может содержать пустые строки для трассировки стека и потенциально может быть создана без возникновения других ошибок. Я предполагаю, что это может произойти оттуда, но я не знаю, как это произошло.
Ответы
Ответ 1
Если вы получаете исключение, но не соответствующую трассировку стека, то в какой-то момент обработчик исключений, вероятно, оценивает исключение и повторно бросает его неправильно. Например, если вы делаете throw ex;
, вы будете есть трассировку стека, которая привела бы к этой точке. Чтобы сохранить существующий стек вызовов, вы просто хотите throw;
Рекомендации по устранению исключений
Обратите внимание, что путь С# является противоположным соглашению для языка Java, где вы должны throw ex;
ссылка на Java: Лучшая практика: Ловля и повторное бросание исключений Java
Ответ 2
Я предпочитаю управлять своими исключениями с пользовательскими исключениями. Если в вашем случае вы используете свои собственные исключения, вы можете пойти в класс, если бы вы определили их и переопределили stacktrace. например:
public class YourCustomException: Exception
{
public YourCustomException() : base() { } //constructor
public override string StackTrace
{
get { return " at: my custom stack trace"; }
}
}