Ведение журнала и трассировка в приложениях .NET

Завершено

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

Трассировка — это способ следить за процессом выполнения приложения во время его работы. При разработке приложения .NET вы можете добавить инструменты для трассировки и отладки. Это инструментирование можно использовать во время разработки приложения и после его развертывания.

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

  • Проблемы, возникающие в течение длительного периода времени, могут оказаться трудными для отладки с помощью традиционного отладчика. Журналы позволяют проводить подробный анализ после события, охватывающий длительный период времени. Напротив, отладчики ограничены анализом в режиме реального времени.
  • Многопоточные приложения и распределенные приложения часто трудно отлаживать. Присоединение отладчика обычно изменяет поведение. Подробные журналы можно анализировать по мере необходимости, чтобы понять сложные системы.
  • Проблемы в распределенных приложениях могут возникать из сложного взаимодействия между многими компонентами. Возможно, не имеет смысла подключать отладчик к каждой части системы.
  • Многие службы не должны быть остановлены. Присоединение отладчика часто вызывает сбои тайм-аута.
  • Проблемы не всегда предвиделись. Ведение журнала и трассировка предназначены для низкой нагрузки, чтобы программы всегда могли записываться в случае возникновения проблемы.

Записываем информацию в окна вывода

До этого момента мы использовали консоль для отображения сведений пользователю приложения. Существуют другие типы приложений, созданных с помощью .NET, которые имеют пользовательские интерфейсы, такие как мобильные, веб-приложения и классические приложения, и нет видимой консоли. В этих приложениях System.Console логирует сообщения в фоновом режиме. Эти сообщения могут отображаться в окне вывода в Visual Studio или Visual Studio Code. Они также могут выводиться в системный журнал, такой как Android logcat. В результате при использовании System.Console.WriteLine в приложении, отличном от консольного, следует проявлять особую осторожность.

Здесь можно использовать System.Diagnostics.Debug и System.Diagnostics.Trace в дополнение к System.Console. Как Debug, так и Trace являются частью System.Diagnostics и будут записывать только в лог-файлы при присоединении соответствующего прослушивателя.

Выбор, какой API стиля печати использовать, остаётся за вами. Основные различия:

  • System.Console
    • Она всегда включена и всегда записывается в консоль.
    • Полезная информация о том, что клиенту может понадобиться увидеть в выпуске.
    • Так как это самый простой подход, он часто используется для временной отладки. Этот код отладки часто не помещается в систему управления версиями.
  • System.Diagnostics.Trace
    • Включен только тогда, когда определено TRACE.
    • По умолчанию записывает в подключенные прослушиватели, например, DefaultTraceListener.
    • Используйте этот API при создании журналов, которые будут включены в большинстве сборок.
  • System.Diagnostics.Debug
    • Включен только при определении DEBUG (в режиме отладки).
    • Записывает в подключенный отладчик.
    • Используйте этот API при создании журналов, которые будут включены только в отладочных сборках.
Console.WriteLine("This message is readable by the end user.");
Trace.WriteLine("This is a trace message when tracing the app.");
Debug.WriteLine("This is a debug message just for developers.");

При разработке стратегии трассировки и отладки думайте о том, как вы хотите выглядеть выходные данные. Несколько инструкций записи, заполненных несвязанными сведениями, создают лог, который трудно прочитать. С другой стороны, использование WriteLine для помещения связанных инструкций на отдельные строки может затруднить определение того, какая информация связана. Как правило, используйте несколько операторов Write, если требуется объединить информацию из нескольких источников, чтобы создать одно информативное сообщение. Используйте инструкцию WriteLine, если требуется создать одно полное сообщение.

Debug.Write("Debug - ");
Debug.WriteLine("This is a full line.");
Debug.WriteLine("This is another full line.");

Данные из предыдущего журналирования с Debug:

Debug - This is a full line.
This is another full line.

Определение констант TRACE и DEBUG

По умолчанию при отладке приложения определяется константа DEBUG. Это можно контролировать, добавив запись DefineConstants в файл проекта в группе свойств. Ниже приведен пример включения TRACE для конфигураций Debug и Release в дополнение к DEBUG для конфигураций Debug.

<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
    <DefineConstants>DEBUG;TRACE</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
    <DefineConstants>TRACE</DefineConstants>
</PropertyGroup>

При использовании Trace, когда он не присоединён к отладчику, нужно сконфигурировать прослушиватель трассировки, например, dotnet-trace.

Условная трассировка

Помимо простых Write и WriteLine методов, также есть возможность добавлять условия с WriteIf и WriteLineIf. Например, следующая логика проверяет, равен ли счетчик нулю, а затем записывает сообщение отладки:

if(count == 0)
{
    Debug.WriteLine("The count is 0 and this may cause an exception.");
}

Это можно переписать в одной строке кода:

Debug.WriteLineIf(count == 0, "The count is 0 and this may cause an exception.");

Эти условия также можно использовать с Trace и флагами, которые определены в приложении:

bool errorFlag = false;  
System.Diagnostics.Trace.WriteIf(errorFlag, "Error in AppendData procedure.");  
System.Diagnostics.Debug.WriteIf(errorFlag, "Transaction abandoned.");  
System.Diagnostics.Trace.Write("Invalid value for data request");

Убедитесь, что существуют определенные условия

Утверждение или оператор Assert проверяет условие, которое вы указали в качестве аргумента оператора Assert. Если условие оценивается как true, действие не выполняется. Если условие оценивается как false, утверждение не выполняется. Если вы работаете с отладочной сборкой, программа вводит режим останова.

Вы можете использовать метод Assert из Debug или Trace, которые находятся в пространстве имен System.Diagnostics. Debug методы классов не включаются в версию выпуска программы, поэтому они не увеличивают размер или снижают скорость кода выпуска.

Используйте метод System.Diagnostics.Debug.Assert без ограничений для проверки условий, которые должны быть истинными, если ваш код правильный. Например, предположим, что вы написали функцию с разделением целых чисел. По правилам математики делитель никогда не может быть нулевым. Это условие можно проверить с помощью утверждения:

int IntegerDivide(int dividend, int divisor)
{
    Debug.Assert(divisor != 0, $"{nameof(divisor)} is 0 and will cause an exception.");

    return dividend / divisor;
}

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

Заметка

При использовании System.Diagnostics.Debug.Assertубедитесь, что любой код внутри Assert не изменяет результаты программы при удалении Assert. В противном случае в результате ваших действий может возникнуть ошибка, которая проявляется только в финальной версии программы. Будьте особенно осторожны с утверждениями, содержащими вызовы функции или процедуры.

Использование Debug и Trace из пространства имен System.Diagnostics — отличный способ обеспечить дополнительный контекст при запуске и отладке приложения.