Een gids om terug te loggen

1. Overzicht

Logback is een van de meest gebruikte frameworks voor logboekregistratie in de Java-gemeenschap. Het is een vervanging voor zijn voorganger, Log4j. Logback biedt een snellere implementatie dan Log4j, biedt meer opties voor configuratie en meer flexibiliteit bij het archiveren van oude logbestanden.

Deze inleiding introduceert de architectuur van Logback en laat zien hoe u deze kunt gebruiken om uw applicaties te verbeteren.

2. Logback-architectuur

Drie klassen omvatten de Logback-architectuur; Logger, Appender, en Indeling.

Een logger is een context voor logboekberichten. Dit is de klasse waarmee toepassingen communiceren om logboekberichten te maken.

Appenders plaatsen logboekberichten op hun uiteindelijke bestemming. Een Logger kan meer dan één Appender hebben. Over het algemeen denken we dat Appenders zijn gekoppeld aan tekstbestanden, maar Logback is veel krachtiger dan dat.

Lay-out bereidt berichten voor op de uitvoer. Logback ondersteunt het maken van aangepaste klassen voor het opmaken van berichten, evenals robuuste configuratie-opties voor de bestaande.

3. Installatie

3.1. Afhankelijkheid van Maven

Logback gebruikt de Simple Logging Facade for Java (SLF4J) als zijn eigen interface. Voordat we kunnen beginnen met het loggen van berichten, moeten we Logback en Slf4j toevoegen aan ons pom.xml:

 ch.qos.logback logback-core 1.2.3 org.slf4j slf4j-api 1.7.30 test 

Maven Central heeft de nieuwste versie van de Logback Core en de meest recente versie van slf4j-api.

3.2. Klassenpad

Logback vereist ook logback-classic.jar op het klassenpad voor runtime.

We zullen dit toevoegen aan pom.xml als testafhankelijkheid:

 ch.qos.logback logback-classic 1.2.3 

4. Basisvoorbeeld en configuratie

Laten we beginnen met een snel voorbeeld van het gebruik van Logback in een applicatie.

Ten eerste hebben we een configuratiebestand nodig. We maken een tekstbestand met de naam logback.xml en plaats het ergens in ons klassenpad:

   % d {HH: mm: ss.SSS} [% thread]% -5level% logger {36} -% msg% n 

Vervolgens hebben we een eenvoudige klasse nodig met een hoofd methode:

openbare klasse Voorbeeld {privé statische laatste Logger-logger = LoggerFactory.getLogger (Example.class); public static void main (String [] args) {logger.info ("Voorbeeldlogboek van {}", Example.class.getSimpleName ()); }}

Deze klasse maakt een Logger en oproepen info () om een ​​logbericht te genereren.

Als we rennen Voorbeeld we zien ons bericht gelogd naar de console:

20: 34: 22.136 [main] INFO Voorbeeld - Voorbeeldlogboek uit Voorbeeld

Het is gemakkelijk in te zien waarom Logback zo populair is; we kunnen binnen enkele minuten aan de slag.

Deze configuratie en code geven ons een paar hints over hoe dit werkt.

  1. We hebben een appender genaamd STDOUT die verwijst naar een klassenaam ConsoleAppender.
  2. Er is een patroon dat het formaat van ons logbericht beschrijft.
  3. Onze code creëert een Logger en we hebben er ons bericht aan doorgegeven via een info () methode.

Nu we de basis begrijpen, laten we het eens nader bekijken.

5. Logger Contexten

5.1. Een context creëren

Om een ​​bericht in Logback te loggen, hebben we een Logger van SLF4J of Logback:

privé statische laatste Logger-logger = LoggerFactory.getLogger (Example.class); 

En gebruikte het toen:

logger.info ("Voorbeeldlogboek van {}", Example.class.getSimpleName ()); 

Dit is onze logboekcontext. Toen we het creëerden, zijn we geslaagd LoggerFactory onze klas. Dit geeft de Logger een naam (er is ook een overbelasting die een Draad).

