CodeGym /Java blog /Tilfældig /Logning: hvad, hvordan, hvor og med hvad?
John Squirrels
Niveau
San Francisco

Logning: hvad, hvordan, hvor og med hvad?

Udgivet i gruppen
Hej alle i CodeGym-fællesskabet! Logning: hvad, hvordan, hvor og med hvad?  - 1 Lad os i dag tale om logning:
  1. Hvad det er, hvorfor det eksisterer, hvornår du skal bruge det, hvornår du bør undgå det.
  2. Hvilke logningsimplementeringer er tilgængelige i Java, og hvad du skal gøre med alle disse logningsmuligheder.
  3. Og log niveauer. Vi vil diskutere, hvad appender er, og hvordan man konfigurerer det korrekt.
  4. Logning af noder og hvordan man konfigurerer dem korrekt, så alt fungerer som vi ønsker.
Dette materiale er beregnet til et bredt publikum. Det vil være klart for enhver, der bare lærer Java at kende, såvel som folk, der allerede arbejder, men kun har udforsket logger.info("log something"); Let's go!

Hvorfor har du brug for logning?

Lad os se på nogle virkelige tilfælde, hvor logning kan løse et problem. Her er et eksempel fra mit arbejde. Der er punkter, hvor en applikation integreres med andre tjenester. Jeg bruger logning på disse punkter til at etablere en slags "alibi" : hvis integrationen ikke virker, så bliver det nemt at finde ud af, hvilken side der har problemet. Det er også ønskeligt at logge vigtige oplysninger, der er gemt i en database. For eksempel oprettelsen af ​​en admin-bruger. Det er netop den slags ting, der ville være godt at logge.

Værktøjer til at logge på Java

Blandt de velkendte logningsløsninger i Java kan vi fremhæve følgende:
  • Log4j
  • JUL — java.util.logging
  • JCL — Jakarta Commons Logning
  • Log tilbage
  • SLF4J — Simple Logging Facade til Java
Vi vil give et overblik over hver af dem. Så tager vi en slf4j - log4j binding som grundlag for en praktisk diskussion. Dette kan virke mærkeligt nu, men bare rolig: i slutningen af ​​artiklen vil alt være klart.

System.err.println

I begyndelsen var der System.err.println (viser logposter på konsollen). Selv i dag bruges denne teknik til hurtigt at lave en log ved fejlretning. Selvfølgelig er der ingen indstillinger at diskutere her, så husk bare denne metode, så går vi videre.

Log4j

Dette er en komplet løsning, som udviklere har skabt af nødvendighed. Resultatet er et virkelig interessant værktøj, som du kan bruge. På grund af forskellige omstændigheder endte denne løsning ikke i JDK, hvilket i høj grad forstyrrede hele samfundet. Log4j har konfigurationsmuligheder, der lader dig aktivere logning af com.example.typepakken og slå den fra i com.example.type.genericunderpakken. Dette gør det muligt hurtigt at udelukke kode, der ikke skal logges. Det er vigtigt at bemærke her, at der er to versioner af Log4j: 1.2.x og 2.xx, og de er inkompatible med hinanden . Log4j tilføjede begreberne appender(et værktøj, der bruges til at skrive logfiler) og layout (logformatering). Dette lader dig kun logge det, du har brug for, og logge det lige, som du har brug for det. Vi vil tale mere om appender lidt senere.

JUL — java.util.logging

En af de vigtigste fordele ved denne løsning er, at JUL er inkluderet i JDK (Java Development Kit). Desværre, da det blev udviklet, baserede dets skabere det ikke på det populære Log4j-værktøj, men snarere en løsning fra IBM. Den beslutning har fået konsekvenser. Virkeligheden er, at ingen bruger JUL nu. Logniveauerne i JUL adskiller sig fra hvad Logback, Log4j og Slf4j har. Det gør det sværere for dem at forstå hinanden. At oprette en logger er mere eller mindre ens. For at gøre dette skal du lave en import:

java.util.logging.Logger log = java.util.logging.Logger.getLogger(LoggingJul.class.getName());
Klassenavnet er bestået, så vi ved, hvor vores logning kommer fra. Fra og med Java 8 kan du bestå Supplier<String>. Dette hjælper os med at læse og oprette en linje kun, når vi virkelig har brug for det, snarere end hver gang, som det tidligere var tilfældet. Først med udgivelsen af ​​Java 8 løste udviklere endelig vigtige problemer og gjorde JUL virkelig brugbar. Nemlig metoder med en Supplier<String> msgSupplierparameter, som vist nedenfor:

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

JCL — Jakarta Commons Logning

Fordi der ikke var nogen industristandard for logning i lang tid, og mange mennesker skabte deres egne brugerdefinerede loggere, blev det besluttet at frigive JCL, en generel indpakning, der kunne bruges oven på andre. Hvorfor? Nogle gange brugte afhængigheder tilføjet til projektet en anden logger end den i projektet. På grund af dette blev de føjet til projektet som transitive afhængigheder, og det skabte reelle problemer, når man forsøgte at sætte det hele sammen. Desværre var indpakningen ikke særlig funktionel og tilføjede ikke noget. Det ville nok være praktisk, hvis alle brugte JCL. Men det er ikke, hvad der skete, så at bruge JCL er ikke den bedste idé i øjeblikket.

Log tilbage

Open source-stien er tornet... Den samme udvikler, der skrev Log4j, skrev også Logback som en efterfølgende logningsramme. Det var baseret på samme idé som Log4j. Forskellene i Logback er:
  • forbedret ydeevne
  • tilføjet native support til Slf4j
  • udvidede filtreringsmuligheder
Som standard kræver Logback ingen konfiguration og registrerer alle hændelser på DEBUG-niveau og højere. Hvis du har brug for tilpasning, kan du opnå det gennem en XML-konfiguration:

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

SLF4J — Simple Logging Facade til Java

Engang i 2006 forlod en af ​​Log4js grundlæggere projektet og skabte Slf4j (Simple Logging Facade for Java), en indpakning til Log4j, JUL, common-logging og Logback. Som du kan se, er vi avanceret til det punkt, hvor vi laver en wrapper over en wrapper... I dette tilfælde er den opdelt i to dele: En API, der bruges i applikationen, og en implementering, der tilføjes med separat afhængigheder for hver type logning. For eksempel slf4j-log4j12.jarog slf4j-jdk14.jar. Du skal tilslutte den korrekte implementering, og det er det: hele dit projekt vil bruge den. Slf4j understøtter alle de nyeste funktioner, såsom formatering af strenge til logning. Tidligere var der et sådant problem. Lad os sige, at vi opretter en logpost som denne:

log.debug("User " + user + " connected from " + request.getRemoteAddr());
På grund af sammenkædningsoperatoren userbliver objektet lydløst til en streng takket være user.toString(). Dette tager tid og bremser systemet. Og det kan være OK, hvis vi fejlretter applikationen. Vi begynder at støde på problemer, hvis logniveauet for denne klasse er INFO eller højere. Med andre ord, vi bør ikke skrive denne logindgang (til INFO eller højere), og vi bør ikke bruge strengsammenkædning. I teorien burde logningsbiblioteket selv adressere dette. Som det sker, viste dette sig at være det største problem i den første version af Log4j. Det leverede ikke en anstændig løsning, men foreslog i stedet at gøre noget som dette:

if (log.isDebugEnabled()) {
    log.debug("User " + user + " connected from " + request.getRemoteAddr());
}
Det vil sige, i stedet for én linje kode til logning, foreslog de at skrive 3! Logning bør minimere kodeændringer, og de tre linjer overtræder klart denne generelle tilgang. Slf4j havde ingen kompatibilitetsproblemer med JDK og API, så en god løsning dukkede straks op:

log.debug("User {} connected from {}", user, request.getRemoteAddr());
hvor {}angiver pladsholdere for de argumenter, der overføres til metoden. Det vil sige, at den første {}svarer til user, og den anden {}svarer til request.getRemoteAddr(). Ved at gøre det på denne måde vil vi kun udføre strengsammenkædning, hvis logniveauet kræver, at vi skriver logindgangen. Derefter begyndte Sjf4j hurtigt at vokse i popularitet. På nuværende tidspunkt er det den bedste løsning. Lad os derfor tage et kig på logning ved hjælp af en slf4j-log4j12binding.

Hvad skal logges

Du skal selvfølgelig ikke logge alt. Dette er ofte ikke nødvendigt og nogle gange endda farligt. For eksempel, hvis du logger en persons personlige data, og det på en eller anden måde bliver lækket, vil der være reelle problemer, især i projekter med fokus på vestlige markeder. Men der er også ting, du helt sikkert bør logge :
  1. Start/slut af ansøgningen. Vi skal vide, om ansøgningen virkelig startede og endte som forventet.
  2. Sikkerhedsproblemer. Her ville det være godt at logge forsøg på at gætte nogens adgangskode, tilfælde hvor administratorer logger ind osv.
  3. Visse ansøgning angiver . For eksempel overgangen fra en tilstand til en anden i en forretningsproces.
  4. Visse fejlfindingsoplysninger sammen med det tilsvarende logniveau.
  5. Visse SQL-scripts. Der er tilfælde i den virkelige verden, hvor dette er nødvendigt. Men igen, ved dygtigt at justere logniveauerne, kan du opnå fremragende resultater.
  6. Løbende tråde kan logges, når det kontrolleres, at tingene fungerer korrekt.

Populære fejl i logning

Der er mange nuancer her, men vi vil især nævne nogle få almindelige fejl:
  1. Overdreven logning. Du bør ikke logge hvert trin, der teoretisk set kan være vigtigt. Her er en god tommelfingerregel: Logs bør ikke overstige 10% af belastningen. Ellers vil der være præstationsproblemer.
  2. Logning af alle data i én fil. På et tidspunkt vil dette gøre det meget vanskeligt at læse/skrive loggen, for ikke at nævne det faktum, at visse systemer har grænser for filstørrelse.
  3. Brug af forkerte logniveauer. Hvert logniveau har klare grænser, og de bør respekteres. Hvis en grænse er uklar, kan I blive enige om, hvilket niveau der skal bruges.

Log niveauer

x: Synlig
FATAL FEJL ADVARE INFO FEJLFINDE SPOR ALLE
AF
FATAL x
FEJL x x
ADVARE x x x
INFO x x x x
FEJLFINDE x x x x x
SPOR x x x x x x
ALLE x x x x x x x
Hvad er logniveauer? For på en eller anden måde at skabe et hierarki af logposter er visse konventioner og afgrænsninger nødvendige. Det er grunden til, at logniveauer blev indført. Niveauet indstilles i applikationen. Hvis en post er under et specificeret niveau, bliver den ikke logget. For eksempel har vi logfiler, som vi bruger, når vi fejlretter applikationen. Under normal drift (når applikationen bruges til dets tilsigtede formål), er sådanne logfiler ikke nødvendige. Derfor er logniveauet højere end for fejlretning. Lad os se på logniveauer ved hjælp af Log4j. Bortset fra JUL bruger andre løsninger de samme logniveauer. Her er de i faldende rækkefølge:
  • FRA: Ingen logposter registreres; alt ignoreres.
  • FATAL: En fejl, der forhindrer programmet i at fortsætte med at køre. For eksempel "JVM fuld af hukommelsesfejl".
  • FEJL: Fejl på dette niveau indikerer problemer, der skal løses. Fejlen stopper ikke applikationen som helhed. Andre anmodninger fungerer muligvis korrekt.
  • ADVARSEL: Logposter, der repræsenterer en advarsel. Der skete noget uventet, men systemet var i stand til at klare det og opfyldte anmodningen
  • INFO: Logposter, der angiver vigtige handlinger i applikationen. Disse er ikke fejl eller advarsler. De er forventede systemhændelser.
  • DEBUG: Logposter skal bruges til at fejlfinde applikationen. For at sikre, at applikationen gør nøjagtigt, hvad der forventes, eller for at beskrive de handlinger, applikationen foretager, dvs. "Entered method1".
  • TRACE: Logposter med lavere prioritet til fejlretning. Det laveste logniveau.
  • ALL: Et logniveau til at skrive alle applikationens logposter.
I INFO log niveau er aktiveret et sted i applikationen, så vil indtastningerne for hvert niveau blive logget, fra INFO til FATAL. Hvis FATAL-logniveauet er indstillet, vil kun logposter med det niveau blive skrevet.

Logning og afsendelse af logs: Appender

Lad os overveje, hvordan alt dette fungerer, når vi bruger Log4j, som giver rigelige muligheder for at skrive/sende logfiler:
  • at skrive til en fil -DailyRollingFileAppender
  • at skrive information til konsollen —ConsoleAppender
  • at skrive logfiler til en database —JDBCAppender
  • at administrere afsendelseslogfiler over TCP/IP —TelnetAppender
  • for at sikre, at logning ikke påvirker ydeevnen negativt —AsyncAppender
Der er et par flere implementeringer: en komplet liste er tilgængelig her . Forresten, hvis den appender du skal bruge ikke findes, er det ikke noget problem. Du kan skrive din egen appender ved at implementere Appender- grænsefladen, som Log4j understøtter.

Logning af noder

Til demonstrationsformål vil vi bruge en Slf4j interface, med en implementering fra Log4j. Oprettelse af en logger er meget enkel: i en klasse ved navn MainDemo, som vil udføre noget logning, skal vi tilføje følgende:

org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(MainDemo.class);
Dette vil oprette en logger for os. For at lave en logindtastning er der flere tilgængelige metoder, hvis navne afspejler hvilket logniveau der vil blive brugt. For eksempel:

logger.trace("Method 1 started with argument={}", argument);
logger.debug("Database updated with script = {}", script);
logger.info("Application has started on port = {}", port);
logger.warn("Log4j didn't find the log4j.properties file. Please fix this.");
logger.error("Connection refused to host = {}", host);
Selvom vi består klassen, er det endelige navn klassens fulde navn, inklusive pakker. Dette gøres, så du senere kan opdele logningen i noder og konfigurere logningsniveauet og appenderen for hver node. For eksempel blev loggeren oprettet i com.github.romankh3.logginglecture.MainDemoklassen. Navnet danner grundlaget for at skabe et hierarki af logningsnoder. Hovedknuden er RootLogger på topniveau . Dette er den node, der modtager alle logposter for hele applikationen. De resterende knudepunkter kan afbildes som vist nedenfor: Logning: hvad, hvordan, hvor og med hvad?  - 3Appendere er konfigureret til specifikke logningsnoder. Nu skal vi se på log4j.properties- filen for at se et eksempel på, hvordan man konfigurerer dem.

En trin-for-trin guide til filen log4j.properties

Vi sætter alt op et trin ad gangen og ser, hvad der er muligt:

log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
Denne linje siger, at vi registrerer CONSOLE-appenderen, som bruger org.apache.log4j.ConsoleAppender-implementeringen. Denne appender skriver information til konsollen. Dernæst registrerer vi en anden appender. Denne vil skrive til en fil:

log4j.appender.FILE=org.apache.log4j.RollingFileAppender
Det er vigtigt at bemærke, at selve appenderne stadig skal konfigureres. Når vi har registreret vores appenders, kan vi bestemme hvilke logniveauer og hvilke appenders der skal bruges ved noderne.

log4j.rootLogger=DEBUG, KONSOL, FIL

  • log4j.rootLogger betyder, at vi er ved at konfigurere rodnoden, som indeholder alle logposter
  • Det første ord efter lighedstegnet angiver det mindste logniveau, der skal skrives (i vores tilfælde er det DEBUG)
  • Efter kommaet angiver vi alle de bilag, der skal bruges.
For at konfigurere en mere specifik logning node, ville du bruge en post som denne:

log4j.logger.com.github.romankh3.logginglecture=TRACE, OWN, CONSOLE
hvor log4j.logger.bruges til at referere til en specifik node. I vores tilfælde, com.github.romankh3.logginglecture. lad os nu tale om at konfigurere CONSOLE-appenderen:

# CONSOLE appender customization
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.threshold=DEBUG
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=[%-5p] : %c:%L : %m%n
Her ser vi, at det er muligt at indstille det specifikke niveau, som appenderen skal begynde at virke på. Her er et eksempel på, hvad der rent faktisk sker: antag, at en meddelelse med INFO-niveauet modtages af logningsnoden og sendes til den tilknyttede tilknyttede meddelelse. Hvis appenderens tærskel er sat til WARN, modtager den logindtastningen, men gør intet med den. Dernæst skal vi beslutte, hvilket layout meddelelsen vil bruge. Jeg bruger PatternLayout i eksemplet, men der er mange andre muligheder. Vi vil ikke dække dem i denne artikel. Eksempel på konfiguration af FILE-appenderen:

# File appender customization
log4j.appender.FILE=org.apache.log4j.RollingFileAppender
log4j.appender.FILE.File=./target/logging/logging.log
log4j.appender.FILE.MaxFileSize=1MB
log4j.appender.FILE.threshold=DEBUG
log4j.appender.FILE.MaxBackupIndex=2
log4j.appender.FILE.layout=org.apache.log4j.PatternLayout
log4j.appender.FILE.layout.ConversionPattern=[ %-5p] - %c:%L - %m%n
Du kan konfigurere den specifikke fil, som logposter vil blive skrevet til, som det kan ses på denne linje:

log4j.appender.FILE.File=./target/logging/logging.log
Indtastningen skrives til logging.logfilen. For at undgå problemer med filstørrelsen kan du konfigurere den maksimale, som i dette tilfælde er 1MB. MaxBackupIndexangiver, hvor mange sådanne logfiler der vil være. Hvis vi skal oprette flere filer end dette, vil den første fil blive slettet. For at se på et rigtigt eksempel, hvor logning er konfigureret, kan du gå til det offentlige repository på GitHub.

Forstærk det, vi har diskuteret

Prøv på egen hånd at gøre alt, hvad vi har beskrevet:
  • Opret dit eget projekt, der ligner vores eksempel ovenfor.
  • Hvis du ved, hvordan du bruger Maven, så brug det. Hvis ikke, så læs denne vejledning, som beskriver, hvordan du forbinder biblioteket.

Sammenfattende

  1. Vi talte om de logningsløsninger, der findes i Java.
  2. Næsten alle de kendte logbiblioteker er skrevet af én person :D
  3. Vi lærte, hvad der skal og ikke skal logges.
  4. Vi fandt ud af logniveauer.
  5. Vi blev introduceret til logning noder.
  6. Vi kiggede på, hvad en appender er, og hvad den er til.
  7. Vi oprettede en log4j.proterties-fil trin for trin.

Yderligere materialer

  1. CodeGym: Logger lektion
  2. Weekly Geekly: Java-logning. Hej Verden
  3. Kodningsrædsel: Problemet med at logge
  4. YouTube: Understanding Java Logging Hell - The Basics. Java-logning helvede og hvordan man holder sig ude af det
  5. Log4j: Appender
  6. Log4j: Layout
Se også min anden artikel:
Kommentarer
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION