2014-01-31 4 views
13

У нас есть служба, которая будет регистрировать необработанные исключения на уровне домена приложения (через Log4net).исключение без трассировки стека - как?

Мы вошли:

2014-01-28 16: 49: 19636 ОШИБКА [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 и отсутствие следа.

Я проверил регистрацию обработчика исключений и успешно выполнил протоколирование трассировки стека и любого внутреннего исключения. Если бы он был брошен нашим кодом, мы увидели бы трассировку стека. Если он был брошен третьей библиотекой C#, то снова мы увидим трассировку стека хотя бы одного метода (будь то повторное исключение или нет). Здесь мы видим управляемое исключение без трассировки стека. Я не знаю, как это возможно.

Рассматривая декомпилированную стороннюю библиотеку, он разговаривает с неуправляемым кодом, и событие, вызвавшее это исключение, вероятно, находится на неуправляемой земле, но как могла такая ситуация вызвать исключение с помощью null null без stacktrace?

Причина этой проблемы является прерывистой. Мы запускаем этот код в производстве в течение нескольких месяцев и видим, как он это делает. Это довольно причудливо.

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

Редактировать включить комментарий снизу:

Мое исключение не является стандартным повторно бросить, потому что трассировка стека либо нулевым или пустым. В нем нет имени метода повторного броска. Копаясь дальше, класс Exception может быть построен из сериализованной информации, и похоже, что сериализованная информация может содержать пустые строки для трассировки стека и потенциально может быть создана без возникновения других ошибок. Я думаю, это может произойти оттуда, но я не знаю, как это произошло.

+1

[Эта нить] (http://stackoverflow.com/questions/57383/in-c-how-can-i-rethrow-innerexception-without-losing-stack-trace) может помочь – Andrei

+0

Finger poking: попытайтесь проверить ['Environment.StackTrace'] (http://msdn.microsoft.com/en-us/library/system.environment.stacktrace.aspx) и, возможно, внутреннее исключение? – Sinatr

+0

@ Аndrei это интересное чтение, но у моего исключения нет даже одного метода в его трассировке стека, который я бы имел, если бы это был обычный повторный бросок. Далее, класс Exception может быть построен из сериализованной информации, и похоже, что сериализованная информация может содержать нулевые строки для трассировки стека без возникновения ошибок. Я думаю, это может произойти оттуда, но я не знаю, как это произошло. – Skym

ответ

9

Если вы получаете исключение, но не имеете соответствующей трассировки стека, то в какой-то момент обработчик исключений, вероятно, оценивает исключение и повторно бросает его неправильно. Например, если вы делаете throw ex;, вы будете есть трассировку стека, которая привела бы к этой точке.Для того, чтобы сохранить существующий стек вызовов вы хотите просто throw; Throwing exceptions best practices

Обратите внимание, что C# способом является противоположностью конвенции для языка Java, где вы должны throw ex; Java справки: Best Practice: Catching and re-throwing Java Exceptions

1

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

public class YourCustomException: Exception 
{ 
    public YourCustomException() : base() { } //constructor 

    public override string StackTrace 
    { 
     get { return " at: my custom stack trace"; } 
    } 
} 
Смежные вопросы