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.