Ведение журнала и трассировка в приложениях .NET
По мере разработки приложение становится все более сложным, и вам нужно будет применять к нему дополнительные диагностические средства отладки.
Трассировка — это способ отслеживать выполнение приложения во время его работы. Вы можете добавить инструментирование трассировки и отладки в приложение .NET при его разработке. Это инструментирование можно использовать во время разработки приложения и после его развертывания.
Этот простой прием является удивительно эффективным. Его можно использовать, когда одного отладчика недостаточно, как описано ниже.
- Проблемы, возникающие в течение длительных периодов времени, может быть трудно отлаживать с помощью традиционного отладчика. Журналы позволяют детализировать проверку после смерти, которая охватывает длительные периоды времени. В отладчиках, напротив, доступен лишь анализ в режиме реального времени.
- Многопоточные приложения и распределенные приложения часто трудно отлаживать. Присоединение отладчика часто изменяет поведение приложения. Подробные журналы можно анализировать по мере необходимости, чтобы понять сложные системы.
- Проблемы в распределенных приложениях могут возникать из-за сложного взаимодействия между многими компонентами. Нецелесообразно подключать отладчик к каждой части системы.
- Многие службы нельзя останавливать. Присоединение отладчика часто приводит к превышению времени ожидания.
- Проблемы не всегда удается прогнозировать. Ведение журнала и трассировка создают очень низкую нагрузку, поэтому программы будут сохранять данные даже при возникновении проблемы.
Запись данных в окна вывода
До этого момента мы использовали только консоль для вывода сведений пользователю приложения. На основе .NET можно создать и другие приложения с пользовательскими интерфейсами, например мобильные приложения, веб-приложения и классические приложения, в которых нет видимой консоли. В таких приложениях сообщения выводятся с помощью System.Console
в фоновом режиме. Эти сообщения могут отображаться в окне вывода Visual Studio или Visual Studio Code. Их также можно направить в системный журнал, например logcat
в Android. В результате при использовании 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.");
При проектировании стратегии трассировки и отладки подумайте о том, как должны выглядеть выходные данные. При наличии нескольких операторов Write, заполненных несвязанными данными, получается сложный для чтения журнал. С другой стороны, при использовании метода 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
. Если условие выполняется, никаких действий не производится. Если же условие не выполняется, то утверждение выдает ошибку. Если вы работаете с отладочной сборкой, программа переходит в режим прерывания.
Метод 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
не изменял результаты программы в случае его удаления. В противном случае вы можете случайно допустить ошибку, которая проявится только в версии выпуска программы. Будьте особенно осторожны с операторами утверждения, которые содержат вызовы функций или процедур.
Как видите, использование Debug
и Trace
из пространства имен System.Diagnostics
отлично подходит для предоставления дополнительного контекста при выполнении и отладке приложения.