Správné protokolování je klíčovou součástí procesu vývoje softwaru. Vzhledem k množství dostupných protokolovacích frameworků pro Javu je zásadní vybrat ten, který se vyznačuje snadným používáním. Zároveň by měl být zvolený framework vysoce výkonný, rozšiřitelný a umožňovat rozsáhlé přizpůsobení. Log4j2 je bezplatná knihovna pro protokolování v Javě, která splňuje všechny tyto požadavky.
Integrace Log4j2 do jakékoli aplikace otevírá dveře k funkcím, jako je pokročilé filtrování, podpora pro lambda výrazy Java 8, vyhledávání vlastností a vlastní úrovně protokolování. Podívejme se, jak můžete Log4j2 začlenit do svých projektů a jaké výhody vám jeho funkce přinesou.
Co je Log4j2?
Protokolování představuje metodu zaznamenávání užitečných informací, označovaných jako protokoly, které lze následně využít pro analýzu a odkazování. Protokoly se dají efektivně využít pro rychlé odstraňování chyb v kódu aplikace. Umožňují pochopit tok kódu a řešit problémy a chyby, které se objeví v produkčním prostředí.
Kromě diagnostických účelů se protokoly uplatňují i pro účely auditování – například pro sledování úspěšnosti odeslání upozornění uživateli.
Log4j2 se řadí mezi nejoblíbenější knihovny pro protokolování v Javě. Je nástupcem původní a vlivné knihovny Log4j. Log4j2, vyvinutý organizací Apache Software Foundation v rámci Apache Logging Services, je bezplatný software s otevřeným zdrojovým kódem (FOSS), distribuovaný pod licencí Apache, verze 2.0.
Log4j2 staví na solidních základech původní Log4j. Používání Loggeru přináší oproti jednoduchým příkazům System.out.println() značné výhody. Jedná se především o kontrolu nad tím, které zprávy se zobrazí, a zamezení protokolování nepotřebných informací. Správné protokolování je klíčové zejména v produkčním prostředí, kde nemáme k dispozici debuggery.
Jak přidat Log4j2 do vašeho projektu?
Existuje několik metod, jak začlenit Log4j2 do vašeho Java projektu. Pro plné využití všech funkcí Log4j2 se doporučuje používat Java 8 nebo vyšší.
Pojďme si rozebrat různé metody, které můžete použít pro integraci Log4j2, a to v závislosti na specifických požadavcích.
Přidání Log4j2 do projektů pomocí Apache Maven
Pokud pro sestavení projektu používáte Apache Maven, musíte do souboru pom.xml přidat závislosti na Log4j2.
<dependencies> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-api</artifactId> <version>2.20.0</version> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> <version>2.20.0</version> </dependency> </dependencies>
Pro usnadnění správy verzí napříč různými artefakty nabízí Log4j2 soubor pom.xml ve formě kusovníku (Bill of Material). Pokud tento soubor zahrnete do správy závislostí, nemusíte specifikovat jednotlivé verze.
<!-- Add the BOM to the dependencyManagement --> <dependencyManagement> <dependencies> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-bom</artifactId> <version>2.20.0</version> <scope>import</scope> <type>pom</type> </dependency> </dependencies> </dependencyManagement> <!-- Once the BOM is added, the versions are not required --> <dependencies> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-api</artifactId> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> </dependency> </dependencies>
Přidání Log4j2 do projektů pomocí Apache Gradle
Pokud jako nástroj pro sestavení používáte Apache Gradle, můžete závislosti Log4j2 přidat do souboru build.gradle.
dependencies { implementation 'org.apache.logging.log4j:log4j-api:2.20.0' implementation 'org.apache.logging.log4j:log4j-core:2.20.0' }
Při použití Gradle verze 5.0 nebo vyšší máte možnost importovat Log4j2 Maven Bill Of Materials (BOM) a zajistit tak konzistentní verze závislostí. Toho docílíte přidáním následujícího kódu do souboru build.gradle.
dependencies { implementation platform('org.apache.logging.log4j:log4j-bom:2.20.0') implementation 'org.apache.logging.log4j:log4j-api' runtimeOnly 'org.apache.logging.log4j:log4j-core' }
Pro verze Gradle 2.8-4.10 není přímý import kusovníku Maven k dispozici. Pro funkcionalitu správy závislostí musíte použít dodatečný plugin.
plugins { id 'io.spring.dependency-management' version '1.0.15.RELEASE' } dependencyManagement { imports { mavenBom 'org.apache.logging.log4j:log4j-bom:2.20.0' } } dependencies { implementation 'org.apache.logging.log4j:log4j-api' runtimeOnly 'org.apache.logging.log4j:log4j-core' }
Přidání Log4j2 do samostatných aplikací bez nástroje pro sestavení
Pokud projekt nepoužívá nástroj pro sestavení, můžete potřebnou verzi artefaktu Log4j2 stáhnout z oficiální stránky pro stahování Log4j2.
Po stažení je nutné zajistit, aby třída vaší aplikace zahrnovala následující JAR soubory:
- log4j-api-2.20.0.jar
- log4j-core-2.20.0.jar
Jaké jsou součásti v Log4j2?
Pro pochopení funkčnosti Log4j2 a plného využití jeho možností je důležité porozumět tomu, jak Log4j2 funguje. Pod povrchem se Log4j2 skládá z několika základních stavebních bloků, které si nyní popíšeme.
#1. LoggerContext
LoggerContext je centrální jednotkou celého logovacího systému. Uchovává všechny Loggery používané v aplikaci a obsahuje odkaz na konfiguraci.
#2. Konfigurace
Konfigurace zahrnuje veškeré informace potřebné logovacím systémem, včetně Loggerů, Appenderů, Filtrů a dalších prvků. V Log4j2 můžete definovat konfiguraci pomocí různých formátů souborů, jako jsou XML, JSON a YAML, případně programově prostřednictvím Log4j2 API.
Každá změna vlastnosti v konfiguraci spustí automatické opětovné načtení, takže není vyžadován restart aplikace.
#3. Logger
Logger je klíčovou součástí systému Log4j2. Protokoly se generují v kódu aplikace pomocí příkazu LogManager.getLogger() a využívají se pro generování protokolových záznamů. Zprávy protokolu se generují na různých úrovních závažnosti, jako je ladění (debug), informace (info), varování (warning), chyba (error) a kritická chyba (fatal).
#4. LoggerConfig
LoggerConfig odpovídá za chování specifického Loggeru. Definuje jeho chování a nastavení pro protokolování událostí, které tento konkrétní Logger generuje. Umožňuje nastavení různých úrovní protokolování, konfiguraci appenderů a aplikaci filtrů.
#5. Filtr
V Log4j2 můžete selektivně zpracovávat události protokolu pomocí filtrů. Filtry se aplikují na základě definovaných kritérií a můžete je použít na loggery i appendery. Filtry řídí, které události protokolu mohou projít kanálem protokolování k dalšímu zpracování, což umožňuje ladění a zajištění zpracování jen relevantních záznamů.
#6. Appender
Appender určuje cíl každé protokolové zprávy. Jeden Logger může mít více Appenderů a každá protokolová událost bude odeslána všem Appenderům daného Loggeru. Log4j2 nabízí mnoho předkonfigurovaných appenderů, například ConsoleAppender pro výpis zpráv do konzole a FileAppender pro výstup do souboru. Každý Appender vyžaduje vlastní Layout, který definuje, jak bude vypadat výsledná protokolová zpráva.
#7. Rozložení (Layout)
Layout v Log4j2 definuje, jak bude vypadat výsledná zpráva protokolu a je spojen s konkrétním Appenderem. Zatímco Appender určuje výstupní cíl, Layout popisuje formát výpisu zprávy.
Top 5 funkcí Log4j2
Log4j2 je bohatý na funkce, které ho odlišují od ostatních dostupných protokolovacích frameworků pro Javu. Nabízí funkce od asynchronních loggerů po podporu lambda výrazů Java 8, což dává Log4j2 náskok před konkurencí. Pojďme se podívat na některé z těchto významných funkcí.
#1. Rozšíření funkcí pomocí pluginů
V Log4j 1.x vyžadovalo vytváření rozšíření poměrně rozsáhlé úpravy kódu. Log4j2 tento problém řeší pomocí systému pluginů, který umožňuje snadnou rozšiřitelnost.
Nový plugin lze deklarovat pomocí anotace @Plugin ve vaší třídě. S využitím pluginů můžete vytvářet vlastní komponenty, jako jsou filtry a doplňky. Do knihovny se tak dají snadno přidávat i komponenty třetích stran.
#2. Podpora Java 8 Lambda
S verzí Log4j2 2.4 byla zavedena podpora pro lambda výrazy v Javě 8. Pomocí lambda výrazů můžete inline definovat logiku protokolování, čímž eliminujete potřebu víceřádkových kontrol nebo anonymních vnitřních tříd. To zároveň zajišťuje, že náročné metody se nespouštějí zbytečně. Výsledkem je čistší a čitelnější kód s menší systémovou režií.
Představme si situaci, kdy chcete zaznamenat výsledek náročné operace, ale pouze pokud je povolena úroveň ladění. Před zavedením podpory lambda byste museli použít následující kód:
if (logger.isDebugEnabled()) { logger.debug("The output of the given operation is: {}", expensiveOperation()); }
Takové podmíněné kontroly by zbytečně komplikovaly kód. S Log4j2 však lze stejnou operaci provést následovně:
logger.debug("The output of the given operation is: {}", () -> expensiveOperation()
Metoda `expensiveOperation()` se vyhodnotí pouze v případě, že je povolena úroveň ladění, takže explicitní kontroly nejsou potřeba.
#3. Asynchronní loggery
Každá událost protokolování je I/O operace, což zvyšuje režii systému. Log4j2 tento problém řeší zavedením asynchronních loggerů, které běží v odděleném vlákně od vlákna aplikace. Při použití asynchronních loggerů získává volající vlákno kontrolu zpět okamžitě po zavolání metody `logger.log()`.
To umožňuje pokračovat v logice aplikace bez nutnosti čekání na dokončení události protokolování. Díky tomuto asynchronnímu chování se dosahuje vyšší propustnosti při protokolování. Můžete si vybrat, zda budou všechny loggery ve výchozím nastavení asynchronní, nebo kombinovat synchronní a asynchronní chování.
#4. Logování bez odpadků
V Javě je garbage collection proces, který automaticky uvolňuje nepoužívané objekty v aplikaci. I když se o tuto operaci nemusíte starat ručně, má svou vlastní režii.
Pokud vaše aplikace vytvoří příliš mnoho objektů v krátkém časovém intervalu, proces garbage collection může vyžadovat více systémových prostředků, než je optimální. Několik knihoven pro protokolování, včetně starších verzí Log4j, vytváří při procesu protokolování velké množství dočasných objektů, což zvyšuje tlak na garbage collector a ovlivňuje výkon systému.
Od verze 2.6 běží Log4j2 v režimu „bez odpadků“, což je jeho výchozí chování. To znamená, že objekty jsou opětovně používány a tvorba dočasných objektů je minimalizována.
Následující obrázky ukazují, jak Log4j2 verze 2.6 řeší problém nepotřebných objektů v porovnání s verzí 2.5.
V Log4j2 verze 2.5 se během procesu protokolování vytváří mnoho dočasných objektů; Zdroj: apache.org
V Log4j2.6 se během procesu protokolování nevytvářejí žádné dočasné objekty; Zdroj: apache.org
#5. Vyhledávání
V Log4j2 můžete do protokolů přidávat kontextové informace pomocí vyhledávání. Díky vyhledávání můžete získávat data z různých zdrojů, jako jsou systémové vlastnosti, proměnné prostředí nebo uživatelsky definované hodnoty. Do protokolů se tak dají dynamicky vkládat relevantní informace, což zvyšuje jejich užitečnost.
Představte si situaci, kdy chcete ke každému řádku protokolu zaznamenávat ID relace uživatele, abyste mohli vyhledat všechny protokoly s daným ID.
Jednoduchý, ale obtížně udržovatelný způsob by bylo explicitní přidávání ID relace ke každému řádku, což by bylo náchylné na chyby a opomenutí.
logger.info("The user data has been fetched for session id {}", sessionId); ... logger.info("The transaction has been processed for session id {}", sessionId); ... logger.info("Request has been successfully processed for session id {}", sessionId);
Efektivnější přístup je použití kontextového vyhledávání mapy. ID relace se přidá do kontextu vlákna v kódu aplikace a jeho hodnotu lze použít v konfiguraci Log4j2. Díky tomu není nutné ID relace explicitně uvádět v protokolových zprávách.
ThreadContext.put("sessionId", sessionId);
Po přidání hodnoty ji lze použít ve vyhledávání pomocí klíčového slova `ctx`.
<File name="Application" fileName="application.log"> <PatternLayout> <pattern>%d %p %c{1.} [%t] $${ctx:sessionId} %m%n</pattern> </PatternLayout> </File>
Jak vytvořit vlastní úrovně protokolu v Log4j2?
Úrovně protokolu v Log4j2 se používají ke kategorizaci událostí protokolu podle jejich závažnosti a důležitosti. Úroveň protokolu se nastavuje v kódu při protokolování zprávy.
Například `logger.debug()` přidá úroveň DEBUG, zatímco `logger.error()` přidá úroveň ERROR. To ovlivňuje, které zprávy se nakonec zobrazí ve výstupu. Úroveň protokolu můžete konfigurovat v konfiguračním souboru.
Předkonfigurované úrovně protokolování v Log4j2 a jejich odpovídající hodnoty jsou uvedeny níže.
OFF 0 FATAL 100 ERROR 200 WARN 300 INFO 400 DEBUG 500 TRACE 600 ALL MAX HODNOTA
Pokud je úroveň protokolu nastavena na určitou úroveň, zobrazí se všechny protokolové zprávy s touto hodnotou a všechny zprávy s nižšími hodnotami, ostatní jsou ignorovány.
Například pokud nastavíte úroveň protokolu na WARN, zobrazí se zprávy WARN, ERROR a FATAL. Ostatní zprávy s nižší úrovní budou ignorovány. To je obzvláště užitečné, když spouštíte stejný kód v různých prostředích.
Při spuštění kódu ve vývojovém prostředí můžete chtít nastavit úroveň protokolu na INFO nebo DEBUG, abyste viděli více protokolů. V produkčním prostředí je lepší nastavit úroveň na ERROR, abyste se zaměřili jen na relevantní zprávy v případě anomálií.
Někdy může být potřeba přidat vlastní úroveň protokolu nad rámec těch předkonfigurovaných. Log4j2 vám to snadno umožní. Podívejme se, jak můžete přidat vlastní úroveň protokolu a používat ji ve své aplikaci.
#1. Přidání vlastní úrovně protokolu pomocí konfiguračního souboru
Vlastní úrovně protokolu se přidávají tak, že je deklarujete v konfiguračním souboru.
V následujícím příkladu je definována vlastní úroveň protokolu s názvem NOTICE s hodnotou 450, čímž je umístěna mezi INFO (s hodnotou 400) a DEBUG (s hodnotou 500). Pokud je úroveň nastavena na NOTICE, zobrazí se zprávy INFO, ale zprávy DEBUG budou přeskočeny.
<?xml version="1.0" encoding="UTF-8"?> <Configuration> <CustomLevels> <CustomLevel name="NOTICE" intLevel="450" /> </CustomLevels> <Appenders> <File name="MyFile" fileName="logs/app.log"> <PatternLayout pattern="%d %-7level %logger{36} - %msg%n"/> </File> </Appenders> <Loggers> <Root level="trace"> <AppenderRef ref="MyFile" level="NOTICE" /> </Root> </Loggers> </Configuration>
#2. Přidání vlastní úrovně protokolu do kódu
Kromě deklarování v konfiguračním souboru můžete definovat vlastní úrovně protokolu přímo v kódu.
final Level VERBOSE = Level.forName("VERBOSE", 550);
Tím se vytvoří nová úroveň protokolu s názvem VERBOSE, která leží mezi úrovněmi DEBUG (s hodnotou 500) a TRACE (s hodnotou 600). Pokud je logger nastaven na úroveň VERBOSE, protokolují se všechny zprávy s touto úrovní a zprávy DEBUG. Zprávy TRACE budou naopak přeskočeny.
#3. Použití Custom Log Level v kódu
Vlastní úrovně protokolu musí být nejprve deklarovány, a to buď v konfiguračním souboru, nebo v kódu. Poté je můžete volně používat.
Následující příklad kódu ukazuje deklaraci vlastní úrovně NOTICE a její následné použití.
final Level NOTICE = Level.forName("NOTICE", 550); final Logger logger = LogManager.getLogger(); logger.log(NOTICE, "a notice level message");
I když to vygeneruje požadovanou zprávu s nově vytvořenou úrovní, může být obtížné vždy explicitně předávat úroveň. Naštěstí můžete generovat zdrojový kód a získat pomocné metody pro protokolování vlastních úrovní. Můžete tak používat vlastní metodu logger.notice(), podobně jako používáte logger.debug() nebo logger.error().
Log4j2 nabízí utilitu, která vám pomůže vytvářet vlastní rozšířené loggery. Následující příkaz vygeneruje soubor Java s názvem CustomLogger.java, který obsahuje stávající metody protokolování spolu s nově vygenerovanými metodami pro úroveň NOTICE.
java -cp log4j-core-2.20.0.jar org.apache.logging.log4j.core.tools.ExtendedLoggerGenerator com.example.CustomLogger NOTICE=450 > com/example/CustomLogger.java
Po vygenerování souboru můžete ve svém kódu použít třídu pro vytváření nových protokolů, které budou obsahovat dodatečné metody pro vaši vlastní úroveň protokolu. Tím se rozšiřuje funkčnost vašich loggerů.
final Logger logger = CustomLogger.create(ValueFirstSmsSender.class); //this new method is similar to using logger.debug() logger.notice("a notice level message");
Závěr
Log4j2 je velmi výkonný framework pro protokolování v Javě, který nabízí širokou škálu funkcí, konfigurací, vylepšení výkonu a mnoho dalšího. Vzhledem k tomu, že protokoly jsou velmi důležitou součástí procesu vývoje softwaru, robustní framework jako Log4j2 významně přispívá k celkové efektivitě aplikace.
Díky flexibilitě a rozšiřitelnosti Log4j2 je možné správně zaznamenávat události probíhající ve vaší aplikaci. Protokoly se tak stávají účinným nástrojem pro ladění i auditování. Díky všem svým funkcím a vylepšením si Log4j2 zaslouží být preferovanou volbou v mnoha rozmanitých softwarových projektech.
Mohly by vás také zajímat tyto Java IDE a online kompilátory.