Spring Cloud Sleuth in een Monolith-applicatie

1. Overzicht

In dit artikel introduceren we Spring Cloud Sleuth - een krachtig hulpmiddel voor het verbeteren van logs in elke applicatie, maar vooral in een systeem dat is opgebouwd uit meerdere services.

En voor dit artikel gaan we ons concentreren op het gebruik van Sleuth in een monoliettoepassing, niet tussen microservices.

We hebben allemaal de ongelukkige ervaring gehad om te proberen een probleem te diagnosticeren met een geplande taak, een multi-threaded bewerking of een complex webverzoek. Zelfs als er sprake is van logboekregistratie, is het vaak moeilijk te zeggen welke acties met elkaar moeten worden gecorreleerd om een ​​enkel verzoek te creëren.

Dit kan maken het diagnosticeren van een complexe handeling is erg moeilijk of zelfs onmogelijk. Dit resulteert vaak in oplossingen zoals het doorgeven van een unieke id aan elke methode in het verzoek om de logboeken te identificeren.

Komt binnen Sleuth. Deze bibliotheek maakt het mogelijk om logboeken te identificeren die betrekking hebben op een specifieke taak, thread of verzoek. Sleuth integreert moeiteloos met logging-frameworks zoals Log terug en SLF4J om unieke ID's toe te voegen die helpen bij het opsporen en diagnosticeren van problemen met behulp van logboeken.

Laten we eens kijken hoe het werkt.

2. Installatie

We beginnen met het maken van een Spring Boot webproject in onze favoriete IDE en deze afhankelijkheid toevoegen aan onze pom.xml het dossier:

 org.springframework.cloud spring-cloud-starter-sleuth 

Onze applicatie draait met Spring Boot en de bovenliggende pom biedt versies voor elk item. De nieuwste versie van deze afhankelijkheid is hier te vinden: spring-cloud-starter-sleuth. Bekijk het project op Github om de volledige POM te zien.

Laten we bovendien een toepassingsnaam toevoegen om instructies te geven Sleuth om de logboeken van deze toepassing te identificeren.

In onze application.properties bestand voeg deze regel toe:

spring.application.name = Baeldung Sleuth-zelfstudie

3. Sleuth-configuraties

Sleuth is in staat om logboeken in veel situaties te verbeteren. Vanaf versie 2.0.0 gebruikt Spring Cloud Sleuth Brave als de traceringsbibliotheek die unieke ID's toevoegt aan elk webverzoek dat onze applicatie binnenkomt. Bovendien heeft het Spring-team ondersteuning toegevoegd voor het delen van deze id's over threadgrenzen heen.

Traceringen kunnen worden gezien als een enkele aanvraag of taak die in een applicatie wordt geactiveerd. Alle verschillende stappen in dat verzoek, zelfs over applicatie- en threadgrenzen heen, hebben hetzelfde traceId.

Aan de andere kant kunnen overspanningen worden gezien als secties van een taak of verzoek. Een enkele trace kan zijn samengesteld uit meerdere bereiken die elk correleren met een specifieke stap of sectie van het verzoek. Met behulp van trace- en span-id's kunnen we precies bepalen waar en wanneer onze applicatie zich bevindt terwijl deze een verzoek verwerkt. Het lezen van onze logboeken veel gemakkelijker maken.

In onze voorbeelden zullen we deze mogelijkheden in één applicatie onderzoeken.

3.1. Eenvoudig webverzoek

Laten we eerst een controllerklasse maken om mee te werken:

@RestController openbare klasse SleuthController {@GetMapping ("/") openbare String helloSleuth () {logger.info ("Hallo Sleuth"); "succes" teruggeven; }}

Laten we onze applicatie starten en naar "// localhost: 8080" gaan. Bekijk de logboeken voor uitvoer die er als volgt uitziet:

2017-01-10 22: 36: 38.254 INFO [Baeldung Sleuth-zelfstudie, 4e30f7340b3fb631,4e30f7340b3fb631, false] 12516 --- [nio-8080-exec-1] c.b.spring.session.SleuthController: Hallo Sleuth

Dit ziet eruit als een normaal blok, behalve het gedeelte aan het begin tussen de haakjes. Dit is de belangrijkste informatie die Spring Sleuth heeft toegevoegd. Deze gegevens volgen het formaat van:

[toepassingsnaam, traceId, spanId, export]

  • Naam van de toepassing - Dit is de naam die we hebben ingesteld in het eigenschappenbestand en kan worden gebruikt om logboeken van meerdere instanties van dezelfde applicatie samen te voegen.
  • TraceId - Dit is een id die is toegewezen aan een enkele aanvraag, taak of actie. Zoiets als elk uniek door de gebruiker geïnitieerd webverzoek heeft zijn eigen verzoek traceId.
  • SpanId - Houdt een werkeenheid bij. Bedenk een verzoek dat uit meerdere stappen bestaat. Elke stap kan zijn eigen hebben spanId en afzonderlijk worden gevolgd. Standaard start elke applicatiestroom met dezelfde TraceId en SpanId.
  • Exporteren - Deze eigenschap is een booleaanse waarde die aangeeft of dit logboek al dan niet is geëxporteerd naar een aggregator zoals Zipkin. Zipkin valt buiten het bestek van dit artikel, maar speelt een belangrijke rol bij het analyseren van logboeken die zijn gemaakt door Sleuth.

Inmiddels zou u een idee moeten hebben van de kracht van deze bibliotheek. Laten we een ander voorbeeld bekijken om verder te demonstreren hoe integraal deze bibliotheek is voor logboekregistratie.

3.2. Eenvoudig webverzoek met servicetoegang

Laten we beginnen met het maken van een service met een enkele methode:

@Service openbare klasse SleuthService {openbare leegte doSomeWorkSameSpan () {Thread.sleep (1000L); logger.info ("Aan het werk"); }}

Laten we nu onze service in onze controller injecteren en een verzoektoewijzingsmethode toevoegen die er toegang toe heeft:

@Autowired privé SleuthService sleuthService; @GetMapping ("/ same-span") public String helloSleuthSameSpan () gooit InterruptedException {logger.info ("Same Span"); sleuthService.doSomeWorkSameSpan (); "succes" teruggeven; }

Start ten slotte de applicatie opnieuw en ga naar "// localhost: 8080 / same-span". Let op de logboekuitvoer die eruitziet als:

2017-01-10 22: 51: 47.664 INFO [Baeldung Sleuth Tutorial, b77a5ea79036d5b9, b77a5ea79036d5b9, false] 12516 --- [nio-8080-exec-3] cbspring.session.SleuthController: Same Span 2017-01-10 22 : 51: 48.664 INFO [Baeldung Sleuth Tutorial, b77a5ea79036d5b9, b77a5ea79036d5b9, false] 12516 --- [nio-8080-exec-3] c.baeldung.spring.session.SleuthService: wat werk aan het doen

Houd er rekening mee dat de trace- en span-id's tussen de twee logboeken hetzelfde zijn, ook al zijn de berichten afkomstig van twee verschillende klassen. Dit maakt het triviaal om elk logboek tijdens een verzoek te identificeren door te zoeken naar de traceId van dat verzoek.

Dit is het standaardgedrag, één verzoek krijgt één traceId en spanId. Maar we kunnen handmatig overspanningen toevoegen als we dat nodig achten. Laten we eens kijken naar een voorbeeld dat deze functie gebruikt.

3.3. Handmatig een bereik toevoegen

Laten we om te beginnen een nieuwe controller toevoegen:

@GetMapping ("/ new-span") public String helloSleuthNewSpan () {logger.info ("New Span"); sleuthService.doSomeWorkNewSpan (); "succes" teruggeven; }

En laten we nu de nieuwe methode toevoegen aan onze service:

@Autowired privé Tracer-tracer; // ... public void doSomeWorkNewSpan () gooit InterruptedException {logger.info ("Ik ben in de oorspronkelijke span"); Span newSpan = tracer.nextSpan (). Naam ("newSpan"). Start (); probeer (SpanInScope ws = tracer.withSpanInScope (newSpan.start ())) {Thread.sleep (1000L); logger.info ("Ik ben in de nieuwe reeks bezig met cool werk dat zijn eigen reeks nodig heeft"); } eindelijk {newSpan.finish (); } logger.info ("Ik zit in de oorspronkelijke span"); }

Merk op dat we ook een nieuw object hebben toegevoegd, Tracer. De tracer instantie is gemaakt door Spring Sleuth tijdens het opstarten en wordt beschikbaar gesteld aan onze klas via afhankelijkheidsinjectie.

Traces moeten handmatig worden gestart en gestopt. Om dit te bereiken, code die wordt uitgevoerd in een handmatig aangemaakte span wordt geplaatst in een probeer het eindelijk blok om ervoor te zorgen dat het span is gesloten, ongeacht het succes van de operatie. Merk ook op dat er een nieuwe overspanning in de scope moet worden geplaatst.

Start de applicatie opnieuw en ga naar "// localhost: 8080 / new-span". Let op de logboekuitvoer die er als volgt uitziet:

2017-01-11 21: 07: 54.924 INFO [Baeldung Sleuth Tutorial, 9cdebbffe8bbbade, 9cdebbffe8bbbade, false] 12516 --- [nio-8080-exec-6] cbspring.session.SleuthController: New Span 2017-01-11 21 : 07: 54.924 INFO [Baeldung Sleuth Tutorial, 9cdebbffe8bbbade, 9cdebbffe8bbbade, false] 12516 --- [nio-8080-exec-6] c.baeldung.spring.session.SleuthService: Ik zit in de oorspronkelijke reeks 2017-01- 11 21: 07: 55.924 INFO [Baeldung Sleuth Tutorial, 9cdebbffe8bbbade, 1e706f252a0ee9c2, false] 12516 --- [nio-8080-exec-6] c.baeldung.spring.session.SleuthService: Ik ben in de nieuwe reeks bezig met wat cool werk dat zijn eigen tijd nodig heeft 2017-01-11 21: 07: 55.924 INFO [Baeldung Sleuth Tutorial, 9cdebbffe8bbbade, 9cdebbffe8bbbade, false] 12516 --- [nio-8080-exec-6] c.baeldung.spring.session. SleuthService: Ik zit in de oorspronkelijke reeks

We kunnen zien dat het derde logboek het traceId met de anderen, maar het heeft een uniek spanId. Dit kan worden gebruikt om verschillende secties in één verzoek te lokaliseren voor meer fijnmazige tracering.

Laten we nu eens kijken Sleuth's ondersteuning voor threads.

3.4. Runnables overspannen

Om de threading-mogelijkheden van Sleuth laten we eerst een configuratieklasse toevoegen om een ​​threadpool op te zetten:

@Configuration openbare klasse ThreadConfig {@Autowired privé BeanFactory beanFactory; @Bean openbare uitvoerder executor () {ThreadPoolTaskExecutor threadPoolTaskExecutor = nieuwe ThreadPoolTaskExecutor (); threadPoolTaskExecutor.setCorePoolSize (1); threadPoolTaskExecutor.setMaxPoolSize (1); threadPoolTaskExecutor.initialize (); retourneer nieuwe LazyTraceExecutor (beanFactory, threadPoolTaskExecutor); }}

Belangrijk hierbij is het gebruik van LazyTraceExecutor. Deze klasse komt uit de Sleuth bibliotheek en is een speciaal soort uitvoerder die onze traceIds naar nieuwe discussies en maak nieuwe spanIds in het proces.

Laten we nu deze uitvoerder in onze controller aansluiten en deze gebruiken in een nieuwe aanvraagtoewijzingsmethode:

@Autowired privé uitvoerder uitvoerder; @GetMapping ("/ new-thread") openbare String helloSleuthNewThread () {logger.info ("New Thread"); Runnable runnable = () -> {probeer {Thread.sleep (1000L); } catch (InterruptedException e) {e.printStackTrace (); } logger.info ("Ik zit in de nieuwe thread - met een nieuwe span"); }; executor.execute (uitvoerbaar); logger.info ("Ik ben klaar - met de originele span"); "succes" teruggeven; }

Laten we, met onze uitvoerbare versie op zijn plaats, onze applicatie herstarten en navigeren naar "// localhost: 8080 / new-thread". Let op de loguitvoer die er als volgt uitziet:

2017-01-11 21: 18: 15.949 INFO [Baeldung Sleuth Tutorial, 96076a78343c364d, 96076a78343c364d, false] 12516 --- [nio-8080-exec-9] cbspring.session.SleuthController: New Thread 2017-01-11 21 : 18: 15.950 INFO [Baeldung Sleuth Tutorial, 96076a78343c364d, 96076a78343c364d, false] 12516 --- [nio-8080-exec-9] cbspring.session.SleuthController: Ik ben klaar - met de originele span 2017-01-11 21: 18: 16.953 INFO [Baeldung Sleuth Tutorial, 96076a78343c364d, e3b6a68013ddfeea, false] 12516 --- [lTaskExecutor-1] cbspring.session.SleuthController: Ik zit in de nieuwe thread - met een nieuwe reeks

Net als in het vorige voorbeeld kunnen we zien dat alle logboeken hetzelfde delen traceId. Maar het logboek dat uit de uitvoerbare reeks komt, heeft een unieke reeks die het werk dat in die thread is gedaan, bijhoudt. Onthoud dat dit gebeurt vanwege de LazyTraceExecutor, als we een normale uitvoerder zouden gebruiken, zouden we hetzelfde blijven zien spanId gebruikt in de nieuwe thread.

Laten we nu eens kijken Sleuth's ondersteuning voor @Async methoden.

3.5. @Async Ondersteuning

Om asynchrone ondersteuning toe te voegen, moeten we eerst onze ThreadConfig class om deze functie in te schakelen:

@Configuration @EnableAsync openbare klasse ThreadConfig breidt AsyncConfigurerSupport uit {// ... @Override openbare uitvoerder getAsyncExecutor () {ThreadPoolTaskExecutor threadPoolTaskExecutor = nieuwe ThreadPoolTaskExecutor (); threadPoolTaskExecutor.setCorePoolSize (1); threadPoolTaskExecutor.setMaxPoolSize (1); threadPoolTaskExecutor.initialize (); retourneer nieuwe LazyTraceExecutor (beanFactory, threadPoolTaskExecutor); }}

Merk op dat we verlengen AsyncConfigurerSupport om onze asynchrone uitvoerder te specificeren en te gebruiken LazyTraceExecutor om ervoor te zorgen dat traceIds en spanIds correct worden gepropageerd. We hebben ook toegevoegd @EnableAsync naar de top van onze klas.

Laten we nu een asynchrone methode aan onze service toevoegen:

@Async public void asyncMethod () {logger.info ("Start Async Method"); Thread.sleep (1000L); logger.info ("Async-methode beëindigen"); }

Laten we nu deze methode aanroepen vanaf onze controller:

@GetMapping ("/ async") public String helloSleuthAsync () {logger.info ("Before Async Method Call"); sleuthService.asyncMethod (); logger.info ("Na Async Method Call"); "succes" teruggeven; }

Laten we tot slot onze service herstarten en naar "// localhost: 8080 / async" gaan. Let op de logboekuitvoer die er als volgt uitziet:

2017-01-11 21: 30: 40.621 INFO [Baeldung Sleuth Tutorial, c187f81915377fff, c187f81915377fff, false] 10072 --- [nio-8080-exec-2] cbspring.session.SleuthController: Before Async Method Call 2017-01- 11 21: 30: 40.622 INFO [Baeldung Sleuth Tutorial, c187f81915377fff, c187f81915377fff, false] 10072 --- [nio-8080-exec-2] cbspring.session.SleuthController: After Async Method Call 2017-01-11 21:30 : 40.622 INFO [Baeldung Sleuth Tutorial, c187f81915377fff, 8a9f3f097dca6a9e, false] 10072 --- [lTaskExecutor-1] c.baeldung.spring.session.SleuthService: Start async-methode 2017-01-11 21: 30: 41.622 INFO [Baeldung Zelfstudie, c187f81915377fff, 8a9f3f097dca6a9e, false] 10072 --- [lTaskExecutor-1] c.baeldung.spring.session.SleuthService: Async-methode beëindigen

We kunnen hier zoveel zien als ons uitvoerbare voorbeeld, Sleuth propageert het traceId in de async-methode en voegt een unieke spanId toe.

Laten we nu een voorbeeld bekijken met veerondersteuning voor geplande taken.

3.6. @Verwacht Ondersteuning

Laten we tot slot eens kijken hoe Sleuth werkt met @Verwacht methoden. Om dit te doen, laten we onze ThreadConfig class om planning in te schakelen:

@Configuration @EnableAsync @EnableScheduling openbare klasse ThreadConfig breidt uit AsyncConfigurerSupport implementeert SchedulingConfigurer {// ... @Override public void configureTasks (ScheduledTaskRegistrar scheduleTaskRegistrar) {scheduleTaskRegistrar.setSchedulor (scheduler); } @Bean (destroyMethod = "shutdown") public Executor schedulingExecutor () {return Executors.newScheduledThreadPool (1); }}

Merk op dat we het SchedulingConfigurer interface en heeft de methode configureTasks overschreven. We hebben ook toegevoegd @EnableScheduling naar de top van onze klas.

Laten we vervolgens een service toevoegen voor onze geplande taken:

@Service openbare klasse SchedulingService {privé Logger-logger = LoggerFactory.getLogger (this.getClass ()); @Autowired privé SleuthService sleuthService; @Scheduled (fixedDelay = 30000) public void scheduleWork () gooit InterruptedException {logger.info ("Start wat werk vanaf de geplande taak"); sleuthService.asyncMethod (); logger.info ("Werk beëindigen van geplande taak"); }}

In deze klas hebben we een enkele geplande taak gemaakt met een vaste vertraging van 30 seconden.

Laten we nu onze applicatie herstarten en wachten tot onze taak is uitgevoerd. Bekijk de console voor uitvoer als deze:

2017-01-11 21: 30: 58.866 INFO [Baeldung Sleuth-zelfstudie, 3605f5dea28df2,3605f5deaea28df2, false] 10072 --- [pool-1-thread-1] cbspring.session.SchedulingService: begin met wat werk vanaf de geplande taak 2017 -01-11 21: 30: 58.866 INFO [Baeldung Sleuth-zelfstudie, 3605f5dea28df2,3605f5deaea28df2, false] 10072 --- [pool-1-thread-1] cbspring.session.SchedulingService: werk beëindigen van geplande taak

Dat kunnen we hier zien Sleuth heeft voor onze taak nieuwe trace- en span-id's gemaakt. Elke instantie van een taak krijgt standaard zijn eigen trace en span.

4. Conclusie

Tot slot hebben we gezien hoe Spring Sleuth kan in verschillende situaties binnen een enkele webapplicatie worden gebruikt. We kunnen deze technologie gebruiken om eenvoudig logboeken van een enkel verzoek te correleren, zelfs als dat verzoek meerdere threads omvat.

Inmiddels kunnen we zien hoe Spring Cloud Sleuth kan ons helpen gezond te blijven bij het debuggen van een omgeving met meerdere threads. Door elke bewerking te identificeren in een traceId en elke stap in een spanId we kunnen onze analyse van complexe taken echt in onze logboeken opsplitsen.

Zelfs als we niet naar de cloud gaan, Spring Sleuth is waarschijnlijk een kritieke afhankelijkheid in bijna elk project; het is naadloos te integreren en is een enorme meerwaarde.

Vanaf hier wilt u misschien andere functies van Sleuth. Het kan tracering in gedistribueerde systemen ondersteunen met behulp van RestTemplate, voor berichtenprotocollen die worden gebruikt door RabbitMQ en Redis, en via een poort als Zuul.

Zoals altijd kun je de broncode vinden op Github.


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