Java-logboekregistratie met geneste diagnostische context (NDC)

1. Overzicht

Geneste diagnostische context (NDC) is een mechanisme om interleaved logboekberichten van verschillende bronnen te onderscheiden. NDC doet dit door de mogelijkheid te bieden om onderscheidende contextuele informatie toe te voegen aan elke logboekvermelding.

In dit artikel zullen we het gebruik van NDC en het gebruik / de ondersteuning ervan in verschillende Java-logging-frameworks onderzoeken.

2. Diagnostische contexten

In een typische multi-threaded applicatie, zoals een webapplicatie of REST API's, wordt elk clientverzoek bediend door een andere thread. De logboeken die door een dergelijke applicatie worden gegenereerd, zijn een mix van alle klantverzoeken en bronnen. Dit maakt het moeilijk om zakelijk inzicht te krijgen in de logboeken of om fouten op te sporen.

Nested Diagnostic Context (NDC) beheert een stapel contextuele informatie per thread. De gegevens in NDC zijn beschikbaar voor elk logverzoek in de code en kunnen worden geconfigureerd om bij elk logbericht te loggen - zelfs op plaatsen waar de gegevens niet binnen het bereik vallen. Deze contextuele informatie in elk logbericht helpt om de logboeken te onderscheiden op basis van hun bron en context.

De Mapped Diagnostic Context (MDC) beheert informatie ook per thread, maar als kaart.

3. De NDC-stack in een voorbeeldtoepassing

Om het gebruik van een NDC-stack te demonstreren, nemen we een voorbeeld van een REST API die geld naar een investeringsrekening stuurt.

De informatie die nodig is als invoer wordt weergegeven in een Investering klasse:

openbare klasse Investering {private String transactionId; particuliere String-eigenaar; privé Long bedrag; openbare investering (String transactionId, String owner, Long bedrag) {this.transactionId = transactionId; this.owner = eigenaar; this.amount = bedrag; } // standaard getters en setters}

De overboeking naar de beleggingsrekening geschiedt met Investeringsservice. De volledige broncode voor deze klassen is te vinden in dit github-project.

In de voorbeeldtoepassing worden de data Transactie ID en eigenaar worden in de NDC-stack geplaatst, in de thread die een bepaald verzoek verwerkt. Deze gegevens zijn beschikbaar in elk logbericht in die thread. Op deze manier kan elke unieke transactie worden getraceerd en kan de relevante context van elk logbericht worden geïdentificeerd.

4. NDC in Log4j

Log4j biedt een klasse met de naam NDC die statische methoden biedt om gegevens in de NDC-stack te beheren. Basisgebruik:

  • Gebruik bij het invoeren van een context NDC.push () om contextgegevens toe te voegen aan de huidige thread
  • Gebruik bij het verlaten van de context NDC.pop () om de contextgegevens eruit te halen
  • Bel bij het verlaten van de thread NDC.verwijderen () om de diagnostische context voor de thread te verwijderen en ervoor te zorgen dat geheugen wordt vrijgemaakt (vanaf Log4j 1.3 niet langer nodig)

Laten we in de voorbeeldtoepassing NDC gebruiken om contextuele gegevens op relevante plaatsen in de code toe te voegen / te verwijderen:

importeer org.apache.log4j.NDC; @RestController openbare klasse Log4JController {@Autowired @Qualifier ("Log4JInvestmentService") privé InvestmentService log4jBusinessService; @RequestMapping (value = "/ ndc / log4j", method = RequestMethod.POST) openbare ResponseEntity postPayment (@RequestBody Investering) {NDC.push ("tx.id =" + investment.getTransactionId ()); NDC.push ("tx.owner =" + investment.getOwner ()); log4jBusinessService.transfer (investment.getAmount ()); NDC.pop (); NDC.pop (); NDC.remove (); retourneer nieuwe ResponseEntity (investering, HttpStatus.OK); }}

De inhoud van NDC kan worden weergegeven in logberichten met behulp van %X optie in de ConversionPattern gebruikt door appender in log4j.properties:

log4j.appender.consoleAppender.layout.ConversionPattern =% -4r [% t]% 5p% c {1} -% m - [% x]% n

Laten we de REST API implementeren op tomcat. Monster verzoek:

POST / logging-service / ndc / log4j {"transactionId": "4", "owner": "Marc", "amount": 2000}

We kunnen de diagnostische contextinformatie zien in de logboekuitvoer:

48569 [http-nio-8080-exec-3] INFO Log4JInvestmentService - Voorbereiding op overboeking 2000 $. - [tx.id = 4 tx.owner = Marc] 49231 [http-nio-8080-exec-4] INFO Log4JInvestmentService - Voorbereiding om 1500 $ over te maken. - [tx.id = 6 tx.owner = Samantha] 49334 [http-nio-8080-exec-3] INFO Log4JInvestmentService - Is de overdracht van 2000 $ succesvol voltooid? waar. - [tx.id = 4 tx.owner = Marc] 50023 [http-nio-8080-exec-4] INFO Log4JInvestmentService - Is de overdracht van $ 1500 met succes voltooid? waar. - [tx.id = 6 tx.owner = Samantha] ...

5. NDC in Log4j 2

NDC in Log4j 2 wordt Thread Context Stack genoemd:

importeer org.apache.logging.log4j.ThreadContext; @RestController openbare klasse Log4J2Controller {@Autowired @Qualifier ("Log4J2InvestmentService") privé InvestmentService log4j2BusinessService; @RequestMapping (value = "/ ndc / log4j2", method = RequestMethod.POST) openbare ResponseEntity postPayment (@RequestBody Investeringsinvestering) {ThreadContext.push ("tx.id =" + investment.getTransactionId ()); ThreadContext.push ("tx.owner =" + investment.getOwner ()); log4j2BusinessService.transfer (investment.getAmount ()); ThreadContext.pop (); ThreadContext.pop (); ThreadContext.clearAll (); retourneer nieuwe ResponseEntity (investering, HttpStatus.OK); }}

Laten we, net als bij Log4j, de %X optie in het Log4j 2-configuratiebestand log4j2.xml:

Log output:

204724 [http-nio-8080-exec-1] INFO Log4J2InvestmentService - Voorbereiding op overboeking 1500 $. - [tx.id = 6, tx.owner = Samantha] 205455 [http-nio-8080-exec-2] INFO Log4J2InvestmentService - Voorbereiding om 2000 $ over te maken. - [tx.id = 4, tx.owner = Marc] 205525 [http-nio-8080-exec-1] INFO Log4J2InvestmentService - Is de overdracht van $ 1500 met succes voltooid? false. - [tx.id = 6, tx.owner = Samantha] 206064 [http-nio-8080-exec-2] INFO Log4J2InvestmentService - Is de overdracht van 2000 $ succesvol voltooid? waar. - [tx.id = 4, tx.owner = Marc] ...

6. NDC in Logging Facades (JBoss Logging)

Logging-gevels zoals SLF4J bieden integratie met verschillende logging-frameworks. NDC wordt niet ondersteund in SLF4J (maar opgenomen in de slf4j-ext-module). JBoss Logging is een logboekbrug, net als SLF4J. NDC wordt ondersteund in JBoss Logging.

Standaard zoekt JBoss Logging het ClassLoader voor de beschikbaarheid van back-ends / providers in de volgende volgorde van prioriteit: JBoss LogManager, Log4j 2, Log4j, SLF4J en JDK Logging.

JBoss LogManager als de logboekregistratieprovider wordt meestal gebruikt in de WildFly-applicatieserver. In ons geval kiest de JBoss-logging-bridge de volgende in volgorde van prioriteit (dat is Log4j 2) als de logging-provider.

Laten we beginnen met het toevoegen van de vereiste afhankelijkheid in pom.xml:

 org.jboss.logging jboss-logging 3.3.0.Final 

De laatste versie van de afhankelijkheid kan hier worden gecontroleerd.

Laten we contextuele informatie toevoegen aan de NDC-stack:

importeer org.jboss.logging.NDC; @RestController openbare klasse JBossLoggingController {@Autowired @Qualifier ("JBossLoggingInvestmentService") privé InvestmentService jbossLoggingBusinessService; @RequestMapping (value = "/ ndc / jboss-logging", method = RequestMethod.POST) openbare ResponseEntity postPayment (@RequestBody Investeringsinvestering) {NDC.push ("tx.id =" + investment.getTransactionId ()); NDC.push ("tx.owner =" + investment.getOwner ()); jbossLoggingBusinessService.transfer (investment.getAmount ()); NDC.pop (); NDC.pop (); NDC.clear (); retourneer nieuwe ResponseEntity (investering, HttpStatus.OK); }}

Log output:

17045 [http-nio-8080-exec-1] INFO JBossLoggingInvestmentService - Voorbereiding om 1.500 $ over te maken. - [tx.id = 6, tx.owner = Samantha] 17725 [http-nio-8080-exec-1] INFO JBossLoggingInvestmentService - Is de overdracht van $ 1.500 succesvol voltooid? waar. - [tx.id = 6, tx.owner = Samantha] 18257 [http-nio-8080-exec-2] INFO JBossLoggingInvestmentService - Voorbereiding om 2.000 $ over te maken. - [tx.id = 4, tx.owner = Marc] 18904 [http-nio-8080-exec-2] INFO JBossLoggingInvestmentService - Is de overdracht van 2.000 $ succesvol voltooid? waar. - [tx.id = 4, tx.owner = Marc] ...

7. Conclusie

We hebben gezien hoe diagnostische context helpt bij het op een zinvolle manier correleren van logboeken - zowel vanuit zakelijk oogpunt als voor foutopsporingsdoeleinden. Het is een techniek van onschatbare waarde om logboekregistratie te verrijken, vooral in toepassingen met meerdere threads.

Het voorbeeld dat in dit artikel wordt gebruikt, is te vinden in het Github-project.