Вопрос по .net, c# – Воссоздать трассировку стека с номерами строк из отчета об ошибке пользователя в .net?

15

First, the problem: У меня есть несколько бесплатных проектов, и, как и любое программное обеспечение, они содержат ошибки. Некоторые коллеги-пользователи при обнаружении ошибки присылают мне отчеты об ошибках со следами стека. Чтобы упростить поиск места неисправности, я хочу видеть номера строк в этой трассировке стека. Если приложение поставляется без файлов .pdb, то вся информация о строках теряется, поэтому в настоящее время все мои проекты развернуты с файлами .pdb и, следовательно, сгенерированные трассировки стека имеют эти номера. Но! Но я не хочу видеть эти файлы в дистрибутиве и хочу удалить все .pdb. Они сбивают с толку пользователей, занимают место в установщике и т. Д.

Delphi solution: Давным-давно, когда я был программистом на Delphi, я использовал следующую технику: в исключительных случаях мое приложение ходило по стеку и собирало адреса. Затем, когда я получил отчет об ошибке, я использовал инструмент, который восстанавливает правильную трассировку стека с именами функций и номерами строк на основе собранных адресов и соответствующих файлов символов, расположенных на МОЕЙ машине.

Question: Есть ли какая-нибудь библиотека, техника или что-то еще, чтобы сделать то же самое в .NET?

Status Update: Очень интересно, что часто задавание вопроса - лучший способ начать собственное расследование. Например, я некоторое время думаю об этой проблеме, но начинаю искать ответ только несколько дней назад.

Вариант 1: MiniDumps. После долгих поисков я нашел способ создания мини-дампа из кода и воссоздания стека из управляемого мини-дампа.

Redistributable assembly to create mini dump form code - clrdump Blog post about using previous assembly - Creating and analyzing minidumps in .NET production applications

Однако это решение требует перераспределения двух дополнительных сборок (размером ~ 1 МБ), и мини-дампы занимают некоторое место, и пользователю неудобно отправлять их по электронной почте. Так что для моих целей сейчас это недопустимо.

Вариант 2: Спасибо weiqure за подсказку. Можно извлечь управляемое смещение IL для каждого кадра стека. Теперь проблема в том, как получить номера строк из .pdb на основе этого смещения. И что я нашел:

PDB File Internals, just for information because: ISymbolReader - managed interface to read program database files And finally a tool to convert .pdb files to structured xml for easy xpath processing

Используя этот инструмент, можно создавать XML-файлы для каждой сборки выпуска и помещать их в репозиторий. Когда исключение возникает на компьютере пользователя, можно создать отформатированное сообщение об ошибке со смещениями IL. Затем пользователь отправляет это сообщение (очень маленькое) по почте. И, наконец, можно создать простой инструмент, который воссоздает полученный стек из отформатированного сообщения об ошибке.

Мне только интересно, почему никто другой не реализует такой инструмент? Я не верю, что это интересно только мне.

Я выбрал второй вариант и записал кучу классов для замены внутреннего дампа исключений. Я также планирую написать статью о моем решении со всей информацией и источниками. arbiter
После того, как вы напишите статью, оставьте комментарий со ссылкой на этот вопрос. Благодарю. Giorgi
Какой вариант вы выбрали? Я тоже ищу решение. Giorgi
К вашему сведению: в Delphi это теперь легко, потому что есть madExcept, который помещает трассировку стека и другую полезную информацию в отчет об (необработанных) исключениях. schnaader

Ваш Ответ

4   ответа
14

Вы можете получить смещение последней инструкции MSIL из Исключения, используя System.Diagnostics.StackTrace:

// Using System.Diagnostics
static void Main(string[] args)
{
    try { ThrowError(); }
    catch (Exception e)
    {
        StackTrace st = new System.Diagnostics.StackTrace(e);
        string stackTrace = "";
        foreach (StackFrame frame in st.GetFrames())
        {
            stackTrace = "at " + frame.GetMethod().Module.Name + "." + 
                frame.GetMethod().ReflectedType.Name + "." 
                + frame.GetMethod().Name 
                + "  (IL offset: 0x" + frame.GetILOffset().ToString("x") + ")\n" + stackTrace;
        }
        Console.Write(stackTrace);
        Console.WriteLine("Message: " + e.Message);
    }
    Console.ReadLine();
}

static void ThrowError()
{
    DateTime myDateTime = new DateTime();
    myDateTime = new DateTime(2000, 5555555, 1); // won't work
    Console.WriteLine(myDateTime.ToString());
}