Logboekcontexten bestaan ​​in een hiërarchie die sterk lijkt op de Java-objecthiërarchie:

  1. Een logger is een voorouder als zijn naam, gevolgd door een punt, de voorvoegsel van een onderliggende logger is
  2. Een logger is een ouder als er geen voorouders tussen zijn en een kind

Bijvoorbeeld de Voorbeeld klasse hieronder is in de com.baeldung.logback pakket. Er is nog een klas genaamd VoorbeeldAppender in de com.baeldung.logback.appenders pakket.

Voorbeeld Appender's Logger is een kind van Voorbeeld Logger.

Alle loggers zijn afstammelingen van de vooraf gedefinieerde rootlogger.

EEN Logger heeft een Niveau, die kan worden ingesteld via configuratie of met Logger.setLevel (). Het instellen van het niveau in code heeft voorrang op configuratiebestanden.

De mogelijke niveaus zijn, in volgorde van prioriteit: TRACE, DEBUG, INFO, WARN en FOUT.Elk niveau heeft een overeenkomstige methode die we gebruiken om een ​​bericht op dat niveau te loggen.

Als aan een logger niet expliciet een niveau is toegewezen, erft hij het niveau van zijn dichtstbijzijnde voorouder. De root-logger is standaard ingesteld op DEBUG. We zullen hieronder zien hoe u dit kunt negeren.

5.2. Met behulp van een context

Laten we een voorbeeldprogramma maken dat laat zien hoe u een context binnen logboekregistratiehiërarchieën gebruikt:

ch.qos.logback.classic.Logger parentLogger = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger ("com.baeldung.logback"); parentLogger.setLevel (Level.INFO); Logger childlogger = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger ("com.baeldung.logback.tests"); parentLogger.warn ("Dit bericht wordt gelogd omdat WARN> INFO."); parentLogger.debug ("Dit bericht wordt niet geregistreerd omdat DEBUG <INFO."); childlogger.info ("INFO == INFO"); childlogger.debug ("DEBUG <INFO"); 

Wanneer we dit uitvoeren, zien we deze berichten:

20: 31: 29.586 [main] WARN com.baeldung.logback - Dit bericht wordt gelogd omdat WARN> INFO. 20: 31: 29.594 [hoofd] INFO com.baeldung.logback.tests - INFO == INFO

We beginnen met het ophalen van een Logger genaamd com.baeldung.logback en cast het naar een ch.qos.logback.classic.Logger.

Er is een Logback-context nodig om het niveau in de volgende instructie in te stellen; merk op dat de abstracte logger van de SLF4J niet implementeert setLevel ().

We stellen het niveau van onze context in op INFO;we maken vervolgens een andere logger met de naam com.baeldung.logback.tests.

We loggen twee berichten met elke context om de hiërarchie te demonstreren. Logback registreert het WAARSCHUWEN, en INFO berichten en filtert het DEBUGberichten.

Laten we nu de rootlogger gebruiken:

ch.qos.logback.classic.Logger logger = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger ("com.baeldung.logback"); logger.debug ("Hallo!"); Logger rootLogger = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger (org.slf4j.Logger.ROOT_LOGGER_NAME); logger.debug ("Dit bericht wordt gelogd omdat DEBUG == DEBUG."); rootLogger.setLevel (Level.ERROR); logger.warn ("Dit bericht wordt niet geregistreerd omdat WARN <ERROR."); logger.error ("Dit wordt gelogd."); 

We zien deze berichten wanneer we dit fragment uitvoeren:

20: 44: 44.241 [main] DEBUG com.baeldung.logback - Hallo! 20: 44: 44.243 [main] DEBUG com.baeldung.logback - Dit bericht wordt gelogd omdat DEBUG == DEBUG. 20: 44: 44.243 [main] ERROR com.baeldung.logback - Dit wordt gelogd. 

Om af te sluiten zijn we begonnen met een Logger context en afgedrukt een DEBUG bericht.

Vervolgens hebben we de rootlogger opgehaald met behulp van de statisch gedefinieerde naam en het niveau ingesteld op FOUT.

En tot slot hebben we aangetoond dat Logback feitelijk elke instructie minder dan een fout filtert.

5.3. Geparametriseerde berichten

In tegenstelling tot de berichten in de bovenstaande voorbeeldfragmenten, moesten de meest bruikbare logboekberichten worden toegevoegd Snaren. Dit omvat het toewijzen van geheugen, het serialiseren van objecten, het aaneenschakelen Snaren, en mogelijk later het vuilnis opruimen.

Beschouw de volgende boodschap:

log.debug ("Huidige telling is" + aantal); 

We maken de kosten voor het maken van het bericht, ongeacht of de logger het bericht registreert of niet.

Logback biedt een alternatief met zijn geparametreerde berichten:

log.debug ("Huidige telling is {}", aantal); 

De accolades {} accepteren alle Voorwerp en gebruikt zijn toString () methode om een ​​bericht samen te stellen nadat is gecontroleerd of het logboekbericht vereist is.

Laten we een paar verschillende parameters proberen:

String message = "Dit is een string"; Geheel getal nul = 0; probeer {logger.debug ("Logboekbericht: {}", bericht); logger.debug ("Gaat {} delen door {}", 42, nul); int resultaat = 42 / nul; } catch (uitzondering e) {logger.error ("Fout bij delen {} door {}", 42, nul, e); } 

Dit fragment levert het volgende op:

21: 32: 10.311 [main] DEBUG com.baeldung.logback.LogbackTests - Logboekbericht: dit is een string 21: 32: 10.316 [main] DEBUG com.baeldung.logback.LogbackTests - 42 wordt gedeeld door 0 21:32 : 10.316 [main] ERROR com.baeldung.logback.LogbackTests - Fout bij het delen van 42 door 0 java.lang.ArithmeticException: / door nul op com.baeldung.logback.LogbackTests.givenParameters_ValuesLogged (LogbackTests.java:64) ... 

We zien hoe a Draad, een int, en een Geheel getal kunnen als parameters worden doorgegeven.

Ook wanneer een Uitzondering wordt doorgegeven als het laatste argument aan een logging-methode, zal Logback de stacktracering voor ons afdrukken.

6. Gedetailleerde configuratie

In de vorige voorbeelden gebruikten we het 11-regelige configuratiebestand dat we in sectie 4 hadden gemaakt om logboekberichten naar de console af te drukken. Dit is het standaardgedrag van Logback; als het geen configuratiebestand kan vinden, maakt het een ConsoleAppender en associeert het met de rootlogger.

6.1. Configuratie-informatie zoeken

Een configuratiebestand kan in het klassenpad worden geplaatst en een naam krijgen logback.xml of logback-test.xml.

Hier is hoe Logback probeert configuratiegegevens te vinden:

  1. Zoek naar bestanden met de naam logback-test.xml, logback.groovy,of logback.xml in het klassenpad, in die volgorde.
  2. Als de bibliotheek die bestanden niet kan vinden, zal het proberen om Java's te gebruiken ServiceLoader om een ​​implementator van het com.qos.logback.classic.spi.Configurator.
  3. Configureer zichzelf om de uitvoer rechtstreeks naar de console te loggen

Opmerking: de huidige versie van Logback ondersteunt geen Groovy-configuratie omdat er geen versie van Groovy is die compatibel is met Java 9.

6.2. Basisconfiguratie

Laten we onze voorbeeldconfiguratie eens nader bekijken.

Het hele bestand is in tags.

We zien een tag die een Appender van het type ConsoleAppender, en noemt het STDOUT. Genest in die tag is een coderingsprogramma. Het heeft een patroon met wat eruit ziet sprintf-stijl ontsnappingscodes:

  % d {HH: mm: ss.SSS} [% thread]% -5level% logger {36} -% msg% n 

Als laatste zien we een wortel label. Deze tag stelt de root-logger in op DEBUG mode en associeert zijn output met de Appender genaamd STDOUT:

6.3. Problemen met de configuratie oplossen

Configuratiebestanden voor terugmelden kunnen ingewikkeld worden, dus er zijn verschillende ingebouwde mechanismen voor het oplossen van problemen.

Als u foutopsporingsinformatie wilt zien terwijl Logback de configuratie verwerkt, kunt u logboekregistratie voor foutopsporing inschakelen:

 ... 

Logback zal statusinformatie naar de console afdrukken terwijl deze de configuratie verwerkt:

23:54: 23,040 | -INFO in ch.qos.logback.classic.LoggerContext [standaard] - Bron [logback-test.xml] gevonden in [file: / Users / egoebelbecker / ideaProjects / logback-guide / out / test / resources / logback-test.xml] 23: 54: 23,230 | -INFO in ch.qos.logback.core.joran.action.AppenderAction - Ongeveer om appender van het type [ch.qos.logback.core.ConsoleAppender] 23 te instantiëren: 54: 23,236 | -INFO in ch.qos.logback.core.joran.action.AppenderAction - Benoem appender als [STDOUT] 23: 54: 23,247 | -INFO in ch.qos.logback.core.joran.action.NestedComplexPropertyIA - Uitgaande van het standaardtype [ch.qos.logback.classic.encoder.PatternLayoutEncoder] voor [encoder] eigenschap 23: 54: 23,308 | -INFO in ch.qos.logback.classic.joran.action.RootLoggerAction - Het niveau van de ROOT-logger instellen op DEBUG 23: 54: 23,309 | -INFO in ch.qos.logback.core.joran.action.AppenderRefAction - Voeg appender met de naam [STDOUT] toe aan Logger [ROOT] 23: 54: 23,310 | -INFO in ch.qos.logback. classic.joran.action.ConfigurationAction - Einde van configuratie. 23: 54: 23,313 | -INFO in [e-mail beveiligd] - De huidige configuratie registreren als veilig terugvalpunt

Als er waarschuwingen of fouten worden aangetroffen tijdens het ontleden van het configuratiebestand, schrijft Logback statusberichten naar de console.

Er is een tweede mechanisme om statusinformatie af te drukken:

  ... 

De StatusListener onderschept statusberichten en drukt deze af tijdens de configuratie en terwijl het programma draait.

De uitvoer van alle configuratiebestanden wordt afgedrukt, wat het handig maakt om "malafide" configuratiebestanden op het klassenpad te lokaliseren.

6.4. Configuratie automatisch opnieuw laden

Het opnieuw laden van de logboekconfiguratie terwijl een toepassing actief is, is een krachtig hulpmiddel voor probleemoplossing. Logback maakt dit mogelijk met de scannen parameter:

 ... 

Het standaardgedrag is om het configuratiebestand elke 60 seconden te scannen op wijzigingen. Wijzig dit interval door toe te voegen scanPeriod:

 ... 

We kunnen waarden specificeren in milliseconden, seconden, minuten of uren.

6.5. Wijzigen Loggers

In ons voorbeeldbestand hierboven hebben we het niveau van de rootlogger ingesteld en deze aan de console gekoppeld Appender.

We kunnen het niveau instellen voor elke logger:

   % d {HH: mm: ss.SSS} [% thread]% -5level% logger {36} -% msg% n 

Laten we dit toevoegen aan ons klassenpad en deze code uitvoeren:

Logger foobar = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger ("com.baeldung.foobar"); Logger logger = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger ("com.baeldung.logback"); Logger testslogger = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger ("com.baeldung.logback.tests"); foobar.debug ("Dit wordt gelogd van foobar"); logger.debug ("Dit wordt niet gelogd van logger"); logger.info ("Dit wordt gelogd van logger"); testslogger.info ("Dit wordt niet gelogd van tests"); testslogger.warn ("Dit wordt gelogd van tests"); 

We zien deze output:

00: 29: 51.787 [main] DEBUG com.baeldung.foobar - Dit wordt gelogd van foobar 00: 29: 51.789 [main] INFO com.baeldung.logback - Dit wordt gelogd van logger 00: 29: 51.789 [main] WARN com .baeldung.logback.tests - Dit wordt gelogd van tests 

Door het niveau van onze Loggers niet programmatisch in te stellen, stelt de configuratie ze in; com.baeldung.foobar erft DEBUG van de root-logger.

Loggerserven ook de appender-ref van de root-logger. Zoals we hieronder zullen zien, kunnen we dit negeren.

6.6. Variabele vervanging

Logback-configuratiebestanden ondersteunen variabelen. We definiëren variabelen binnen het configuratiescript of extern. Een variabele kan op elk punt in een configuratiescript worden opgegeven in plaats van een waarde.

Hier is bijvoorbeeld de configuratie voor een FileAppender:

  $ {LOG_DIR} /tests.log true% -4relative [% thread]% -5level% logger {35} -% msg% n 

Bovenaan de configuratie hebben we een eigendomgenaamd LOG_DIR.Vervolgens hebben we het gebruikt als onderdeel van het pad naar het bestand in het appender definitie.

Eigenschappen worden verklaard in een tag in configuratiescripts. Maar ze zijn ook beschikbaar via externe bronnen, zoals systeemeigenschappen. We kunnen de eigendom declaratie in dit voorbeeld en stel de waarde in van LOG_DIR op de opdrachtregel:

$ java -DLOG_DIR = / var / log / applicatie com.baeldung.logback.LogbackTests

We specificeren de waarde van het onroerend goed met $ {propertyname}. Logback implementeert variabelen als tekstvervanging. Vervanging van variabelen kan op elk punt in een configuratiebestand plaatsvinden waar een waarde kan worden gespecificeerd.

7. Appenders

Loggers voorbij lopen Logboekregistratie naar Appenders.Appenders doe het eigenlijke werk van loggen. We beschouwen loggen meestal als iets dat naar een bestand of de console gaat, maar Logback kan veel meer. Logback-core biedt verschillende handige toevoegingen.

7.1. ConsoleAppender

We hebben gezien ConsoleAppenderal in actie. Ondanks zijn naam, ConsoleAppender voegt berichten toe aan System.outof System.err.

Het gebruikt een OutputStreamWriter om de I / O te bufferen, dus het naar System.err resulteert niet in ongebufferd schrijven.

7.2. FileAppender

FileAppendervoegt berichten toe aan een bestand. Het ondersteunt een breed scala aan configuratieparameters. Laten we een bestandsappender toevoegen aan onze basisconfiguratie:

    % d {HH: mm: ss.SSS} [% thread]% -5level% logger {36} -% msg% n tests.log true% -4relative [% thread]% -5level% logger {35} -% msg % n 

De FileAppender is geconfigureerd met een bestandsnaam via . De tag instrueert de Appenderom toe te voegen aan een bestaand bestand in plaats van het af te kappen. Als we de test meerdere keren uitvoeren, zien we dat de logboekuitvoer aan hetzelfde bestand wordt toegevoegd.

Als we onze test van bovenaf opnieuw uitvoeren, worden berichten van com.baeldung.logback.tests ga naar zowel de console als naar een bestand met de naam tests.log. De afstammende logger erft de associatie van de rootlogger met de ConsoleAppender met zijn associatie met FileAppender. Appenders zijn cumulatief.

We kunnen dit gedrag opheffen:

Instelling additiviteit naar falseschakelt het standaardgedrag uit. Tests logt niet in op de console, en ook geen van zijn nakomelingen.

7.3. RollingFileAppender

Vaak is het toevoegen van logboekberichten aan hetzelfde bestand niet het gedrag dat we nodig hebben. We willen dat bestanden "rollen" op basis van tijd, logbestandsgrootte of een combinatie van beide.

Hiervoor hebben we RollingFileAppender:

  $ {LOG_FILE} .log $ {LOG_FILE}.% D {jjjj-MM-dd} .gz 30 3GB% -4relatief [% thread]% -5level% logger {35} -% msg% n 

EEN RollingFileAppenderheeft een RollingPolicy.In deze voorbeeldconfiguratie zien we een TimeBasedRollingPolicy.

Net als bij de FileAppender, we hebben deze appender geconfigureerd met een bestandsnaam. We hebben een eigenschap gedeclareerd en hiervoor gebruikt omdat we de onderstaande bestandsnaam zullen hergebruiken.

We definiëren een fileNamePattern binnen in de RollingPolicy.Dit patroon definieert niet alleen de naam van bestanden, maar ook hoe vaak ze moeten worden gerold. TimeBasedRollingPolicyonderzoekt het patroon en rollen op de meest fijn gedefinieerde periode.

Bijvoorbeeld:

   $ {LOG_DIR} / $ {LOG_FILE} .log $ {LOG_DIR} /% d {jjjj / MM} / $ {LOG_FILE} .gz 3 GB 

Het actieve logboekbestand is / var / logs / application / LogFile.Dit bestand rolt aan het begin van elke maand over in / Huidig ​​jaar / Huidige maand / LogFile.gzen RollingFileAppender creëerteen nieuw actief bestand.

Wanneer de totale grootte van gearchiveerde bestanden 3 GB bedraagt, RollingFileAppenderverwijdert archieven op basis van first-in-first-out.

Er zijn codes voor een week, uur, minuut, seconde en zelfs milliseconde. Logback heeft hier een referentie.

RollingFileAppenderheeft ook ingebouwde ondersteuning voor het comprimeren van bestanden. Het comprimeert onze opgerolde bestanden omdat ze onze naam hebben gekregen LogFile.gz.

TimeBasedPolicyis niet onze enige optie voor rollende bestanden. Logback biedt ook SizeAndTimeBasedRollingPolicy,die zal rollen op basis van de huidige grootte van het logboekbestand en de tijd. Het biedt ook een FixedWindowRollingPolicydie logboekbestandsnamen rolt elke keer dat de logger wordt gestart.

We kunnen ook onze eigen schrijven RollingPolicy.

7.4. Aangepaste toevoegingen

We kunnen aangepaste appenders maken door een van de basisappender-klassen van Logback uit te breiden. We hebben hier een tutorial voor het maken van aangepaste appenders.

8. Indelingen

Indelingen formaat logboekberichten. Net als de rest van Logback, Indelingenzijn uitbreidbaar en we kunnen onze eigen maken. Het default PatternLayout biedt wat de meeste applicaties nodig hebben en nog wat.

We hebben gebruikt PatternLayout in al onze voorbeelden tot nu toe:

 % d {HH: mm: ss.SSS} [% thread]% -5level% logger {36} -% msg% n 

Dit configuratiescript bevat de configuratie voor PatternLayoutEncoder.We passeren een Encoder naar onze Appender,en deze encoder gebruikt de PatternLayout om de berichten te formatteren.

De tekst in het tag definieert hoe logboekberichten worden opgemaakt. PatternLayout implementeert een grote verscheidenheid aan conversiewoorden en formaatmodificatoren voor het maken van patronen.

Laten we deze opsplitsen. PatternLayout herkent conversiewoorden met een%, dus de conversies in ons patroon genereren:

  • % d {HH: mm: ss.SSS} - een tijdstempel met uren, minuten, seconden en milliseconden
  • [%draad] - de threadnaam die het logbericht genereert, tussen vierkante haken
  • % -5niveau - het niveau van de logboekgebeurtenis, opgevuld tot 5 tekens
  • % logger {36} - de naam van de logger, ingekort tot 35 karakters
  • % msg% n - de logberichten gevolgd door het platformafhankelijke regelteken

We zien dus soortgelijke berichten:

21: 32: 10.311 [main] DEBUG com.baeldung.logback.LogbackTests - Logboekbericht: dit is een tekenreeks

Een volledige lijst met conversiewoorden en formaataanpassers vindt u hier.

9. Conclusie

In deze uitgebreide handleiding hebben we de basisprincipes besproken van het gebruik van Logback in een applicatie.

We hebben gekeken naar de drie belangrijkste componenten in de architectuur van Logback: loggers, appenders en lay-out. Logback's heeft krachtige configuratiescripts, die we hebben gebruikt om componenten voor het filteren en opmaken van berichten te manipuleren. We hebben ook gekeken naar de twee meest gebruikte bestandsaanhangers om logbestanden te maken, door te rollen, te ordenen en te comprimeren.

Zoals gewoonlijk zijn codefragmenten te vinden op GitHub.