I forbindelse med et af vores projekter blev vi konfronteret med mange debugging cases. Simple meddelelser i logfilerne er ikke altid nok. Det kan f.eks. være nødvendigt at have flere oplysninger om den bruger, der udførte handlingen (hans IP, hans tilladelser, hans identifikator, …). I vores tilfælde var vores applikation bygget op af flere mikroservices, og vi ønskede præcist at identificere det flow, der følges af en forespørgsel, der passerer fra en mikroservice til en anden. Til dette formål blev der genereret en unik identifikator, som blev vist i logfilerne for hver webapplikation. Dette hjalp os meget med at løse problemer med de tredjepartsapplikationer, vi brugte.
- Hvordan logges meddelelser?
- Hvilke kontekstoplysninger skal vi tilføje til vores meddelelser?
- Kan disse oplysninger tilføjes, når vi kører asynkrone tråde?
Denne artikel hjælper dig med at opbygge en Spring Boot Java-applikation til at logge meddelelser med Log4j og bruge MDC i dette bibliotek (Mapping Diagnostic Context) til at tilføje kontekstualiseringsdata ud over meddelelser, især for asynkrone opgaver.
Lad os starte med at generere en klassisk Spring Boot-applikation med det indbyggede Log4j-bibliotek. Dette bibliotek giver os mulighed for at bruge en logger, der genererer logmeddelelser af forskellige typer (info, fejl, advarsel, …)
- Op Spring Initializr (https://start.spring.io/) skal du opbygge et grundlæggende Spring Boot-projekt uden nogen afhængigheder.
- Redigér pom.xml-filen for at tilføje de afhængigheder, der er nødvendige for at bruge Log4j-biblioteket
- Opret src/main/resources/log4j2.xml-fil, der definerer formatet for fremtidige logmeddelelser
pom.xml
src/main/resources/log4j2.xml
Vis vores første logmeddelelse
I den nuværende tilstand vises der ingen logmeddelelse, hvis vi starter programmet (f.eks. via et IDE eller ved hjælp af Maven). Vi vil oprette en komponent, der bruger Log4j-biblioteket til at logge en informationsmeddelelse.
Opret en src/main/java/com/sipios/example/mdc/Execute.java-fil med nedenstående kode. Pakkenavnet er her com.sipios.example.mdc, det skal naturligvis erstattes af dit 🙂
src/main/java/com/sipios/sipios/example/mdc/Execute.java
Hvis du kører programmet, vises der nu en første logmeddelelse, der respekterer det definerede format. Det er også muligt at bruge metoderne error
og warning
. Logmeddelelser, der svarer til disse typer, vil blive vist.
Brug MDC (Mapping Diagnostic Context) i din log
Nu da vi ved, hvordan vi skal bruge Log4j-biblioteket, vil vi kunne bruge Mapping Diagnostic Context (MDC), som giver os mulighed for at knytte et data Map til vores meddelelse. Nogle eksempler på data, som vi anbefaler, at du sætter i MDC’en:
- Data om den aktuelle session (bruger, forespørgsel, anmodning …)
- Metri om udførelsen af processen (starttidspunkt og udførelsestid, …)
- Informationer om version af programmet
- …
Dette kort vises i logfilerne, hvis masken %X
er anvendt i definitionen af Log4j-meddelelsesformatet. Det er tilfældet her i vores fil src/main/resources/log4j2.xml. I den foregående udførelse ser vi {}
, hvilket indikerer et tomt Map.
Brug af MDC er meget simpelt og bruges som et klassisk Map via metoderne put
, get
, remove
, clear
… Lad os tilføje to poster til MDC og udføre programmet.
src/main/java/com/sipios/example/mdc/Execute.java
MDC er global, og den bevares, så længe den ikke er ændret. Hvis du ønsker at tømme den ved at forlade f.eks. en komponent, skal du blot bruge clear
-metoden. Dette vil så give følgende resultat.
Hvordan fungerer det med asynkrone komponenter?
Lad os prøve MDC med asynkrone komponenter (en komponent, der udføres på en parallel tråd til hovedtråden)! Først og fremmest skal vi konfigurere vores program til at udføre sådanne bønner. Vi opretter en tjeneste med to metoder, hvoraf den ene er synkron og den anden asynkron.
- Tilføj annotationen @EnableAsync til Application-klassen
- Opret en tjeneste med en normal metode og en @Async-metode
- Modificer komponenten til at injicere og bruge tjenestens metoder
- Lancer applikationen
src/main/java/com/sipios/example/mdc/Application.java
src/main/java/java/com/sipios/example/mdc/service/Example.java
src/main/java/com/sipios/sipios/example/mdc/Execute.java
Føj taskExecutor i Application class
src/main/java/com/sipios/sipios/example/mdc/Application.java
Re-execute :
Som vi kan se, er MDC i async-tråd tom. Hver asynkron opgave startes nemlig i en ny tråd. Hver tråd er knyttet til en Map MDC, der er initieret af opgavens eksekutor. Det er muligt at spille på denne eksekutor for at få den samme MDC som på hovedtråden. Lad os tilføje en decorator i asyncExecutor for at duplikere MDC!
src/main/java/com/sipios/sipios/example/mdc/ExampleTaskDecorator.java
Sæt denne decorator i async config
src/main/java/com/sipios/example/mdc/Application.java
Relaunch application
Der kan du gå! Vi kan i logfilerne formidle al den kontekst, som vi ønsker i synkrone eller asynkrone opgaver.
Derved bliver fejlfinding af et program forenklet og mere forståeligt. Som en del af vores projekt har dette sparet os for en masse tid i udvekslingen med vores bidragydere. Nu er det op til dig 🙂
Bibliografi
- http://www.baeldung.com/mdc-in-log4j-2-logback
- https://spring.io/guides/gs/async-method/
- https://moelholm.com/2017/07/24/spring-4-3-using-a-taskdecorator-to-copy-mdc-data-to-async-threads/