Typowa scenka gdzieś na mieście. Stoi dwóch policjantów w bramie i coś tam bazgrze w notatnikach. Co oni robią? Oczywiście notują informacje, które są istotne z ich punktu widzenia dla przebiegu patrolu. Inaczej mówiąc, logują informacje istotne z punktu widzenia biznesu. I właśnie o logowaniu dziś będzie.

Rodzaje logowania

Z punktu widzenia architekta możemy wydzielić trzy rodzaje logów. Każdy z nich odpowiedzialny jest za inny aspekt działania aplikacji, ale jeden zapis do logu może być istotny dla wielu aspektów.

Logi biznesowe

W tej grupie mamy zebrane logowanie wszystkich informacji istotnych z punktu widzenia biznesu. Mogą to byś zarówno informacje na potrzeby audytu – kto, gdzie, kiedy podjął daną akcję, przebieg procesu biznesowego, jak i informacje na potrzeby analizy pod kątem rynku np. systemu rekomendacji. W tej kategorii istotne jest określenie wspólnie z biznesem co i kiedy należy logować.

Ten log może, choć nie musi, być obiektem domenowym. Tak! Obiektem domenowym, ponieważ ma znaczenie biznesowe. Dlatego też należy przyznać temu logowi odpowiedni status i uwzględnić go na poszczególnych etapach projektowania. Ciekawym doświadczeniem może być pociśnięcie ekspertów domenowych w czasie stormingu, by określili się, co warto zapisać. Jest tu jednak zaszyta pewnego rodzaju pułapka projektowa. W wielu organizacjach, w których IT jest narzędziem, a nie istotą biznesu, istnieje silne przywiązanie do bazy danych jako miejsca składowania informacji istotnych dla biznesu. Bardzo ciężko jest w takim przypadku wytłumaczyć, że np. plik tekstowy, albo baza dokumentowa są wystarczającym rozwiązaniem.

Logi operacyjne

Logi operacyjne są najważniejsze z punktu widzenia programistów. Pozwalają na analizę stanu aplikacji, przyczyn awarii, dostarczają danych dla narzędzi monitorujących. Najczęściej logi te są wykorzystywane na etapie testów manualnych, kiedy testerzy wykorzystują je jako załączniki do zgłoszeń. Tu będą wszystkie zrzuty stacktrace, parametry wywołania metod czy czasy ich wykonania.

Oczywiście różne informacje mają różne priorytety, zatem projektując taki log, należy wziąć to pod uwagę. W efekcie będziemy tu intensywnie wykorzystywać różne poziomy logowania. Co więcej, jeżeli nie wykorzystujemy żadnego mechanizmy składowania i analizy logów w rodzaju Grayloga czy Logstasha, to koniecznie należy dopieścić konfigurację, tak by informacje o różnych aspektach trafiały do różnych plików (tak, wiem, nagle niskopoziomowo się zrobiło, ale to pewne uproszczenie myślowe). Dzięki temu analiza będzie prostsza.

Logi deweloperskie

Czyli taki bardziej rozbudowany dupadebug. Dzięki tym logom możemy śledzić przebieg programu bez konieczności korzystania z debuggera. Nie są one jakoś często stosowane, ale niekiedy są dość ważne. Tu też zbieramy informacje, które posłużą do dalszej analizy programu. Popularnym zastosowaniem jest rozrzucenie tego typu zapisów w celu odtworzenia procesów dla kodu zastanego i starego. Pozwala to na szybkie określenie warunków wykonania i ścieżek w kodzie na podstawie parametrów wywołania.

Błędy

Gdy mówimy o błędach popełnianych przy logowaniu, to zazwyczaj wskazywane są:

  • Synchronizacja zapisu do logu
  • Łączenie Stringów
  • Podwójne sprawdzanie poziomu logowania (konstrukcja w rodzaju if(log.isDebugEnable())

Rzecz w tym, że poza pierwszym z ww. problemów nie są, to poważne rzeczy. Znacznie częściej mamy do czynienia z zupełnie innymi wrzodami.

Nieprawidłowy poziom logowania

Chyba najpopularniejszy błąd. Pisząc kod, nie zastanawiamy się nad tym, co i jak będzie logowane. Wiadomo błędy na error albo podobny, reszta pomiędzy info, a debug. Błędy do olania na warrning. Nie ważne, czy informacja jest ważna dla biznesu, operatorów czy chcemy mieć jakiś marker w logu. W ten sposób do logu trafiają losowe informacje, które ciężko analizować i jeszcze ciężej coś z nich wywnioskować.

Jak sobie z tym radzić? Myśleć, co się pisze oraz, oczywiście, poświęcić trochę czasu na określenie zasad logowania.

Różne systemy logowania

Drugim popularnym błędem jest mieszanie systemów logowania. Niestety wykorzystywane przez nas narzędzia nie ułatwiają nam życia. Część korzysta z log4j, część z Apache Logging, a jeszcze inne obudowują to w slf4j/slf4j2. Jeżeli dołożymy do tego zawsze dostępny Logger z JRE oraz stary dobry System.out.println, to okaże się, że w ramach jednej aplikacji mamy kilka niespójnych systemów logowania.

Problemy

Drugi z ww. błędów jest objawem poważnego wrzodu na ciele społeczności JVMowej. Język ma co prawda logger na pokładzie, ale pojawił się on dość późno oraz jest stosunkowo prymitywny. W efekcie mamy dużo różnych bibliotek, które mają niespójne API. To oczywiście powoduje, że wraz ze wzrostem złożoności projektu i przyrostem liczby zależności pojawią się coraz to nowsze mechanizmy logowania. Co prawda sfl4j miał rozwiązać ten problem, ale no cóż…

Drugim problemem związanym z niespójnością jest ograniczona możliwość dostosowania loggerów do potrzeb naszej aplikacji. Wybierając jakieś rozwiązanie, musimy pogodzić się z jego ograniczeniami. W ten sposób nasz kod zostaje w pewnym sensie przywiązany do biblioteki. W dodatku tracimy swobodę definiowania, jak logowanie ma działać. Utworzenie loggerów na potrzeby różnych aspektów jest trudne, a w dodatku zmiana biblioteki staje się praktycznie niemożliwa. Słabo. Bardzo słabo.

Podsumowanie

W kolejnym wpisie zabawimy się już z kodem. Mam nadzieję, że to krótkie wprowadzenie nie zabiło waszej ciekawości.