BETA
Aby się zalogować, najpiew wybierz portal.
Aby się zarejestrować, najpiew wybierz portal.
Podaj słowa kluczowe
Słowa kluczowe muszą mieć co najmniej 3 sąsiadujące znaki alfanumeryczne
Pole zawiera niedozwolone znaki

Baza wiedzy











Śledzenie i logowanie zdarzeń (tracing and logging) na platformie .NET.

18-03-2009 09:30 | Maciej Zbrzezny
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:

Podobne artykuły

Komentarze 5

spocco
spocco
0 pkt.
Nowicjusz
21-01-2010
oceń pozytywnie 0
    bo by się przydał.
ignavus
ignavus
49 pkt.
Poczatkujacy
21-01-2010
oceń pozytywnie 0
Za zgodą autora publikacja została przeniesiona na miesiąc konkursowy.
User 114134
User 114134
2 pkt.
Nowicjusz
21-01-2010
oceń pozytywnie 0
z początku uznałem artykuł bardziej za ciekawostkę zoologiczną niż faktycznie przydatną informację, a w tej chwili mam do zrobienia taką właśnie kontrolke na strone i przyznam szczerze, że artykuł ogromnie mi pomógł. Wielkie dzięki ;)
wariatus
wariatus
0 pkt.
Nowicjusz
21-01-2010
oceń pozytywnie 0
Świętny i tak dalej, tylko jedno małe sprostowanie (a raczej 2 w 1 ;))

Twórcom .NET na tyle zależy na innych platformach, że w ostatnim czasie firma Novell otrzymała bardzo dużą kwotę w zamian za dostęp MS do platformy Mono. Czyli opisana technika już wkrótce może stać się "dostępna" także na alternatywnych systemach operacyjnych. Oczywiście nadal problemem będzie obsługa techniki przez przeglądarkę... ale może MS w końcu zrobi IE dla Linuxa ;)
Xazis
Xazis
3 pkt.
Nowicjusz
02-02-2010
oceń pozytywnie 0

dosc jasno opisane i dotyczy dokladnie tego czego bylo mi trzeba :) dzieki

pkt.

Zaloguj się lub Zarejestruj się aby wykonać tę czynność.