Java-logging med nestet diagnostisk kontekst (NDC)

1. Oversikt

Nested Diagnostic Context (NDC) er en mekanisme for å skille sammenflettede loggmeldinger fra forskjellige kilder. NDC gjør dette ved å gi muligheten til å legge til særegen kontekstuell informasjon til hver loggoppføring.

I denne artikkelen vil vi utforske bruken av NDC og bruken / støtten i forskjellige Java-loggerammer.

2. Diagnostiske sammenhenger

I en typisk applikasjon med flere tråder som en webapplikasjon eller REST API-er, serveres hver klientforespørsel av en annen tråd. Loggene generert fra et slikt program vil være en blanding av alle klientforespørsler og kilder. Dette gjør det vanskelig å forstå loggene eller feilsøke.

Nested Diagnostic Context (NDC) administrerer en bunke med kontekstuell informasjon, per tråd. Dataene i NDC er tilgjengelige for alle loggforespørsler i koden og kan konfigureres til å logge med hver loggmelding - selv på steder der dataene ikke er innenfor omfanget. Denne kontekstuelle informasjonen i hver loggmelding hjelper til med å skille loggene etter kilde og kontekst.

Mapped Diagnostic Context (MDC) håndterer også informasjon per tråd, men som et kart.

3. NDC-stakken i et prøveprogram

For å demonstrere bruken av en NDC-stabel, la oss ta et eksempel på et REST API som sender penger til en investeringskonto.

Informasjonen som kreves som input er representert i en Investering klasse:

offentlig klasse investering {privat strengtransaksjon; privat streng eier; privat Lang beløp; offentlig investering (strengtransaksjon, streng eier, langt beløp) {this.transactionId = transactionId; this.owner = eier; dette.beløp = beløp; } // standard getters and setters}

Overføringen til investeringskontoen utføres ved hjelp av InvestmentService. Hele kildekoden for disse klassene finner du i dette github-prosjektet.

I eksempelsøknaden, dataene Transaksjons-ID og Eieren blir plassert i NDC-stakken, i tråden som behandler en gitt forespørsel. Disse dataene er tilgjengelige i hver loggmelding i den tråden. På denne måten kan hver unike transaksjon spores, og den relevante konteksten til hver loggmelding kan identifiseres.

4. NDC i Log4j

Log4j gir en klasse som heter NDC som gir statiske metoder for å administrere data i NDC-stakken. Grunnleggende bruk:

  • Når du går inn i en sammenheng, bruk NDC.push () for å legge til kontekstdata i gjeldende tråd
  • Når du forlater sammenhengen, bruk NDC.pop () å ta ut kontekstdataene
  • Når du går ut av tråden, ring NDC.remove () for å fjerne diagnostisk kontekst for tråden og sikre at minnet frigjøres (fra og med Log4j 1.3, ikke lenger nødvendig)

I eksempelprogrammet, la oss bruke NDC til å legge til / fjerne kontekstuelle data på relevante steder i koden:

import org.apache.log4j.NDC; @RestController offentlig klasse Log4JController {@Autowired @Qualifier ("Log4JInvestmentService") privat InvestmentService log4jBusinessService; @RequestMapping (verdi = "/ ndc / log4j", metode = RequestMethod.POST) offentlig ResponseEntity postPayment (@RequestBody Investment investering) {NDC.push ("tx.id =" + investering.getTransactionId ()); NDC.push ("tx.owner =" + investment.getOwner ()); log4jBusinessService.transfer (investering.getAmount ()); NDC.pop (); NDC.pop (); NDC.remove (); returner nye ResponseEntity (investering, HttpStatus.OK); }}

Innholdet i NDC kan vises i loggmeldinger ved hjelp av % x alternativet i ConversionPattern brukt av appender i log4j.egenskaper:

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

La oss distribuere REST API til tomcat. Eksempel på forespørsel:

POST / logging-service / ndc / log4j {"transactionId": "4", "eier": "Marc", "beløp": 2000}

Vi kan se diagnostisk kontekstinformasjon i loggutgangen:

48569 [http-nio-8080-exec-3] INFO Log4JInvestmentService - Forbereder overføring av 2000 $. - [tx.id = 4 tx.owner = Marc] 49231 [http-nio-8080-exec-4] INFO Log4JInvestmentService - Forbereder overføring av 1500 $. - [tx.id = 6 tx.owner = Samantha] 49334 [http-nio-8080-exec-3] INFO Log4JInvestmentService - Er overføringen på 2000 $ fullført? ekte. - [tx.id = 4 tx.owner = Marc] 50023 [http-nio-8080-exec-4] INFO Log4JInvestmentService - Er overføringen på 1500 $ fullført? ekte. - [tx.id = 6 tx.eeier = Samantha] ...

5. NDC i Log4j 2

NDC i Log4j 2 kalles som trådkontekststabel:

importer org.apache.logging.log4j.ThreadContext; @RestController offentlig klasse Log4J2Controller {@Autowired @Qualifier ("Log4J2InvestmentService") privat InvestmentService log4j2BusinessService; @RequestMapping (verdi = "/ ndc / log4j2", metode = RequestMethod.POST) offentlig ResponseEntity postPayment (@RequestBody Investment investering) {ThreadContext.push ("tx.id =" + investering.getTransactionId ()); ThreadContext.push ("tx.owner =" + investering.getOwner ()); log4j2BusinessService.transfer (investering.getAmount ()); ThreadContext.pop (); ThreadContext.pop (); ThreadContext.clearAll (); returner nye ResponseEntity (investering, HttpStatus.OK); }}

Akkurat som med Log4j, la oss bruke % x i Log4j 2-konfigurasjonsfilen log4j2.xml:

Logg utgang:

204724 [http-nio-8080-exec-1] INFO Log4J2InvestmentService - Forbereder overføring av 1500 $. - [tx.id = 6, tx.owner = Samantha] 205455 [http-nio-8080-exec-2] INFO Log4J2InvestmentService - Forbereder overføring av 2000 $. - [tx.id = 4, tx.owner = Marc] 205525 [http-nio-8080-exec-1] INFO Log4J2InvestmentService - Er overføringen på 1500 $ fullført? falsk. - [tx.id = 6, tx.owner = Samantha] 206064 [http-nio-8080-exec-2] INFO Log4J2InvestmentService - Er overføringen på 2000 $ fullført? ekte. - [tx.id = 4, tx.eeier = Marc] ...

6. NDC i loggfasader (JBoss Logging)

Skogfasader som SLF4J gir integrasjon med ulike loggingsrammer. NDC støttes ikke i SLF4J (men inkludert i slf4j-ext-modulen). JBoss Logging er en hogstbro, akkurat som SLF4J. NDC støttes i JBoss Logging.

Som standard vil JBoss Logging søke i ClassLoader for tilgjengeligheten av back-slutter / leverandører i følgende rekkefølge: JBoss LogManager, Log4j 2, Log4j, SLF4J og JDK Logging.

JBoss LogManager som loggleverandør brukes vanligvis i WildFly-applikasjonsserveren. I vårt tilfelle vil JBoss logging bridge velge den neste i prioritetsrekkefølgen (som er Log4j 2) som loggingsleverandør.

La oss begynne med å legge til den nødvendige avhengigheten i pom.xml:

 org.jboss.logging jboss-logging 3.3.0.Final 

Den siste versjonen av avhengigheten kan sjekkes her.

La oss legge til kontekstuell informasjon i NDC-stakken:

importer org.jboss.logging.NDC; @RestController offentlig klasse JBossLoggingController {@Autowired @Qualifier ("JBossLoggingInvestmentService") privat InvestmentService jbossLoggingBusinessService; @RequestMapping (verdi = "/ ndc / jboss-logging", metode = RequestMethod.POST) offentlig ResponseEntity postPayment (@RequestBody Investment investering) {NDC.push ("tx.id =" + investering.getTransactionId ()); NDC.push ("tx.owner =" + investment.getOwner ()); jbossLoggingBusinessService.transfer (investering.getAmount ()); NDC.pop (); NDC.pop (); NDC.clear (); returner nye ResponseEntity (investering, HttpStatus.OK); }}

Logg utgang:

17045 [http-nio-8080-exec-1] INFO JBossLoggingInvestmentService - Forbereder å overføre 1500 $. - [tx.id = 6, tx.owner = Samantha] 17725 [http-nio-8080-exec-1] INFO JBossLoggingInvestmentService - Har overføringen på 1500 $ fullført? ekte. - [tx.id = 6, tx.owner = Samantha] 18257 [http-nio-8080-exec-2] INFO JBossLoggingInvestmentService - Forbereder å overføre 2000 $. - [tx.id = 4, tx.owner = Marc] 18904 [http-nio-8080-exec-2] INFO JBossLoggingInvestmentService - Er overføringen på 2000 $ fullført? ekte. - [tx.id = 4, tx.eeier = Marc] ...

7. Konklusjon

Vi har sett hvordan diagnostisk kontekst hjelper til å korrelere logger på en meningsfull måte - fra et forretningsmessig synspunkt så vel som for feilsøkingsformål. Det er en uvurderlig teknikk for å berike logging, spesielt i applikasjoner med flere tråder.

Eksemplet som brukes i denne artikkelen finner du i Github-prosjektet.


$config[zx-auto] not found$config[zx-overlay] not found