PV168/Logování

Z FI WIKI
Přejít na: navigace, hledání

Přehled

Logování je ukládání informací o událostech v programu, jehož účelem je v případě potřeby dohledání činnosti systému nebo diagnostikování chyby.

V jazyce Java existují v podstatě tyto tři hlavní implementace logování:

Aby nemusely být aplikace a knihovny psány pro konkrétní z těchto implementací, existují dvě obalovací logovací knihovny, které neposkytují implementaci logování, jen rozhraní:

Logback a Log4J jsou od stejného autora, Logback je novější, rychlejší a flexibilnější než Log4J. Log4J bylo odjakživa lepší než JUL, ale JUL byl prosazen silou firmou Sun jako standardní součást JDK.

SLF4J je nástupce JCL, odstraňuje jeho problémy s classloadery.

Co mám použít ?

Ve zdrojových textech svých programů používejte rozhraní SLF4J.

Při nasazení programů používejte implementaci Logback.

Při využití cizích knihoven nebo programů, které používají něco jiného, využijte SLF4J legacy bridge, tj. jcl-over-slf4j, log4j-over-slf4j, jul-to-slf4j bridge.

Logovací rozhraní

Simple Logging Facade for Java (SLF4J) [1]

Definuje úrovně ALL, TRACE, DEBUG, INFO, WARN, ERROR, FATAL, OFF, viz třída Level.

Použití

 
public class PbsCacheImpl implements PbsCache {
 
    final static Logger log = LoggerFactory.getLogger(PbsCacheImpl.class);
 //...
 
  // u jednoduchých výpisů stačí uvést řetězec a argumenty pro nahrazení
  log.debug("Server {} má {} položek",server,numItems);
 
  //u složitějších výpisů je vhodné předřadit if, aby se argumenty zbytečně nevyhodnocovaly
  if(log.isDebugEnabled()) {
     log.debug("Měla "+babka+" "+babkaPocetJablek+" a dědoušek jen "+dedaPocetJablek);
  }
 
  // u vyjímek pak
   try {
     //...
   } catch(Exception ex) {
     log.error("Houstone, máme problém",ex);
   }

Pokud používáte projekt typu Maven, přidáte knihovnu SLF4J rozhraní přidáním této závislosti:

 
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>1.7.2</version>
</dependency>

nebo u spustitelného projektu se můžete spolehnout na to, že tranzitivními závislostmi bude SLF4J přidán automaticky, např. přidáním Logback:

 
<dependency> 
  <groupId>ch.qos.logback</groupId>
  <artifactId>logback-classic</artifactId>
  <version>1.0.7</version>
</dependency>

Jakarta Commons Logging (JCL) [2]

U nových projektů není doporučeno používat.

Implementace logování

Log4j (LS) [3]

  • velmi komplexní a robustní logovací knihovna
  • umí vše co JUL a něco navíc
  • defacto standard logování J2EE aplikací
  • nyní součástí http://logging.apache.org/, existuje k němu prohlížeč logů Chainsaw
  • úrovně (třída Level) ALL, TRACE, DEBUG, INFO, WARN, ERROR, FATAL, OFF
  • handlery pro logování na konzolu, do souboru, do databáze, přes JMS, do syslogu, emailem a další

Pro správnou funkci je třeba mít v CLASSPATH soubor jménem log4j.xml s konfigurací, např.:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration xmlns:log4j='http://jakarta.apache.org/log4j/'>
    <!-- appender určuje, kam se bude logovat, v tomto případě na konzolu -->
    <appender name="STDOUT" class="org.apache.log4j.ConsoleAppender">
        <layout class="org.apache.log4j.PatternLayout">
            <param name="ConversionPattern" value="%d [%t] %-5p %c - %m%n"/>
        </layout>
    </appender>
    <!-- tento appender loguje do denně rotovaného souboru  v adresáři určeném obsahem systémové property catalina.base-->
    <appender name="roll" class="org.apache.log4j.DailyRollingFileAppender">
        <param name="File" value="${catalina.base}/logs/pbsmon2.log4j"/>
        <param name="DatePattern" value=".yyyy-MM-dd"/>
        <layout class="org.apache.log4j.PatternLayout">
            <param name="ConversionPattern" value="%d [%t] %-5p %c - %m%n"/>
        </layout>
    </appender>
    <!-- category určuje úroveň logování pro třídy v určitém package -->
    <category name="org.apache.log4j.xml">
        <priority value="info"/>
    </category>
    <category name="net.sourceforge.stripes">
            <priority value="info"/>
    </category>
    <category name="cz.muni.fi.pa165.cv5">
            <priority value="debug"/>
    </category>
    <!-- root definuej hlavní konfiguraci, tedy které z appenderů se mají použít -->
    <root>
        <priority value="info"/>
        <appender-ref ref="STDOUT"/>
    </root>
</log4j:configuration>


java.util.logging (JUL) [4]

  • ve standardním API od JDK 1.4
  • třída Logger (instance mají asociované jméno, jehož základ by měl tvořit název balíku, protože je na něm postavena hierarchie Loggerů)
  • Úrovně (instance třídy Level) ALL, FINEST, FINER, FINE, CONFIG, INFO, WARNING, SEVERE, OFF
  • Možnost implementace vlastního Filteru
  • Připravené handlery pro paměť, OutputStream, soubor (včetně rotování), konzolu, IP socket (i více najednou)
  • Připravené textové a XML formátování
  • Podpora lokalizovaných zpráv přebíraných z ResourceBundle
  • LogManager spravující všechny Loggery a jejich konfiguraci

Když neprovedu žádnou konfiguraci, JUL loguje od úrovně INFO na konzolu pomocí SimpleFormatter, protože to je konfigurace v souboru $JAVA_HOME/lib/logging.properties.

Pokud to chci změnit, musím vyrobit soubor logging.properties s obsahem alespoň

#vypis pujde na konzolu
handlers=java.util.logging.ConsoleHandler
# handler propusti vsechno od finest
java.util.logging.ConsoleHandler.level=FINEST
# loggery propusti vsechno od finest
.level= FINEST
#
#java.util.logging.ConsoleHandler.formatter=java.util.logging.SimpleFormatter
#java.util.logging.ConsoleHandler.formatter=java.util.logging.XMLFormatter

a při spuštění specifikovat jeho místo:

java -Djava.util.logging.config.file=/home/nekdo/nekde/logging.properties