2.1 Första logger - log4j

Som du redan vet började loggarnas historia med System.err.println()utmatningen av en post till konsolen. Den används fortfarande aktivt för felsökning, till exempel använder Intellij IDEA den för att visa felmeddelanden till konsolen. Men det här alternativet har inga inställningar, så låt oss gå vidare.

Den första och mest populära loggern hette Log4j. Det var en bra och mycket anpassningsbar lösning. På grund av olika omständigheter kom detta beslut aldrig in i JDK, vilket upprörde hela samhället kraftigt.

Denna logger kunde inte bara logga, den skapades av programmerare för programmerare och gjorde att de kunde lösa problem som hela tiden uppstod i samband med loggning.

Som du redan vet skrivs loggar i slutet så att någon person läser dem och försöker förstå vad som hände under programmets drift - vad och när gick fel som förväntat.

Det log4jfanns tre saker för detta:

  • loggning av underpaket;
  • uppsättning bilagor (resultat);
  • hot reload-inställningar.

För det första kan inställningarna log4jskrivas på ett sådant sätt att de möjliggör inloggning i ett paket och inaktiverar det i ett annat. Det var till exempel möjligt att aktivera inloggning i , com.codegym.servermen inaktivera den i com.codegym.server.payment. Detta gjorde det möjligt att snabbt ta bort onödig information från loggen.

För det andra log4jtillät det att skriva loggningsresultat till flera loggfiler samtidigt. Och utgången till var och en kan konfigureras individuellt. Till exempel, i en fil var det möjligt att bara skriva information om allvarliga fel, i en annan - loggar från en specifik modul och i en tredje - loggar för en viss tid.

Varje loggfil anpassades således till en viss typ av förväntat problem. Detta förenklar livet avsevärt för programmerare som inte gillar att titta igenom gigabyteloggfiler manuellt.

Och slutligen, för det tredje, log4jtillät det att ändra logginställningarna direkt medan programmet kördes, utan att starta om det. Detta var mycket praktiskt när det var nödvändigt att korrigera arbetet med loggarna för att hitta ytterligare information om ett specifikt fel.

Viktig! Det finns två versioner av loggen log4j: 1.2.x och 2.xx , som är inkompatibla med varandra .

Du kan ansluta loggern till projektet med koden:

<dependencies>
  <dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-api</artifactId>
    <version>2.17.2</version>
  </dependency>
 
  <dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-core</artifactId>
    <version>2.17.2</version>
  </dependency>
</dependencies>

2.2 Första officiella logger - JUL: java.util.logging

Efter att djurparken av loggare dök upp i Java-communityt bestämde sig utvecklarna JDKför att göra en standardlogger som alla skulle använda. Så här såg logger ut JUL: paket java.util.logging.

Men under dess utveckling tog skaparna av loggern som grund inte , log4jutan en variant av loggern från IBM, vilket påverkade dess utveckling. Den goda nyheten är att loggern JULingår JDK, de dåliga är att få människor använder den.

JUL

Utvecklarna JULgjorde inte bara "en annan universell standard" , de gjorde också sina egna loggningsnivåer för den, som skilde sig från de som accepterades av populära loggare vid den tiden.

Och det var ett stort problem. När allt kommer omkring samlas produkter Javaofta in från ett stort antal bibliotek, och varje sådant bibliotek hade sin egen logger. Så det var nödvändigt att konfigurera alla loggare som finns i applikationen.

Även om själva loggern är ganska bra. Att skapa en logger är mer eller mindre detsamma. För att göra detta måste du importera:


java.util.logging.Logger log = java.util.logging.Logger.getLogger(LoggingJul.class.getName());

Klassnamnet skickas speciellt för att veta var loggningen kommer ifrån.

Först med releasen löste utvecklarna viktiga problem, varefter det JULär riktigt bekvämt att använda. Innan dess var det någon sorts andra klassens logger.

Denna logger stöder även lambda-uttryck och lat utvärdering. Från och med Java 8, kan du passera Supplier<String>. Detta hjälper till att läsa och skapa en sträng endast i det ögonblick när det verkligen behövs, och inte varje gång, som det var tidigare.

Metoder med ett argument Supplier<String> msgSupplierser ut så här:

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

2.3 First logger wrapper - JCL: jakarta commons logging

Länge fanns det ingen enskild standard bland loggare, den JULborde ha blivit en, men det var värre, log4jså en enda standard dök aldrig upp. Men en hel djurpark av skogshuggare dök upp, som var och en ville bli densamma.

JCL

Men vanliga Java-utvecklare gillade inte att nästan varje bibliotek har sin egen logger och måste konfigureras på något sätt på ett speciellt sätt. Därför beslutade samhället att skapa ett speciellt omslag över andra loggare - så härJCL: jakarta commons logging

Och återigen, projektet, som skapades för att vara ledare, blev inte ett. Du kan inte skapa en vinnare, du kan bara bli en vinnare. Funktionaliteten JCLvar mycket dålig och ingen ville använda den. Loggern, designad för att ersätta alla loggare, gick samma öde till mötes eftersom den JULinte användes.

Även om det har lagts till i många bibliotek som släppts av Apache-gemenskapen, har skogshuggarparken bara växt.

2.4 Första sista loggeren - Logga tillbaka

Men det är inte allt. Utvecklaren log4jbestämde sig för att han var smartast (nåja, de flesta använde trots allt hans logger) och bestämde sig för att skriva en ny förbättrad logger som skulle kombinera fördelarna med log4jandra loggers.

Den nya loggern hette Logback. Det var denna logger som var tänkt att bli den framtida singelloggaren som alla skulle använda. Den baserades på samma idé som i log4j.

Du kan ansluta denna logger till projektet med koden:


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

Skillnaderna låg i Logback:

  • förbättrad prestanda;
  • lagt till inbyggt stöd slf4j;
  • utökat filtreringsalternativ.

En annan fördel med denna logger var att den hade mycket bra standardinställningar. Och du var tvungen att konfigurera loggern bara om du ville ändra något i dem. Inställningsfilen var också bättre anpassad till företagets programvara - alla dess konfigurationer var inställda som xml/.

Som standard Logbackkräver den inga inställningar och registrerar alla loggar från nivån DEBUGoch uppåt. Om du behöver ett annat beteende kan det konfigureras via xmlkonfiguration:

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

2.5 Senaste universella logger - SLF4J: Simple Logging Facade för Java

Hur lång tid kan det vara att hitta den gyllene medelvägen...

2006 lämnade en av skaparna log4jprojektet och bestämde sig för att försöka igen för att skapa en universell logger. Men den här gången var det inte en ny logger, utan en ny universell standard (omslag) som gjorde att olika loggare kunde interagera tillsammans.

Denna logger hette slf4j — Simple Logging Facade for Java, det var ett omslag runt log4j, JUL, common-loggins and logback. Denna loggare löste ett verkligt problem - att hantera en djurpark av skogshuggare, så alla började genast använda den.

Vi löser heroiskt de problem vi skapar för oss själva. Som du kan se har framstegen nått den punkt att vi har skapat ett omslag över omslaget ...

Själva omslaget består av två delar:

  • API, som används i applikationer;
  • Implementeringar som läggs till som separata beroenden för varje logger.

Du kan ansluta loggern till projektet med koden:

<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-api</artifactId>
    <version>2.17.2</version>
</dependency>
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-core</artifactId>
    <version>2.17.2</version>
</dependency>
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-slf4j-impl</artifactId>
    <version>2.17.2</version>
</dependency>

Det räcker med att ansluta den korrekta implementeringen och det är det: hela projektet kommer att arbeta med det.

2.6 Optimering i slf4j

Slf4jstöder alla nya funktioner som strängformatering för loggning . Innan detta fanns ett sådant problem. Låt oss säga att du vill skriva ut ett meddelande till loggen:

log.debug("User " + user + " connected from " + request.getRemoteAddr());

Det finns ett problem med den här koden. Anta att din applikation fungerar på productionoch inte skriver något till loggen, DEBUG-messagesmen metoden log.debug()kommer fortfarande att anropas, och när den anropas kommer följande metoder också att anropas:

  • user.toString();
  • request.getRemoteAddr();

Att anropa dessa metoder saktar ner applikationen. Deras anrop behövs bara under felsökning, men de anropas ändå.

Ur logisk synvinkel måste detta problem lösas i själva loggningsbiblioteket. Och i den första versionen av log4j kom lösningen upp:

if (log.isDebugEnabled()) {
    log.debug("User " + user + " connected from " + request.getRemoteAddr());
}

Istället för en rad för loggen var det nu nödvändigt att skriva tre. Vilket dramatiskt försämrade läsbarheten för koden och sänkte populariteten för log4j.

Loggaren slf4jkunde förbättra situationen något genom att erbjuda smart loggning. Det såg ut så här:

log.debug("User {} connected from {}", user, request.getRemoteAddr());

där {}betecknar infogningen av argument som skickas i metoden. Det vill säga, den första {}motsvarar användaren, den andra {}motsvarar request.getRemoteAddr().

Dessa parametrar kommer att sammanfogas till ett enda meddelande endast om loggningsnivån tillåter loggning. Inte perfekt, men bättre än alla andra alternativ.

Efter det SLF4Jbörjade det växa snabbt i popularitet, för tillfället är detta den bästa lösningen.

Därför kommer vi att överväga att logga med exemplet med en bunt slf4j-log4j12.