Как распечатать текущий Stack Trace в .NET без каких-либо исключений?

350

У меня есть обычный код C #. У меня нет исключений . Я хочу программно регистрировать текущую трассировку стека для целей отладки. Пример:

public void executeMethod() 
{
    logStackTrace();
    method();
}
Ricibald
источник

Ответы:

401

Посмотрите на System.Diagnosticsпространство имен. Там много вкусностей!

System.Diagnostics.StackTrace t = new System.Diagnostics.StackTrace();

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

Я бы порекомендовал вам взглянуть на решения для ведения журналов (такие как NLog, log4net или корпоративная библиотека шаблонов и практик Microsoft), которые могут достичь ваших целей, а затем и некоторых. Удачи, приятель!

кладовая для продуктов
источник
74
Имейте в виду, что StackTraceэто собака медленно - так что используйте это экономно.
Джонатан Дикинсон
214

Альтернативой System.Diagnostics.StackTraceявляется использование System.Environment.StackTrace, которое возвращает строковое представление трассировки стека.

Другой полезный вариант - использовать переменные$CALLER и $CALLSTACK отладки в Visual Studio, поскольку это можно включить во время выполнения без перестройки приложения.

larsmoa
источник
6
Environment.StackTraceпросто новый пример StackTrace.
Даниэль
9
@ Даниель: Да, но System.Environment.StackTraceможет быть более удобным способом доступа к этой информации.
Ларсмоа
6
@AndreiRinea: На самом деле, я полагаю, что вы можете получить доступ к номерам линий, используя System.Diagnostics.StackTrace- см. Msdn.microsoft.com/en-us/library/…
larsmoa
5
Разве это не раздражает, что Environment.StackTraceвсегда начинается с at System.Environment.GetStackTrace(Exception e, Boolean needFileInfo) at System.Environment.get_StackTrace()? Это не является частью текущей трассировки стека, поскольку кто-то ищет ее.
Рори
7
@Rory, взгляните на конструктор StackTrace (int skipFrames, bool fNeedFileInfo), вы можете пропустить начальный кадр. Откройте метод в ILSpy, и вы увидите, что он делает
Уолтер Веховен,
39

Есть два способа сделать это. Это System.Diagnostics.StackTrace()даст вам трассировку стека для текущего потока. Если у вас есть ссылка на Threadэкземпляр, вы можете получить трассировку стека для этого через перегруженную версию StackTrace().

Вы также можете проверить вопрос переполнения стека. Как получить трассировку стека нетокового потока? ,

Брайан Расмуссен
источник
16

Вы также можете сделать это в отладчике Visual Studio без изменения кода.

  1. Создайте точку останова, где вы хотите увидеть трассировку стека.
  2. Щелкните правой кнопкой мыши точку останова и выберите «Действия ...» в VS2015. В VS2010 выберите «При попадании ...», затем включите «Распечатать сообщение».
  3. Убедитесь, что выбрано «Продолжить выполнение».
  4. Введите текст, который вы хотите распечатать.
  5. Добавьте $ CALLSTACK везде, где вы хотите увидеть трассировку стека.
  6. Запустите программу в отладчике.

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

Хэнк Шульц
источник
7
Если вы хотите увидеть трассировку стека и уже находитесь в отладчике VS в точке останова, просто перейдите в Debug-> Windows-> Call Stack.
Харгуш
5
Да, но если вы сделаете это таким образом, программе не нужно останавливаться, чтобы увидеть трассировку стека.
Хэнк Шульц
7
Console.WriteLine(
    new System.Diagnostics.StackTrace().ToString()
    );

Вывод будет похож на:

на YourNamespace.Program.executeMethod (Строка сообщения)

at YourNamespace.Program.Main (String [] args)

Замените Console.WriteLineсвоим Logметодом. На самом деле, нет необходимости .ToString()в случае Console.WriteLine, как он принимает object. Но вам может понадобиться это для вашего метода Log (string msg).

EPoX
источник
-2
   private void ExceptionTest()
    {
        try
        {
            int j = 0;
            int i = 5;
            i = 1 / j;
        }
        catch (Exception ex)
        {
            Console.WriteLine("Error: " + ex.Message);
            var stList = ex.StackTrace.ToString().Split('\\');
            Console.WriteLine("Exception occurred at " + stList[stList.Count() - 1]);
        }
    }

Кажется, работает на меня

Джефф Джейкобс
источник
3
Это просто генерирует очевидное исключение. Зачем? Почему бы просто не создать в явном виде исключение, а не недостаток, который вызовет исключение само по себе? Какая польза от дополнительной логики перехвата, необходимой для получения фактического исключения? И даже в этом случае вы по-прежнему игнорируете фактический опубликованный вопрос о том, как получить трассировку стека без каких-либо исключений (см. Заголовок).
Флатер
это верный ответ, но ужасное решение. НИКТО НЕ ДОЛЖЕН ИСПОЛЬЗОВАТЬ ЭТО… @Даже, где бы вы ни делали это, замените его кодом спуска, как и в других предложенных ответах.
Томер W