Выход:

at ConsoleApplicationN.exe.Program.Main (IL offset: 0x7)
at ConsoleApplicationN.exe.Program.ThrowError (IL offset: 0x1b)
at mscorlib.dll.DateTime..ctor (IL offset: 0x9)
at mscorlib.dll.DateTime.DateToTicks (IL offset: 0x61)
Message: Year, Month, and Day parameters describe an un-representable DateTime.

Вы можете использоватьрефлектор или жеILSpy интерпретировать смещение:

.method private hidebysig static void ThrowError() cil managed
{
    .maxstack 4
    .locals init (
        [0] valuetype [mscorlib]System.DateTime myDateTime)
    L_0000: nop 
    L_0001: ldloca.s myDateTime
    L_0003: initobj [mscorlib]System.DateTime
    L_0009: ldloca.s myDateTime
    L_000b: ldc.i4 0x7d0
    L_0010: ldc.i4 0x54c563
    L_0015: ldc.i4.1 
    L_0016: call instance void [mscorlib]System.DateTime::.ctor(int32, int32, int32)
    L_001b: nop 
    L_001c: ldloca.s myDateTime
    L_001e: constrained [mscorlib]System.DateTime
    L_0024: callvirt instance string [mscorlib]System.Object::ToString()
    L_0029: call void [mscorlib]System.Console::WriteLine(string)
    L_002e: nop 
    L_002f: ret 
}

Вы знаете, что инструкция перед 0x1b вызвала исключение. Для этого легко найти код C #:

 myDateTime = new DateTime(2000, 5555555, 1);

Теперь вы можете отобразить код IL на ваш код C #, но я думаю, что выигрыш будет слишком мал, а усилия слишком велики (хотя может быть плагин отражателя). Вы должны быть в порядке со смещением IL.

Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded arbiter
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceededstackoverflow.com/questions/12264543/…
Error: User Rate Limit ExceededneedError: User Rate Limit Exceeded
5

Вы должны использоватьEnvironment.FailFastвызовите FailFast вApplication.UnhandledException и файл дампа будет создан для вас.

Из MSDN:

The FailFast method writes a log entry to the Windows Application event log using the message parameter, creates a dump of your application, and then terminates the current process.

Use the FailFast method instead of the Exit method to terminate your application if the state of your application is damaged beyond repair, and executing your application's try-finally blocks and finalizers will corrupt program resources. The FailFast method terminates the current process and executes any CriticalFinalizerObject objects, but does not execute any active try-finally blocks or finalizers.

Вы можете написать простое приложение, которое будет собирать файлы журналов и отправлять их вам.

Теперь открыть файл дампа немного сложнее, Visual Studio не может обработать файл управляемого дампа (исправлено в .NET 4.0), который вы можете использоватьWinDBG но вам нужно использоватьСОС.

Error: User Rate Limit Exceeded arbiter
2

Вы можете создать мини-дамп приложения при возникновении ошибки и использовать его для автономного анализа. Это не требует развертывания pdbs на клиентском компьютере.это Ссылка может послужить хорошей отправной точкой для обучения.

Error: User Rate Limit Exceeded arbiter
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
1

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

Microsoft Symbol Server будет индексировать символы отладки и сохранять их для использования позднее, когда у вас, например, будет аварийный дамп, и вам понадобятся символы. Вы можете указать либо Visual Studio, либо Windbg на свой собственный экземпляр сервера символов, какMicrosoft & APOS; s, и он будет опускать символы, необходимые для отладки этой версии вашего приложения (при условии, что вы проиндексировали символы с помощью сервера символов перед отправкой).

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

Это гдеMicrosoft Source Server входит. Так же, как то, где индексы Symbol Serversymbols, исходный сервер будет индексироватьsource чтобы убедиться, что у вас есть соответствующая версия исходного кода, принадлежащая сборке программного обеспечения.

Рабочие версииVersion Control, Symbol Server а такжеSource Server должна быть частью вашей стратегии управления конфигурацией программного обеспечения.

Существуют сторонние инструменты, некоторые коммерческие, которые предоставят вам API для создания снимков приложений, но, как вы уже поняли, вам нужен механизм для загрузки этих снимков в вашу среду.

Джон Роббинс наФайлы PDB

Джон Роббинс наИсходный сервер

Проверять, выписыватьсяДокументация WinDbg при запуске и запуске Symbol Server.

Похожие вопросы