Logi z NLog

Jest wiele sposobów na znajdowanie błędów w aplikacji: dowody matematyczne, testy jednostkowe, ręczne testowanie i debugowanie. Niestety debugowanie może być bardzo czasochłonne jeśli nie wiemy, w którym miejscu znajduje się problem. Tworzenie logów może nam pomóc zlokalizować ten problem.

Istnieje kilka .NETowych frameworków do logowania, m.in. log4net, WisdomCloud.Log i NLog, który postanowiłem użyć w moim projekcie. Można go pobrać z NuGet:NLog.

Pierwsza rzecz jaką należy zrobić po zainstalowaniu paczki to utworzenie pliku konfiguracyjnego. Jego szablon jest dostępny z drugiej paczki NuGet:NLog.Config.

Otrzymujemy plik ,,NLog.config” w XMLu. Mój wygląda tak:

<?xml version="1.0" encoding="utf-8" ?>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
	  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	  xsi:schemaLocation="http://www.nlog-project.org/schemas/NLog.xsd NLog.xsd"
	  autoReload="true"
	  throwExceptions="false" >
  <targets>
	<target xsi:type="File" name="logfile" fileName="SharpOffice.log" lineEnding="CRLF"
			layout="[${date:format=yyyy-MM-dd HH\:mm\:ss}] ${uppercase:${level}} - (${logger})  ${message}"
			footer="----------"/>
  </targets>
  <rules>
	<logger name="*" minlevel="Info" writeTo="logfile" />
	<!-- Comment below on production -->
	<logger name="*" minlevel="Trace" maxlevel="Debug" writeTo="logfile" />
  </rules>
</nlog>

Wewnątrz <targets> określamy cel naszych logów. Może to być plik, konsola, eventlog, mail, NLogViewer i wiele innych. Za pomocą atrybutu layout określamy jak ma wyglądać nasza wiadomość. Moje ustawienie produkuje coś takiego:

[2016-05-16 12:32:04] DEBUG - (Container)  Starting container initialization...

Dalej definiujemy zasady, czyli w jakim przypadku generować logi. name="*" oznacza wszystkich loggerów, ale można określić jednego konkretnego lub grupę mającą ten sam prefix. [min|max]level określa jaki poziom wiadomości akceptować. W kolejności rosnącej są to:

  • Trace
  • Debug
  • Info
  • Warn
  • Error
  • Fatal

Na koniec writeTo określa target do którego mamy pisać.

Logi w kodzie

Aby tworzyć logi wystarczy dodać prywatne statyczne pole typu NLog.Logger do naszej klasy, a następnie poprosić NLog.LogManager o Logger o żądanej nazwie. Np. mój ContainerWrapper posiada taki Logger:

private static readonly Logger Logger = LogManager.GetLogger("Container");

A następnie w kodzie aby wypisać jakąś wiadomość do logu, używamy jednej z metod o nazwie takiej jako poziom:

Logger.Debug("Starting container initialization...");

Dodatkowo możemy przekazywać parametry w formacie String.Format, które nie będą przerabiane na string jeśli nie będzie potrzeby użycia (wynikającego z reguł).

Logger.Warn("DLL file \"{0}\" is not a .NET assembly.", assemblyFile);

W sumie logowanie jest proste, ale też nie można przesadzić z ilością logów, bo kod stanie się nieczytelny.

Mój przykładowy output

Jeszcze nie wprowadziłem logowania do każdej klasy gdzie chciałbym je mieć, ale kilka podstawowych daje ładny efekt:

[2016-05-16 13:17:00] DEBUG - (Container)  Starting container initialization...
[2016-05-16 13:17:00] DEBUG - (Container)  Registering types from "ApplicationRegistrationModule"
[2016-05-16 13:17:00] DEBUG - (Container)  Registering types from "ConfigurationProviderRegistrationModule"
[2016-05-16 13:17:00] DEBUG - (Container)  Registering types from "ConfigurationsRegistrationModule"
[2016-05-16 13:17:00] DEBUG - (Container)  Registering types from "MenuComposerRegistrationModule"
[2016-05-16 13:17:00] DEBUG - (Container)  Registering types from "MenuProviderRegistrationModule"
[2016-05-16 13:17:00] DEBUG - (Container)  Finished container initialization.
[2016-05-16 13:17:01] DEBUG - (Runtime.Eto.Main)  Creating MainWindow...
[2016-05-16 13:17:01] DEBUG - (Runtime.Eto.MenuBuilder)  Composing menu...
[2016-05-16 13:17:01] DEBUG - (Runtime.Eto.MenuBuilder)  Building menu...
[2016-05-16 13:17:01] DEBUG - (Runtime.Eto.Main)  Starting application...
[2016-05-16 13:17:03] DEBUG - (Runtime.Eto.Main)  Stopping application...
[2016-05-16 13:17:03] DEBUG - (Container)  Disposing the container...

Jeśli chcesz dostawać powiadomienia na maila kiedy dodaję nowy post, możesz zasubskrybować mój blog wypełniając formularz poniżej.