Rejestrowanie i śledzenie w aplikacjach .NET
W miarę dalszego opracowywania aplikacji i coraz bardziej złożonej aplikacji należy zastosować dodatkową diagnostykę debugowania do aplikacji.
Śledzenie to sposób monitorowania wykonywania aplikacji podczas jej działania. Instrumentację śledzenia i debugowania można dodać do aplikacji platformy .NET podczas jej opracowywania. Możesz użyć tej instrumentacji podczas tworzenia aplikacji i po jej wdrożeniu.
Ta prosta technika jest zaskakująco potężna. Można go używać w sytuacjach, w których potrzebujesz więcej niż debuger:
- Problemy występujące w długich okresach czasu mogą być trudne do debugowania przy użyciu tradycyjnego debugera. Dzienniki umożliwiają szczegółowy przegląd pośmiertny, który obejmuje długie okresy czasu. Natomiast debugery są ograniczone do analizy w czasie rzeczywistym.
- Aplikacje wielowątkowa i aplikacje rozproszone są często trudne do debugowania. Dołączanie debugera ma tendencję do modyfikowania zachowań. Szczegółowe dzienniki można analizować zgodnie z potrzebami, aby zrozumieć złożone systemy.
- Problemy w aplikacjach rozproszonych mogą wynikać ze złożonej interakcji między wieloma składnikami. Połączenie debugera z każdą częścią systemu może nie być uzasadnione.
- Wiele usług nie powinno być wstrzymanych. Dołączanie debugera często powoduje błędy przekroczenia limitu czasu.
- Problemy nie zawsze są przewidywane. Rejestrowanie i śledzenie są przeznaczone dla małych obciążeń, dzięki czemu programy zawsze mogą być rejestrowane w przypadku wystąpienia problemu.
Zapisywanie informacji w oknach wyjściowych
Do tego momentu używaliśmy konsoli do wyświetlania informacji użytkownikowi aplikacji. Istnieją inne typy aplikacji utworzonych za pomocą platformy .NET, które mają interfejsy użytkownika, takie jak aplikacje mobilne, internetowe i klasyczne, i nie ma widocznej konsoli. W tych aplikacjach System.Console
rejestruje komunikaty "za kulisami". Te komunikaty mogą być wyświetlane w oknie danych wyjściowych w programie Visual Studio lub Visual Studio Code. Mogą one również być danymi wyjściowymi dziennika systemu, takiego jak system Android logcat
. W związku z tym należy wziąć pod uwagę bardzo dużą uwagę podczas korzystania z System.Console.WriteLine
aplikacji innej niż konsola.
Jest to miejsce, w którym można używać funkcji System.Diagnostics.Debug
i System.Diagnostics.Trace
oprócz System.Console
programu . ZarównoDebug
, jak i są częścią System.Diagnostics
i Trace
będą zapisywane tylko w dziennikach, gdy jest dołączony odpowiedni odbiornik.
Wybór, którego interfejsu API stylu drukowania ma być używany, jest dla Ciebie. Najważniejsze różnice to:
- System.console
- Zawsze włączone i zawsze zapisuje dane w konsoli programu .
- Przydatne w przypadku informacji, które klient może potrzebować w wydaniu.
- Ponieważ jest to najprostsze podejście, często jest używane do tymczasowego debugowania ad hoc. Ten kod debugowania często nigdy nie jest zaewidencjonowany do kontroli źródła.
- System.Diagnostics.Trace
- Włączono tylko wtedy, gdy
TRACE
jest zdefiniowana. - Zapisuje do dołączonych odbiorników, domyślnie, DefaultTraceListener.
- Użyj tego interfejsu API podczas tworzenia dzienników, które będą włączone w większości kompilacji.
- Włączono tylko wtedy, gdy
- System.Diagnostics.Debug
- Włączone tylko wtedy, gdy
DEBUG
jest zdefiniowane (w trybie debugowania). - Zapisuje w dołączonym debugerze.
- Użyj tego interfejsu API podczas tworzenia dzienników, które będą włączone tylko w kompilacjach debugowania.
- Włączone tylko wtedy, gdy
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.");
Podczas projektowania strategii śledzenia i debugowania zastanów się, jak mają wyglądać dane wyjściowe. Wiele instrukcji Write wypełnionych niepowiązanymi informacjami tworzy dziennik, który jest trudny do odczytania. Z drugiej strony użycie funkcji WriteLine do umieszczania powiązanych instrukcji w osobnych wierszach może utrudnić odróżnienie informacji, do których informacji należy. Ogólnie rzecz biorąc, użyj wielu instrukcji Write, jeśli chcesz połączyć informacje z wielu źródeł, aby utworzyć pojedynczy komunikat informacyjny. Użyj instrukcji WriteLine, jeśli chcesz utworzyć pojedynczy pełny komunikat.
Debug.Write("Debug - ");
Debug.WriteLine("This is a full line.");
Debug.WriteLine("This is another full line.");
Te dane wyjściowe pochodzą z poprzedniego rejestrowania za pomocą Debug
polecenia :
Debug - This is a full line.
This is another full line.
Definiowanie stałych TRACE i DEBUG
Domyślnie, gdy aplikacja jest uruchomiona w ramach debugowania, stała jest zdefiniowana DEBUG
. Możesz to kontrolować, dodając DefineConstants
wpis w pliku projektu w grupie właściwości. Oto przykład włączania TRACE
obu Debug
konfiguracji i Release
oprócz DEBUG
Debug
konfiguracji.
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<DefineConstants>DEBUG;TRACE</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<DefineConstants>TRACE</DefineConstants>
</PropertyGroup>
Jeśli nie Trace
dołączono do debugera, należy skonfigurować odbiornik śledzenia, taki jak dotnet-trace.
Śledzenie warunkowe
Oprócz prostych Write
i WriteLine
metod istnieje również możliwość dodawania warunków za pomocą WriteIf
metod i WriteLineIf
. Na przykład poniższa logika sprawdza, czy liczba jest równa zero, a następnie zapisuje komunikat debugowania:
if(count == 0)
{
Debug.WriteLine("The count is 0 and this may cause an exception.");
}
Można to napisać ponownie w jednym wierszu kodu:
Debug.WriteLineIf(count == 0, "The count is 0 and this may cause an exception.");
Możesz również użyć tych warunków z flagami Trace
zdefiniowanymi w aplikacji i z flagami:
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");
Sprawdź, czy istnieją pewne warunki
Asercji lub Assert
instrukcji testuje warunek określony jako argument instrukcji Assert
. Jeśli warunek zwróci wartość true
, nie wystąpi żadna akcja. Jeśli warunek zwróci wartość false
, asercji zakończy się niepowodzeniem. Jeśli używasz kompilacji debugowania, program przechodzi w tryb przerwania.
Możesz użyć Assert
metody z Debug
adresu lub Trace
, które znajdują się w System.Diagnostics
przestrzeni nazw. Debug
Metody klas nie są uwzględniane w wersji wydania programu, więc nie zwiększają rozmiaru ani nie zmniejszają szybkości kodu wydania.
System.Diagnostics.Debug.Assert
Użyj metody bezpłatnie, aby przetestować warunki, które powinny zawierać wartość true, jeśli kod jest poprawny. Załóżmy na przykład, że utworzono funkcję dzielenia liczb całkowitych. Zgodnie z zasadami matematyki podział nigdy nie może być zerowy. Ten warunek można przetestować przy użyciu asercji:
int IntegerDivide(int dividend, int divisor)
{
Debug.Assert(divisor != 0, $"{nameof(divisor)} is 0 and will cause an exception.");
return dividend / divisor;
}
Po uruchomieniu tego kodu w debugerze zostanie obliczona instrukcja asercji. Jednak porównanie nie jest wykonywane w wersji wydania, więc nie ma dodatkowych obciążeń.
Uwaga
Jeśli używasz metody System.Diagnostics.Debug.Assert
, upewnij się, że żaden kod wewnątrz Assert
programu nie zmienia wyników programu, jeśli asercja zostanie usunięta. W przeciwnym razie możesz przypadkowo wprowadzić usterkę, która jest wyświetlana tylko w wersji programu. Należy zachować szczególną ostrożność w przypadku asertów zawierających wywołania funkcji lub procedury.
Użycie Debug
elementów i Trace
z System.Diagnostics
przestrzeni nazw to doskonały sposób zapewnienia dodatkowego kontekstu podczas uruchamiania i debugowania aplikacji.