Programista często staje przed koniecznością wyboru sposobu śledzenia przebiegu aplikacji, czy logowaniu błędów. Niniejszy artykuł ma na celu przedstawienie sposobu w jaki można to zrobić w oparciu o platformę . NET. Dzięki wykorzystaniu opisanej tutaj metodologii końcowa aplikacja będzie w tym względzie w pełni konfigurowalna, co może zapewnić wygodę nie tylko programiście, ale również użytkownika końcowego.
Wiem, że na tym portalu znajdują się już inne artykuły poświęcone tej tematyce ( m.in
Wstęp
Programista często staje przed koniecznością wyboru sposobu śledzenia
przebiegu aplikacji, czy logowaniu błędów. Niniejszy artykuł ma na celu
przedstawienie sposobu w jaki można to zrobić w oparciu o platformę .
NET. Dzięki wykorzystaniu opisanej tutaj metodologii końcowa aplikacja
będzie w tym względzie w pełni konfigurowalna, co może zapewnić wygodę
nie tylko programiście, ale również użytkownika końcowego.
Wiem, że na tym portalu znajdują się już inne artykuły poświęcone tej tematyce ( m.in. "
Tracing aplikacji. ", "
Tracing aplikacji. Metody zaawansowane. ").
Wydaje mi się jednak, że mój artykuł pozwoli na trochę inne spojrzenie
i pokaże elastyczność opisywanego zagadnienia. Chciałbym również
wskazać możliwości jakie niesie odseparowanie konfiguracji od
wkompilowanych w kod ustawień logowania.
Zachęcam
wszystkich do lektury:
- Trochę teorii
- Tracing w praktyce
- Przykładowa aplikacja (Logger Sample)
- Podsumowanie
Trochę teorii
Tworząc jakąś aplikację bardzo często stajemy przed koniecznością
śledzenia zdarzeń jakie w niej występują. Szczególnie istotne jest to w
aplikacjach, które wykonują zadania trwające dłuższą chwilę czasu. Do
aplikacji tego typu zaliczyć można:
- programy przetwarzające dane (np. wykonujące skomplikowane obliczenia, kodujące materiał wideo, itp...)
- programy oferujące usługi jak serwer (np. serwer www, ftp, opc lub inny...)
- inne aplikacje, których przebiegiem jesteśmy zainteresowani
Należy pamiętać, że nie zawsze chcemy, a często nawet nie
jest to możliwe, by informować użytkownika bezpośrednio przy pomocy
okna dialogowego.
Zastanówmy się więc jakie są inne możliwości? Najczęściej w takich
przypadkach wykorzystywane jest jedno z dwóch poniższych rozwiązań:
- prywatny plik logu,
- użycie rejestru zdarzeń wbudowanego w systemu operacyjny.
Która
z tych metod jest lepsza? Chyba trudno jednoznaczną odpowiedź, każde z
tych wspomnianych wyżej rozwiązań ma swoje wady i zalety. Pocieszający
jest fakt, że programując w oparciu o platformę .NET Framework nie
trzeba wcale decydować o tym, którą drogę wybrać. Wystarczy tylko
wybrać metodologię opartą o tzw. tracing, a dzięki temu decyzję o tym
gdzie mają nasze logi trafić będzie można zostawić użytkownikowi
końcowemu.
Jak to działa? Mechanizm ten wykorzystuje klasy takie jak:
Dodatkowo można jeszcze wskazywać poziomy zdarzeń (przecież nie
wszystkie zdarzenia są tak samo ważne). Platforma .Net Tracing
przewiduje następujące typy zdarzeń (opisane w enumeracji
TraceLevel):
- Off - logowanie jest wyłączone
- Error - logowane są tylko zdarzenia mające charakter błędów
- Warning - logowane są zdarzenia, które są ostrzeżeniami
- Info - w logu będą się pojawiały informacje
- Verbose - logowane mogą być wszystkie zdarzenia, bez względu na charakter.
Co
ciekawe, to użytkownik obsługujący program może wybrać jakiego
rodzajami zdarzeń jest zainteresowany, wystarczy tylko zmodyfikować
plik konfiguracyjny aplikacji (z rozszerzeniem ".config"), nie potrzeba
wykonywać rekompilacji kodu aplikacji. Dodatkowo użytkownik może
wybierać źródła, dla których zdarzeniami jest zainteresowany, twórca
aplikacji musi jedynie poinformować użytkownika jakie źródła są
dostępne, a później wystarczy już tylko zmiana ustawień w pliku
konfiguracyjnym (.config) i zdarzenia są otrzymywane z innego źródła.
Co więcej użytkownik może zdarzenia z różnych źródeł kierować do
różnych Listener'ów, a dla każdego z nich ustawiać inny poziom
logowania.
Tracing w praktyce
Pierwszą czynnością, którą należy wykonać to wybrać
klasę w naszej aplikacji, która będzie generowała zdarzenia. W tej
klasie powinniśmy utworzyć obiekt TraceSource:
[Kod C#]
privateTraceSource m_tracesource;
...
m_tracesource= new TraceSource("sourcename"); |
Ważna jest nazwa źródła (w powyższym przykładzie:
sourcename),
która jest przekazywana do konstruktora obiektu TraceSource. Ta nazwa
będzie wykorzystywana później w pliku konfiguracyjnym aplikacji, a by
zlokalizować źródło z którego zdarzeniami jesteśmy zainteresowani.
Kolejnym krokiem jest użycie funkcji TraceEvent, w każdym miejscu
programu, gdzie występuje jakieś interesujące zdarzenie. Przykład
takiego wykorzystania znajduje się poniżej:
[Kod C#] m_tracesource.TraceEvent(type, id, message);
|
Tutaj warte komentarza są następujące sprawy:
- type - to typ zdarzenia (według enumeracji TraceEventType), omówiony w poprzedniej części artykułu.
- id - to numeryczny identyfikator przypisany przez programistę aplikacji (czyli przez nas) do tego z darzenia
- message - wiadomość, którą chcemy przekazać użytkownikowi
Teraz
przed nami najciekawszy moment, konfiguracja logowania w pliku
konfiguracyjnym aplikacji. Wszystkie wpisy odnośnie ustawień logowania
lub śledzenia zdarzeń opartego o mechanizm, który tutaj opisuję powinny
się znaleźć w pliku konfiguracyjnym wewnątrz tagu "system.diagnostic":
[Kod XML] <system.diagnostics><!-- ... other definitions place here... --> </system.diagnostics>
|
Wewnątrz tagu "system.diagnostic" powinny się znaleźć następujące elementy:
- sources - czyli
ustawienia odnośnie źródeł, z których zdarzeniami jesteśmy
zainteresowani i dla których definiujemy "listeners", czyli do jakiego
listenera mają trafiać informacje z tego źródła
- switches -
tutaj definiujemy jakim poziomem logowania jesteśmy zainteresowaniu z
danego źródła (czy mają to być błędy (errors), ostrzeżenia (warnings),
itp...), informacje na temat konfiguracji switch'y można znaleźć w MDSN'nie.
- sharedListeners -
tuaj umieszczamy definicje listener'ów, które zamieżamy wykorzystywać.
Oprócz nazw i typu danego listener'a konfiugurujemy też inne elementy
charakterystyczne dla danego typu Listener'a, np.: nazwę pliku, do
którego mają trafić informacje o zdarzeniach.
Przykładowa definicja źródła (source) została pokazana poniżej:
[Kod XML]
<sources> <source name="MySource1" switchName="MySource" switchType="System.Diagnostics.SourceSwitch" /> <listeners> <add name="LogFile"/> <add name="myEventLogTraceListener"/> </listeners> </source></sources>
|
W tym przykładzie dodano źródło "
MySource1",
z którego chcemy odczytywać zdarzenia. Oczywiście takie źródło musi być
wykorzystane w aplikacji, abyśmy jakiekolwiek zdarzenia otrzymali. Dla
tego źródła ustawiono, że switch o nazwie "
MySource" ustawi poziom logowania. Dodatkowo do źródła został dodany szereg listenerów, do których będą trafiały zdarzenia.
Przykładowa definicja (wykorzystanego wcześniej) switch'a znajduje się tutaj:
[Kod C#]
<switches> <add name="MySource" value="All" /> </switches>
|
W tym przypadku zdefiniowany switch ustawił poziom logowania na: "
All", czyli interesują nas wszystkie zdarzenia.
Kolejnym krokiem jest skonfigurowanie wykorzystanych Listener'ów, czyli sekcja sharedListeners:
[Kod C#]
<sharedListeners> <add name="myEventLogTraceListener" type="System.Diagnostics.EventLogTraceListener" initializeData="TraceListenerLog"
/> <add name="LogFile" type="System.Diagnostics.DelimitedListTraceListener"initializeData="Application_Main.log"traceOutputOptions="DateTime"> <filter type="System.Diagnostics.EventTypeFilter" initializeData="Warning" /> </add> </sharedListeners>
|
Tutaj zostały skonfigurowane dwa listenery:
- myEventLogTraceListener, który wykorzystuje klasę EventLogTraceListner,
z której zdarzenia będą trafiać do logu aplikacji systemu Windows, a
źródłem zdarzenia (wpisanym do logu) będzie TraceListenerLog
- LogFile, wykorzystujący DelimitedListTraceListener, który zdarzenia będzie wpisywał do pliku o nazwie "Application_Main.log",
wpisy będą oddzielane średnikami i będą zawierały datę i czas
zdarzenia. Dodatkowo dla tego Listener'a ustawiony został filtr, który
będzie powodował, że trafiające tutaj zdarzenia, będą przynajmniej
ostrzeżeniami (warnings).
Przykładowa aplikacje (Logger Sample)
Logger
Sample jest prostą aplikacją, która generuje zdarzenia z dwóch źródeł.
Zdarzenia są zapisywane do pliku, logu systemowego i na konsole (jest
to wszystko skonfigurowane w pliku konfiguracyjnym). Główne okno
programu jest bardzo proste, a naciskając przyciski można generować
zdarzenia dla wybranego źródła.
Zachęcam do prześledzenia pliku konfiguracyjnego, by zobaczyć jak łatwo można to konfigurować.
Podsumowanie
Oczywiście to nie wszystko
co można w ten sposób osiągnąć. Interesująca wydaje się zwłaszcza
możliwość implementacji własnego Trace Listener'a. Dzięki temu mamy
większą swobodę w wyborze miejsca do którego będą trafiały nasze logi.
Nie musi być to plik w dziwnym formacie (choć może), czy inne poza
standardowym wykorzystanie rejestru zdarzeń systemu Windows. Możemy iść
tutaj znacznie dalej np.:
- zapisywanie zdarzeń do bazy danych, umożliwiając użytkownikowi wpisanie dowolnego connection-string'a,
- wysyłanie
zdarzeń poprzez WebService do zdalnego rejestru (chyba bardzo dobre
rozwiązanie dla aplikacji, by wykorzystać połączenie sieciowe do
przesłania informacji o problemach do zdalnego serwera należącego do
autorów oprogramowania),
- wysyłanie informacji bezpośrednio w pakietach TCP lub UDP (przykłady można znaleźć w wortalu CodeProject: TraceTool, UDP Trace Listener),
- tworzenie serii plików z logami (np. log z każdego dnia może być w oddzielnym pliku)
- i wiele innych - w zależności od naszej wyobraźni.
Co
trzeba zrobić, aby wykorzystać własny Listener?? Oczywiście stworzyć
klasę dziedziczącą, po TraceListener, a następnie zaimplementować
konieczne funkcje (m.in. Write, TraceEvent i inne...). Teraz wystarczy
już użyć stworzony Listener w naszym programie (np. w pliku
konfiguracyjnym).
W tym miejscu dotarliśmy już do końca tego artykułu. Mam
nadzieję, że udało mi się przybliżyć możliwości śledzenia i logowania
zdarzeń na platformie .NET. Być może w kolejnym artykule dotyczącym tej
tematyki rozszerzę zagadnienie konstruowania własnego TraceListener'a.
Zachęcam do odwiedzenia mojego bloga: http://maciej-progtech.blogspot.com - znajdują tam się inne interesujące artykuły i materiały.
Historia
- 2009.01.27 - Pierwsza wersja artykułu opublikowana w częściach na moim blogu.
- 2009.03.17 - Kolejna wersja artykułu przygotowana na portal CodeGuru.pl
Załączniki: