sobota, 8 listopada 2008

Inspektor Gadget, czyli śledzenie aplikacji cz. II

log4net wchodzi na scenę

Podstawowymi klasami biblioteki log4net z jakimi będzie pracował programista są: LogManager oraz Log. LogManager pełni funkcję kontentera i zarządcy nad Loggerami. Cały system może składać się z hierarchii Loggerów – klas dostarczających metod do logowania. Aby otrzymać konkretną nazwaną instancję klasy Logger posługujemy się statycznymi metodami GetLogger obiektu LoggerManager.



Żądania logowania wykonywane są przez wykonanie określonej metody w zależności od typu zaistniałego zdarzenia, czyli: DEBUG, INFO, WARN, ERROR, FATAL
Zdarzenie zostanie zalogowane przez dany Logger jeśli ma taki sam lub wyższy priorytet. Z kolei każdy Logger może posiadać filtr w którym określono na zdarzenia jakiego typu (priorytetu) ma reagować. Jeśli do danego Loggera nadejdzie żądanie zalogowania zdarzenia niższego niż jest przez niego obsługiwane, to nie zostanie ono zalogowane. Warto zauważyć także, że każdy typ logów może mieć określony sposób formatowania, jest to szczególnie istotne zwłaszcza jeśli część z nich wysyłamy np. mailem w formacie HTML, a część logujemy w bazie w postaci czystego tekstu.

Konfiguracja log4net
Żaden system bez odpowiedniej konfiguracji nie może działać poprawnie. Na szczęście log4net dostarcza szeroki wachlarz możliwości konfiguracji zarówno przez pliki XML jak i programowo. Po pierwsze musimy pobrać log4net z witryny http://logging.apache.org/log4net/download.html i dodać referencję do jego głównej biblioteki log4net.dll. W niniejszym przykładzie będę posługiwał się wersją 1.2.10. Sam log4net nie wymaga wielkiego nakładu na jego konfigurację aby zaczął działać w swojej podstawowej formie. W zasadzie można powiedzieć, że domyślne ustawienia środowiska są wystarczające, aby zacząć przygodę z log4net i sprawdzić, czy w ogóle jest to warte zachodu :-)

using System;
using System.Collections.Generic;

using log4net;
using log4net.Config;

namespace ConsoleApplication1
{
class Program
{
private static readonly ILog MyLogger = LogManager.GetLogger(typeof(Program));

static void Main(string[] args)
{
BasicConfigurator.Configure(); //konfiguracja podstawowa, bez pliku xml
MyLogger.Info("Aplikacja została uruchomiona");

}
}
}



Aby zmusić log4net do pobrania swojej konfiguracji z pliku konfiguracyjnego aplikacji, programista musi jedynie stworzyć odpowiednie wpisy konfiguracyjne oraz wymusić załadowania nastawów z pliku. Spróbujmy dodać plik App.config i wypełnić go podobnie jak na schemacie poniżej.

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />
</configSections>
<log4net>
<appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender" >
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %-5level %logger [%ndc] - %message%newline" />
</layout>
</appender>
<root>
<level value="INFO" />
<appender-ref ref="ConsoleAppender" />
</root>
</log4net>
</configuration>



Teraz wystarczy jedynie załadować konfigurację wywołując metodę XmlConfigurator.Configure();

Logujemy!

Stwórzmy prostą aplikację, która swoją konfigurację do logowania pobierze z pliku konfiguracyjnego aplikacji, a logi typu INFO oraz DEBUG umieszcza na konsoli. Pierwsze co musimy zrobić do dodać odpowiedni plik App.config. Ze względu na to, że w naszym systemie chcemy logować dwa typy zdarzeń: informacyjne (INFO) oraz debugowe (DEBUG) musimy stworzyć wpis appender, czyli naszego wyjścia. Wewnątrz wpisu appendera należy podać sposób formatowania pojedynczego wpisu logu.

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />
</configSections>
<log4net>
<appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender" >
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %-5level %logger [%ndc] - %message%newline" />
</layout>
</appender>
<root>
<level value="DEBUG" />
<appender-ref ref="ConsoleAppender" />
</root>
</log4net>
</configuration>



Dostępne w log4net wyjścia dla naszych logów to:
• AdoNetAppender,
• MS SQL Server,
• MS Access,
• Oracle9i,
• Oracle8i,
• IBM DB2,
• SQLite,
• AspNetTraceAppender,
• BufferingForwardingAppender,
• ColoredConsoleAppender,
• ConsoleAppender,
• EventLogAppender,
• FileAppender,
• ForwardingAppender,
• MemoryAppender,
• NetSendAppender,
• OutputDebugStringAppender,
• RemotingAppender,
• RollingFileAppender,
• SmtpAppender,
• SmtpPickupDirAppender,
• TraceAppender,
• UdpAppender

Uważny czytelnik zauważył pewnie, że nie zdefiniowaliśmy celu naszych logów dla zdarzeń INFO. Tak jak wspominałem wcześniej zdarzenia mają określoną hierarchię i w przypadku wystąpienia zdarzenia o priorytecie >= zdefiniowanemu zostanie on na pewno obsłużony, a o niższym priorytecie - nie.
Wpis o priorytecie INFO jest nad wpisem DEBUG więc wyląduje na naszej konsoli. Podobnie stanie się z wpisami o priorytetach ERROR i FATAL - te akurat zdarzenia powinny być umieszczane w blokach try-catch i automatycznie gromadzić wyjątki np. w bazie danych. Po dokładną specyfikację priorytetów odsyłam do oficjalnej strony projektu log4net .
W systemie może istnieć tyko jeden logger główny: root, reszta logerów dziedziczą po nim tworząc swoiste drzewo dziedziczenia.

namespace ConsoleApplication1
{
class Program
{
private static readonly ILog MyLogger = LogManager.GetLogger(typeof(Program));

static void Main(string[] args)
{
XmlConfigurator.Configure();
MyLogger.Info("Aplikacja została uruchomiona");
If (args != null)
MyLogger.Debug(string.Format("Argumenty uruchomieniowe: {0}", args));
MyLogger.Info("Aplikacja została zakończona");
}
}
}



Efekt powinien być podobny do tego:



W ten oto sposób poprawnie skonfigurowaliśmy oraz zalogowaliśmy pierwsze zdarzenia za pomocą biblioteki log4net! Chyba nie było to trudne?

Do pobrania:

0 komentarze: