CodeGym /Blog Java /Random-PL /Logowanie: co, jak, gdzie iz czym?
John Squirrels
Poziom 41
San Francisco

Logowanie: co, jak, gdzie iz czym?

Opublikowano w grupie Random-PL
Witam wszystkich w społeczności CodeGym! Logowanie: co, jak, gdzie iz czym?  - 1 Dzisiaj porozmawiajmy o logowaniu:
  1. Czym jest, dlaczego istnieje, kiedy należy go używać, a kiedy należy go unikać.
  2. Jakie implementacje rejestrowania są dostępne w Javie i co należy zrobić z tymi wszystkimi opcjami rejestrowania.
  3. I poziomy dziennika. Omówimy czym jest appender i jak go poprawnie skonfigurować.
  4. Logowanie węzłów i jak je poprawnie skonfigurować, aby wszystko działało tak, jak chcemy.
Ten materiał jest przeznaczony dla szerokiego grona odbiorców. Będzie to jasne dla każdego, kto dopiero poznaje Javę, a także dla osób, które już pracują, ale dopiero poznały logger.info("log something"); Let's go!

Dlaczego potrzebujesz logowania?

Przyjrzyjmy się kilku rzeczywistym przypadkom, w których rejestrowanie może rozwiązać problem. Oto przykład z mojej pracy. Istnieją punkty, w których aplikacja integruje się z innymi usługami. Używam rejestrowania w tych punktach, aby ustalić rodzaj „alibi” : jeśli integracja nie działa, łatwo jest ustalić, która strona ma problem. Pożądane jest również rejestrowanie ważnych informacji przechowywanych w bazie danych. Na przykład utworzenie użytkownika administratora. To jest właśnie rodzaj rzeczy, które dobrze byłoby zarejestrować.

Narzędzia do logowania w Javie

Wśród dobrze znanych rozwiązań rejestrowania w Javie możemy wyróżnić następujące:
  • Log4j
  • JUL — java.util.logging
  • JCL — rejestrowanie Jakarta Commons
  • Logowanie
  • SLF4J — Prosta fasada rejestrowania dla języka Java
Przedstawimy przegląd każdego z nich. Następnie weźmiemy powiązanie slf4j - log4j jako podstawę praktycznej dyskusji. Może się to teraz wydawać dziwne, ale nie martw się: pod koniec artykułu wszystko będzie jasne.

System.err.println

Na początku był System.err.println (wyświetlający wpisy w logu na konsoli). Nawet dzisiaj ta technika jest używana do szybkiego rejestrowania podczas debugowania. Oczywiście nie ma tutaj żadnych ustawień do omówienia, więc po prostu zapamiętaj tę metodę i przejdziemy dalej.

Log4j

Jest to kompletne rozwiązanie, które programiści stworzyli z konieczności. Rezultatem jest naprawdę interesujące narzędzie, którego możesz użyć. Rozwiązanie to z różnych powodów nie trafiło do JDK, co bardzo zaniepokoiło całą społeczność. Log4j posiada opcje konfiguracyjne, które umożliwiają włączenie logowania w com.example.typepakiecie i wyłączenie go w com.example.type.genericpodpakiecie. Dzięki temu możliwe jest szybkie wykluczenie kodu, który nie wymaga logowania. Należy tutaj zauważyć, że istnieją dwie wersje Log4j: 1.2.x i 2.xx, które są ze sobą niekompatybilne . Log4j dodał koncepcje appendera(narzędzie służące do zapisywania logów) i układ (formatowanie logów). Dzięki temu możesz rejestrować tylko to, czego potrzebujesz i rejestrować to tak, jak potrzebujesz. Porozmawiamy więcej o appender nieco później.

JUL — java.util.logging

Jedną z kluczowych zalet tego rozwiązania jest to, że JUL jest zawarty w JDK (Java Development Kit). Niestety, gdy powstawał, jego twórcy nie oparli go na popularnym narzędziu Log4j, ale na rozwiązaniu firmy IBM. Ta decyzja pociągnęła za sobą konsekwencje. W rzeczywistości nikt nie używa teraz JUL. Poziomy dziennika w JUL różnią się od tych, które mają Logback, Log4j i Slf4j. To utrudnia im wzajemne zrozumienie. Tworzenie rejestratora jest mniej więcej podobne. Aby to zrobić, musisz wykonać import:

java.util.logging.Logger log = java.util.logging.Logger.getLogger(LoggingJul.class.getName());
Nazwa klasy jest przekazywana, więc wiemy skąd będzie pochodzić nasze logowanie. Począwszy od Javy 8, możesz przekazać Supplier<String>. Pomaga nam to czytać i tworzyć wiersze tylko wtedy, gdy naprawdę tego potrzebujemy, a nie za każdym razem, jak miało to miejsce wcześniej. Dopiero wraz z wydaniem Java 8 programiści w końcu rozwiązali ważne problemy i sprawili, że JUL był naprawdę użyteczny. Mianowicie metody z Supplier<String> msgSupplierparametrem, jak pokazano poniżej:

public void info(Supplier<String> msgSupplier) {
   log(Level.INFO, msgSupplier);
}

JCL — rejestrowanie Jakarta Commons

Ponieważ przez długi czas nie było standardu branżowego dotyczącego rejestrowania, a wiele osób tworzyło własne, niestandardowe rejestratory, podjęto decyzję o wydaniu JCL, ogólnego opakowania, którego można używać na innych. Dlaczego? Czasami zależności dodane do projektu korzystały z innego rejestratora niż ten w projekcie. Z tego powodu zostały dodane do projektu jako zależności przechodnie, co stworzyło prawdziwe problemy przy próbie połączenia tego wszystkiego. Niestety opakowanie nie było zbyt funkcjonalne i nic nie dodało. Prawdopodobnie byłoby wygodniej, gdyby wszyscy korzystali z JCL. Ale tak się nie stało, więc używanie JCL nie jest w tej chwili najlepszym pomysłem.

Logowanie

Ścieżka open source jest ciernista… Ten sam programista, który napisał Log4j, napisał również Logback jako następcę struktury rejestrowania. Opierał się na tym samym pomyśle co Log4j. Różnice w Logbacku to:
  • ulepszona wydajność
  • dodano natywną obsługę Slf4j
  • rozbudowane opcje filtrowania
Domyślnie Logback nie wymaga żadnej konfiguracji i rejestruje wszystkie zdarzenia na poziomie DEBUG i wyższym. Jeśli potrzebujesz dostosowania, możesz to osiągnąć za pomocą konfiguracji XML:

<configuration> 
    <appender name="FILE" class="ch.qos.logback.core.FileAppender"> 
        <file>app.log</file> 
        <encoder> 
            <pattern>%d{HH:mm:ss,SSS} %-5p [%c] - %m%n</pattern> 
        </encoder> 
    </appender> 
    <logger name="org.hibernate.SQL" level="DEBUG" /> 
    <logger name="org.hibernate.type.descriptor.sql" level="TRACE" /> 
    <root level="info"> 
        <appender-ref ref="FILE" /> 
    </root> 
</configuration>

SLF4J — Prosta fasada rejestrowania dla języka Java

Gdzieś w 2006 roku jeden z ojców założycieli Log4j opuścił projekt i stworzył Slf4j (Simple Logging Facade for Java), opakowanie dla Log4j, JUL, common-logging i Logback. Jak widać, doszliśmy do momentu tworzenia wrappera nad wrapperem... W tym przypadku jest on podzielony na dwie części: API używane w aplikacji oraz implementację, która jest dodawana osobnymi zależności dla każdego typu logowania. Na przykład slf4j-log4j12.jari slf4j-jdk14.jar. Musisz podłączyć poprawną implementację i to wszystko: cały Twój projekt będzie z niej korzystał. Slf4j obsługuje wszystkie najnowsze funkcje, takie jak formatowanie ciągów znaków do logowania. Wcześniej był taki problem. Załóżmy, że tworzymy taki wpis w dzienniku:

log.debug("User " + user + " connected from " + request.getRemoteAddr());
Dzięki operatorowi konkatenacji userobiekt po cichu staje się łańcuchem dzięki user.toString(). Zajmuje to dużo czasu i spowalnia system. I to może być OK, jeśli debugujemy aplikację. Zaczynamy napotykać problemy, jeśli poziom dziennika dla tej klasy to INFO lub wyższy. Innymi słowy, nie powinniśmy zapisywać tego wpisu w dzienniku (dla INFO lub wyższego) i nie powinniśmy używać konkatenacji łańcuchów. Teoretycznie sama biblioteka rejestrowania powinna rozwiązać ten problem. Tak się złożyło, że okazało się to największym problemem w pierwszej wersji Log4j. Nie dostarczył przyzwoitego rozwiązania, ale zamiast tego zasugerował zrobienie czegoś takiego:

if (log.isDebugEnabled()) {
    log.debug("User " + user + " connected from " + request.getRemoteAddr());
}
Oznacza to, że zamiast jednego wiersza kodu do logowania zasugerowali napisanie 3! Rejestrowanie powinno minimalizować zmiany kodu, a trzy linie wyraźnie naruszają to ogólne podejście. Slf4j nie miał problemów z kompatybilnością z JDK i API, więc od razu pojawiło się fajne rozwiązanie:

log.debug("User {} connected from {}", user, request.getRemoteAddr());
gdzie {}oznacza symbole zastępcze dla argumentów przekazanych do metody. Oznacza to, że pierwszy {}odpowiada user, a drugi {}odpowiada request.getRemoteAddr(). Robiąc to w ten sposób, wykonamy konkatenację łańcuchów tylko wtedy, gdy poziom dziennika wymaga od nas napisania wpisu dziennika. Potem popularność Sjf4j zaczęła szybko rosnąć. Obecnie jest to najlepsze rozwiązanie. W związku z tym przyjrzyjmy się rejestrowaniu przy użyciu slf4j-log4j12powiązania.

Co trzeba zalogować

Oczywiście nie należy rejestrować wszystkiego. Często nie jest to konieczne, a czasem nawet niebezpieczne. Na przykład, jeśli zarejestrujesz czyjeś dane osobowe i jakoś wyciekną, będą prawdziwe problemy, szczególnie w projektach skoncentrowanych na rynkach zachodnich. Ale są też rzeczy, które zdecydowanie powinieneś zarejestrować :
  1. Początek/koniec aplikacji. Musimy wiedzieć, czy aplikacja naprawdę uruchomiła się i zakończyła zgodnie z oczekiwaniami.
  2. Problemy z bezpieczeństwem. Tutaj dobrze byłoby rejestrować próby odgadnięcia czyjegoś hasła, przypadki logowania się administratorów itp.
  3. Określone stany aplikacji . Na przykład przejście z jednego stanu do drugiego w procesie biznesowym.
  4. Niektóre informacje debugowania wraz z odpowiednim poziomem dziennika.
  5. Niektóre skrypty SQL. Istnieją rzeczywiste przypadki, w których jest to konieczne. Ale znowu, umiejętnie dostosowując poziomy logów, możesz osiągnąć doskonałe wyniki.
  6. Uruchomione wątki mogą być rejestrowane podczas sprawdzania, czy wszystko działa poprawnie.

Popularne błędy w logowaniu

Jest tu wiele niuansów, ale zwrócimy szczególną uwagę na kilka typowych błędów:
  1. Nadmierne logowanie. Nie powinieneś rejestrować każdego kroku, który teoretycznie mógłby być ważny. Oto dobra zasada: kłody nie powinny przekraczać 10% obciążenia. W przeciwnym razie wystąpią problemy z wydajnością.
  2. Logowanie wszystkich danych do jednego pliku. W pewnym momencie bardzo utrudni to odczyt/zapis dziennika, nie wspominając już o tym, że niektóre systemy mają ograniczenia rozmiaru pliku.
  3. Używanie nieprawidłowych poziomów dziennika. Każdy poziom dziennika ma wyraźne granice i należy ich przestrzegać. Jeśli granica jest niejasna, możesz dojść do porozumienia co do tego, którego poziomu użyć.

Rejestruj poziomy

x: Widoczne
FATALNY BŁĄD OSTRZEGAĆ INFORMACJE ODPLUSKWIĆ NAMIERZAĆ WSZYSTKO
WYŁĄCZONY
FATALNY X
BŁĄD X X
OSTRZEGAĆ X X X
INFORMACJE X X X X
ODPLUSKWIĆ X X X X X
NAMIERZAĆ X X X X X X
WSZYSTKO X X X X X X X
Co to są poziomy dziennika? Aby w jakiś sposób stworzyć hierarchię wpisów dziennika, konieczne są pewne konwencje i rozgraniczenia. Dlatego wprowadzono poziomy dziennika. Poziom ustawia się w aplikacji. Jeśli wpis jest poniżej określonego poziomu, nie jest rejestrowany. Na przykład mamy logi, których używamy podczas debugowania aplikacji. Podczas normalnej pracy (gdy aplikacja jest używana zgodnie z jej przeznaczeniem) takie logi nie są potrzebne. W związku z tym poziom dziennika jest wyższy niż w przypadku debugowania. Przyjrzyjmy się poziomom dziennika za pomocą Log4j. Oprócz JUL inne rozwiązania wykorzystują te same poziomy dziennika. Oto one w kolejności malejącej:
  • WYŁ.: Żadne wpisy dziennika nie są rejestrowane; wszystko jest ignorowane.
  • KRYTYCZNY: Błąd uniemożliwiający dalsze działanie aplikacji. Na przykład „Błąd braku pamięci maszyny JVM”.
  • BŁĄD: Błędy na tym poziomie wskazują problemy, które należy rozwiązać. Błąd nie zatrzymuje aplikacji jako całości. Inne żądania mogą działać poprawnie.
  • OSTRZEŻENIE: Wpisy w dzienniku, które reprezentują ostrzeżenie. Stało się coś nieoczekiwanego, ale system poradził sobie i spełnił żądanie
  • INFORMACJE: Wpisy dziennika wskazujące ważne działania w aplikacji. To nie są błędy ani ostrzeżenia. Są to oczekiwane zdarzenia systemowe.
  • DEBUGOWANIE: wpisy dziennika potrzebne do debugowania aplikacji. Za upewnienie się, że aplikacja robi dokładnie to, czego się oczekuje, lub za opisanie działań podejmowanych przez aplikację, np. „Wprowadzona metoda1”.
  • TRACE: wpisy dziennika o niższym priorytecie do debugowania. Najniższy poziom dziennika.
  • WSZYSTKIE: Poziom dziennika do zapisywania wszystkich wpisów dziennika aplikacji.
Gdzieś w aplikacji jest włączony poziom logu INFO, wtedy logowane będą wpisy dla każdego poziomu, od INFO do FATAL. Jeśli ustawiony jest poziom dziennika FATAL, zostaną zapisane tylko wpisy dziennika z tym poziomem.

Logowanie i wysyłanie logów: Appender

Zastanówmy się, jak to wszystko działa, gdy używamy Log4j, który zapewnia szerokie możliwości zapisywania/wysyłania logów:
  • pisać do pliku —DailyRollingFileAppender
  • zapisywać informacje w konsoli —ConsoleAppender
  • zapisywać dzienniki do bazy danych —JDBCAppender
  • zarządzać wysyłaniem dzienników przez TCP/IP —TelnetAppender
  • za zapewnienie, że rejestrowanie nie ma negatywnego wpływu na wydajność —AsyncAppender
Jest jeszcze kilka implementacji: pełna lista jest dostępna tutaj . Nawiasem mówiąc, jeśli aplikator, którego potrzebujesz, nie istnieje, nie stanowi to problemu. Możesz napisać własny appender, implementując interfejs Appender , który obsługuje Log4j.

Węzły rejestrowania

Do celów demonstracyjnych użyjemy interfejsu Slf4j z implementacją z Log4j. Tworzenie loggera jest bardzo proste: w klasie o nazwie MainDemo, która będzie logować, musimy dodać:

org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(MainDemo.class);
Spowoduje to utworzenie dla nas rejestratora. Aby dokonać wpisu w dzienniku, dostępnych jest kilka metod, których nazwy odzwierciedlają używany poziom dziennika. Na przykład:

logger.trace("Method 1 started with argument={}", argument);
logger.debug("Database updated with script = {}", script);
logger.info("Application has started on port = {}", port);
logger.warn("Log4j didn't find the log4j.properties file. Please fix this.");
logger.error("Connection refused to host = {}", host);
Chociaż przekazujemy klasę, ostateczna nazwa to pełna nazwa klasy, w tym pakiety. Odbywa się to po to, aby później można było podzielić logowanie na węzły i skonfigurować poziom logowania i appender dla każdego węzła. Na przykład program rejestrujący został utworzony w com.github.romankh3.logginglecture.MainDemoklasie. Nazwa stanowi podstawę do stworzenia hierarchii węzłów logowania. Głównym węzłem jest RootLogger najwyższego poziomu . Jest to węzeł, który odbiera wszystkie wpisy dziennika dla całej aplikacji. Pozostałe węzły można przedstawić w następujący sposób: Logowanie: co, jak, gdzie iz czym?  - 3Appendery są skonfigurowane dla określonych węzłów rejestrowania. Teraz przyjrzymy się plikowi log4j.properties , aby zobaczyć przykład ich konfiguracji.

Przewodnik krok po kroku dotyczący pliku log4j.properties

Ustawimy wszystko krok po kroku i zobaczymy, co jest możliwe:

log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
Ten wiersz mówi, że rejestrujemy appender CONSOLE, który używa implementacji org.apache.log4j.ConsoleAppender. Ten program dołączający zapisuje informacje w konsoli. Następnie rejestrujemy kolejnego dołączającego. Ten zapisze do pliku:

log4j.appender.FILE=org.apache.log4j.RollingFileAppender
Należy zauważyć, że same programy dołączające nadal wymagają skonfigurowania. Po zarejestrowaniu naszych programów dołączających możemy określić, które poziomy dziennika i które programy dołączające będą używane w węzłach.

log4j.rootLogger=DEBUGOWANIE, KONSOLA, PLIK

  • log4j.rootLogger oznacza, że ​​konfigurujemy węzeł główny, który zawiera wszystkie wpisy dziennika
  • Pierwsze słowo po znaku równości wskazuje minimalny poziom logowania do zapisu (w naszym przypadku jest to DEBUG)
  • Po przecinku wskazujemy wszystkie dołączacze, które mają być użyte.
Aby skonfigurować bardziej konkretny węzeł rejestrowania, użyjesz takiego wpisu:

log4j.logger.com.github.romankh3.logginglecture=TRACE, OWN, CONSOLE
gdzie log4j.logger.służy do odwoływania się do określonego węzła. W naszym przypadku com.github.romankh3.logginglecture. porozmawiajmy teraz o konfiguracji programu dołączającego CONSOLE:

# CONSOLE appender customization
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.threshold=DEBUG
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=[%-5p] : %c:%L : %m%n
Tutaj widzimy, że możliwe jest ustawienie konkretnego poziomu, na którym appender zacznie działać. Oto przykład tego, co faktycznie się dzieje: załóżmy, że komunikat z poziomem INFO jest odbierany przez węzeł rejestrowania i przekazywany do przypisanego do niego programu dołączającego. Jeśli próg programu dołączającego jest ustawiony na OSTRZEŻENIE, otrzymuje on wpis dziennika, ale nic z nim nie robi. Następnie musimy zdecydować, jakiego układu użyje wiadomość. W przykładzie używam PatternLayout, ale istnieje wiele innych opcji. Nie będziemy ich omawiać w tym artykule. Przykład konfiguracji appendera FILE:

# File appender customization
log4j.appender.FILE=org.apache.log4j.RollingFileAppender
log4j.appender.FILE.File=./target/logging/logging.log
log4j.appender.FILE.MaxFileSize=1MB
log4j.appender.FILE.threshold=DEBUG
log4j.appender.FILE.MaxBackupIndex=2
log4j.appender.FILE.layout=org.apache.log4j.PatternLayout
log4j.appender.FILE.layout.ConversionPattern=[ %-5p] - %c:%L - %m%n
Możesz skonfigurować konkretny plik, do którego będą zapisywane wpisy dziennika, jak widać z tego wiersza:

log4j.appender.FILE.File=./target/logging/logging.log
Wpis zostanie zapisany do logging.logpliku. Aby uniknąć problemów z rozmiarem pliku, możesz skonfigurować maksimum, które w tym przypadku wynosi 1 MB. MaxBackupIndexwskazuje, ile będzie takich plików dziennika. Jeśli musimy utworzyć więcej plików niż to, pierwszy plik zostanie usunięty. Aby zobaczyć prawdziwy przykład konfiguracji logowania, możesz przejść do publicznego repozytorium na GitHub.

Wzmocnij to, o czym rozmawialiśmy

Spróbuj samodzielnie zrobić wszystko, co opisaliśmy:
  • Stwórz własny projekt podobny do naszego przykładu powyżej.
  • Jeśli wiesz, jak korzystać z Mavena, użyj go. Jeśli nie, przeczytaj ten samouczek, w którym opisano sposób podłączenia biblioteki.

W podsumowaniu

  1. Rozmawialiśmy o rozwiązaniach do rejestrowania, które istnieją w Javie.
  2. Prawie wszystkie znane biblioteki logowania zostały napisane przez jedną osobę :D
  3. Dowiedzieliśmy się, co powinno, a czego nie powinno być rejestrowane.
  4. Ustaliliśmy poziomy dziennika.
  5. Zostaliśmy wprowadzeni do logowania węzłów.
  6. Przyjrzeliśmy się, czym jest aplikator i do czego służy.
  7. Krok po kroku stworzyliśmy plik log4j.proterties.

Dodatkowe materiały

  1. CodeGym: Lekcja Loggera
  2. Weekly Geekly: Logowanie w Javie. Witaj świecie
  3. Horror kodowania: problem z logowaniem
  4. YouTube: Zrozumienie piekła rejestrowania Java — podstawy. Java Logging Piekło i jak trzymać się z dala od niego
  5. Log4j: Dodatek
  6. Log4j: Układ
Zobacz też mój inny artykuł:
Komentarze
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION