"Åh, där är du! Minns du att vi har en lektion till idag?"

"Nej, jag letade bara efter dig. Nästan..."

"Utmärkt, då börjar vi. Idag vill jag berätta om loggning."

"Loggen är en lista över de händelser som har inträffat. Nästan som en fartygslogg eller en dagbok. Eller Twitter - det kanske du kan relatera bättre till. Inte överraskande nog är en logger ett objekt som du använder för loggning."

"Inom programmering är det vanligt att logga nästan allt. Och i Java loggar vi allt och till och med lite till."

"Faktum är att Java-program väldigt ofta är stora serverapplikationer utan användargränssnitt, konsol etc. De behandlar tusentals användarförfrågningar samtidigt och det finns ofta olika fel. Speciellt när olika trådar börjar störa varandra."

"Faktum är att det enda sättet att söka efter sällan reproducerbara buggar och misslyckanden under dessa omständigheter är att logga allt som händer på varje tråd."

"Oftast innehåller loggen information om metodargument, eventuella fångade fel och en hel del mellanliggande information."

"Ju mer komplett loggen, desto lättare är det att återskapa en händelsesekvens och spåra orsakerna till fel eller buggar."

"Ibland når loggar flera gigabyte per dag. Detta är normalt."

"Några gigabyte? O_o"

"Japp. Oftast arkiveras loggfiler automatiskt, med en indikation på relevant datum."

"Oj."

"Uh-huh. Från början hade Java ingen egen logger. Som ett resultat skrevs flera oberoende loggare. Den vanligaste av dessa var log4j."

"Några år senare fick Java en egen logger, men dess funktionalitet var mycket sämre och den användes inte särskilt mycket."

"Det är ett faktum att Java har en officiell logger, men hela gemenskapen av Java-programmerare föredrar att använda andra loggare. "

"Senare skrevs flera loggers baserade på log4j."

"Då skrevs den speciella universella loggern slf4j, som nu används flitigt, för dem alla. Den är väldigt lik log4j, så jag ska använda den som ett exempel när jag förklarar loggning."

"Hela loggningsprocessen består av tre delar."

" Först , samla in information."

" För det andra , filtrera den insamlade informationen."

" För det tredje , spela in den valda informationen."

"Låt oss börja med insamling. Här är ett typiskt exempel på en klass som loggar:"

Klass med loggning
class Manager
{
 private static final Logger logger = LoggerFactory.getLogger(Manager.class);

 public boolean processTask(Task task)
 {
  logger.debug("processTask id = " + task.getId());
  try
  {
   task.start();
   task.progress();
   task.complete();
   return true;
  }
  catch(Exception e)
  {
   logger.error("Unknown error", e);
   return false;
  }
 }
}

"Var uppmärksam på orden markerade i rött."

" Rad 3  – Skapa loggerobjektet . Ett sådant statiskt objekt skapas i nästan varje klass! Tja, förutom klasser som inte gör något annat än att lagra data."

" LoggerFactory är en specialklass för att skapa loggare, och getLogger är en av dess statiska metoder. Det aktuella objektet skickas vanligtvis, men olika alternativ är möjliga."

" Rad 7 – Information om metodanropet skrivs till loggern. Observera att detta är den första raden i metoden. Så fort metoden anropas skriver vi omedelbart information till loggen."

"Vi kallar felsökningsmetoden, vilket betyder att informationens betydelse är DEBUG-nivå. Detta används för filtrering. Jag ska berätta om det om ett par minuter."

" Linje 17 – Vi fångar ett undantag och... skriver det omedelbart till loggen! Det här är precis vad som måste göras."

"Den här gången anropar vi felmetoden, som omedelbart indikerar att informationen är på FEL-nivå"

Logger - 1

"Allt verkar klart för tillfället. Tja, så långt det kan vara klart mitt i vårt samtal."

"Bra, låt oss sedan gå vidare till meddelandefiltrering."

"Vanligtvis har varje loggmeddelande sin egen betydelsenivå, som du kan använda för att kassera några av meddelandena. Här är betydelsenivåer jag nämnde:"

Viktighetsnivå Beskrivning
ALLT Alla meddelanden
SPÅR Finkorniga felsökningsmeddelanden
DEBUGA Viktiga felsökningsmeddelanden
INFO Informationsmeddelanden
VARNA Varningar
FEL Fel
DÖDLIG Fatala fel
AV Inga meddelanden

Dessa nivåer används också vid filtrering av meddelanden.

Anta att du ställer in loggningsnivån till VARNA. Då kommer alla meddelanden som är mindre viktiga än WARN att kasseras: TRACE, DEBUG, INFO.

Om du ställer in filtreringsnivån till FATAL, kommer även ERROR-meddelanden att förkastas.

"Det finns ytterligare två betydelsenivåer som används vid filtrering: AV, som kasserar alla meddelanden; och ALL, som visar alla meddelanden (ingenting kasseras)."

"Hur och var ställer jag in filtrering?"

"Jag ska berätta för dig utan vidare."

"Vanligtvis anges log4j-loggerinställningar i filen log4j.properties."

Du kan ange flera tilläggsobjekt i den här filen. Data skrivs till dessa objekt. Det finns datakällor och det finns bilagor - objekt som har motsatta syften. Objekt som data rinner in i som vatten.

"Här är några exempel:"

Loggar till konsolen
# Root logger option
log4j.rootLogger = INFO, stdout

# Direct log messages to stdout
log4j.appender.stdout = org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target = System.out
log4j.appender.stdout.layout = org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern = %d{yyyy-MM-dd HH:mm:ss}

Rad 1 och 4 – Det här är kommentarer

Rad 2 – Vi anger vilken loggningsnivå vi vill ha. Alla mindre viktiga nivåer (DEBUG, TRACE) kommer att kasseras.

På samma ställe lägger vi till ett kommatecken och anger sedan namnet på objektet (som vi själva kommer på) som loggen ska skrivas till. Raderna 5-9 innehåller dess inställningar.

Rad 5 – Vi anger typen av tillägg ( ConsoleAppender ).

Rad 6 – Vi anger exakt var vi skriver ( System.out. ).

Rad 7 – Vi anger klassen som ska hantera konverteringsmönster (PatternLayout).

Rad 8 – Vi anger det konverteringsmönster som ska användas för att skriva. I exemplet ovan är det datum och tid.

"Och så här ser det ut att skriva till en fil:"

Loggar till en fil
# Root logger option
log4j.rootLogger = INFO, file

# Direct log messages to a log file
log4j.appender.file = org.apache.log4j.RollingFileAppender
log4j.appender.file.File = C:\\loging.log
log4j.appender.file.MaxFileSize = 1MB
log4j.appender.file.MaxBackupIndex = 1
log4j.appender.file.layout = org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern = %-5p %c{1}:%L - %m%n

"Rad 2 ställer in meddelandefiltreringsnivån och namnet på tilläggsobjektet (sink)."

"Rad 5 – Vi anger filtilläggstypen ( RollingFileAppender )."

"Rad 6 – Vi anger namnet på filen som loggen ska skrivas till."

"Rad 7 – Vi anger maximal loggstorlek. När denna storleksgräns överskrids skapas en ny fil."

"Rad 8 – Vi anger antalet gamla loggfiler som ska lagras."

"Rader 9-10 – Ställ in konverteringsmönstret."

"Jag vet inte vad som händer här, men jag kan gissa. Det är uppmuntrande."

"Det är bra. Här är ett exempel på hur man skriver en logg till en fil och konsolen:"

Loggar till konsolen och en fil
# Root logger option
log4j.rootLogger = INFO, file, stdout

# Direct log messages to a log file
log4j.appender.file = org.apache.log4j.RollingFileAppender
log4j.appender.file.File = C:\\loging.log
log4j.appender.file.MaxFileSize = 1MB
log4j.appender.file.MaxBackupIndex = 1
log4j.appender.file.layout = org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern = %-5p %c{1}:%L - %m%n

# Direct log messages to stdout
log4j.appender.stdout = org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target = System.out
log4j.appender.stdout.layout = org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern = %d{yyyy-MM-dd HH:mm:ss}

"Ah, så du kan göra det? Det är bra!"

"Japp. Du kan deklarera hur många bilagor du vill och anpassa var och en."

Dessutom kan varje appendator ha mycket flexibla inställningar för meddelandefiltrering. Vi kan inte bara tilldela en individuell meddelandefiltreringsnivå till varje appendator, utan vi kan också filtrera meddelanden efter paket! Det är därför du behöver ange en klass när du skapar en logger (jag pratar om LoggerFactory.getLogger ).

"Till exempel:"

Loggar till konsolen och en fil
# Root logger option
log4j.rootLogger = INFO, file, stdout

# Direct log messages to a log file
log4j.appender.file = org.apache.log4j.RollingFileAppender
log4j.appender.file.threshold = DEBUG
log4j.appender.file.File = C:\\loging.log
log4j.appender.file.MaxFileSize = 1MB
log4j.appender.file.MaxBackupIndex = 1
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern = %-5p %c{1}:%L - %m%n

# Direct log messages to stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.threshold = ERROR
log4j.appender.stdout.Target = System.out
log4j.appender.stdout.layout = org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern = %d{yyyy-MM-dd HH:mm:ss}

log4j.logger.org.springframework = ERROR
log4j.logger.org.hibernate = ERROR
log4j.logger.com.codegym = DEBUG
log4j.logger.org.apache.cxf = ERROR

"Rad 6 och 15 – Vi ställer in vår egen filtreringsnivå för varje appendator."

"Raderna 20-23 – Vi anger paketnamnet och filtreringsnivån för dess meddelanden. Log4j.logger är ett prefix: paketnamnet är markerat i orange."

"Verkligen? Du kan till och med göra det. Tja, coolt!"

"Förresten, varken log4j eller slf4j ingår i JDK. Du måste ladda ner dem separat. Du kan göra det här . Men det finns ett annat sätt:"

" Steg 1 .Lägg till importer till klassen:"

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

" Steg 2 . Placera markören på dessa rader och tryck Alt+Enter i IntelliJ IDEA"

" Steg 3. Välj menyalternativet "Filburk på webben".

" Steg 4 . Välj 'slf4j-log4j13.jar'"

" Steg 5. Ange var biblioteket (jar) ska laddas ner"

" Steg 6. Använd de klasser du behöver."

"Wow! Vilken dag det här har varit. Så mycket som är nytt och så mycket som är coolt!"

"Här är en annan bra artikel om loggning: https://docs.oracle.com/javase/10/core/java-logging-overview.htm#JSCOR-GUID-48004124-2C00-49F7-A640-0C0DDA271DBC "

"Okej, det räcker. Ta det lugnt, programmerare."