Spring Cloud Sleuth v monolitickej aplikácii

1. Prehľad

V tomto článku uvádzame Spring Cloud Sleuth - výkonný nástroj na vylepšenie protokolov v akejkoľvek aplikácii, najmä však v systéme vytvorenom z viacerých služieb.

A pri tomto zápise sa zameriame na používanie Sleuth v monolitickej aplikácii, nie naprieč mikroslužbami.

Všetci sme mali nešťastnú skúsenosť so snahou diagnostikovať problém s naplánovanou úlohou, operáciou s viacerými vláknami alebo zložitou webovou požiadavkou. Často, aj keď sa prihlasuje, je ťažké povedať, aké akcie je potrebné vzájomne korelovať, aby sa vytvorila jedna požiadavka.

Toto môže robiť diagnostikovať zložitú akciu je veľmi ťažké alebo dokonca nemožné. Výsledkom často sú riešenia, ako je odovzdanie jedinečného ID každej metóde v žiadosti o identifikáciu protokolov.

In prichádza Sleuth. Táto knižnica umožňuje identifikovať protokoly týkajúce sa konkrétnej úlohy, vlákna alebo požiadavky. Sleuth sa bez námahy integruje do protokolových rámcov ako Logback a SLF4J pridať jedinečné identifikátory, ktoré pomáhajú sledovať a diagnostikovať problémy pomocou protokolov.

Poďme sa pozrieť na to, ako to funguje.

2. Inštalácia

Začneme vytvorením Jarná topánka webový projekt v našom obľúbenom IDE a pridanie tejto závislosti k nášmu pom.xml spis:

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

Naša aplikácia beží s Jarná topánka a nadradená pomôcka poskytuje verzie pre každú položku. Najnovšiu verziu tejto závislosti nájdete tu: spring-cloud-starter-sleuth. Ak si chcete pozrieť celý POM, pozrite si projekt na Github.

Na doplnenie pridajme názov aplikácie Sleuth na identifikáciu protokolov tejto aplikácie.

V našom application.properties súbor pridať tento riadok:

spring.application.name = Baeldung Sleuth Tutorial

3. Konfigurácie Sleuth

Sleuth je schopný vylepšiť protokoly v mnohých situáciách. Počínajúc verziou 2.0.0 používa Spring Cloud Sleuth Brave ako sledovaciu knižnicu, ktorá pridáva jedinečné ID ku každej webovej požiadavke, ktorá vstupuje do našej aplikácie. Jarný tím ďalej pridal podporu zdieľania týchto ID cez hranice vlákien.

O stopách sa dá uvažovať ako o jednej požiadavke alebo úlohe, ktorá sa spustí v aplikácii. Všetky rôzne kroky v tejto žiadosti, dokonca aj cez hranice aplikácií a vlákien, budú mať rovnaké traceId.

Na druhej strane sa rozpätia dajú považovať za časti práce alebo žiadosti. Jedna stopa môže byť zložená z viacerých rozpätí, z ktorých každé koreluje s konkrétnym krokom alebo časťou žiadosti. Pomocou identifikátorov sledovania a rozsahu môžeme presne určiť, kedy a kde je naša aplikácia, keď spracuje žiadosť. Oveľa jednoduchšie čítanie našich protokolov.

V našich príkladoch preskúmame tieto možnosti v jednej aplikácii.

3.1. Jednoduchá webová požiadavka

Najskôr vytvorme triedu radiča, ktorá bude vstupným bodom pre prácu s:

@RestController verejná trieda SleuthController {@GetMapping ("/") public String helloSleuth () {logger.info ("Hello Sleuth"); návrat "úspech"; }}

Spustime našu aplikáciu a prejdite na „// localhost: 8080“. Sledujte protokoly o výstupe, ktorý vyzerá takto:

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

Vyzerá to ako normálny protokol, s výnimkou časti na začiatku medzi zátvorkami. Toto sú základné informácie, ktoré Spring Sleuth pridal. Tieto údaje majú nasledujúci formát:

[názov aplikácie, traceId, spanId, export]

  • Názov aplikácie - Toto je názov, ktorý sme nastavili v súbore vlastností. Je možné ho použiť na agregáciu protokolov z viacerých inštancií tej istej aplikácie.
  • TraceId - Toto je ID, ktoré je priradené k jednej žiadosti, úlohe alebo akcii. Každá webová požiadavka iniciovaná jedinečným používateľom bude mať svoju vlastnú traceId.
  • SpanId - Sleduje jednotku práce. Pomysli na požiadavku, ktorá sa skladá z niekoľkých krokov. Každý krok môže mať svoj vlastný spanId a budú sledované individuálne. V predvolenom nastavení bude akýkoľvek tok aplikácií začínať rovnakými TraceId a SpanId.
  • Export - Táto vlastnosť je boolovská hodnota, ktorá označuje, či bol alebo nebol tento protokol exportovaný do agregátora Zipkin. Zipkin je nad rámec tohto článku, ale hrá dôležitú úlohu pri analýze protokolov vytvorených Sleuth.

Teraz by ste už mali mať predstavu o sile tejto knižnice. Pozrime sa na ďalší príklad, aby sme ďalej demonštrovali, aká integrálna je táto knižnica pri protokolovaní.

3.2. Jednoduchá webová požiadavka s prístupom k službe

Začnime tým, že vytvoríme službu jednou metódou:

@Service verejná trieda SleuthService {public void doSomeWorkSameSpan () {Thread.sleep (1000L); logger.info ("Robím nejakú prácu"); }}

Teraz vložíme našu službu do nášho kontrolóra a pridáme metódu mapovania požiadaviek, ktorá k nej pristupuje:

@Autowired private SleuthService sleuthService; @GetMapping ("/ same-span") public String helloSleuthSameSpan () vyvolá InterruptedException {logger.info ("Same Span"); sleuthService.doSomeWorkSameSpan (); návrat "úspech"; }

Nakoniec reštartujte aplikáciu a prejdite na „// localhost: 8080 / same-span“. Sledujte výstup protokolu, ktorý vyzerá takto:

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 [Výukový program Baeldung Sleuth, b77a5ea79036d5b9, b77a5ea79036d5b9, false] 12516 --- [nio-8080-exec-3] c.baeldung.spring.session.SleuthService: Robím nejakú prácu

Upozorňujeme, že identifikátory sledovania a rozsahu sú medzi dvoma protokolmi rovnaké, aj keď správy pochádzajú z dvoch rôznych tried. Vďaka tomu je triviálne identifikovať každý protokol počas žiadosti vyhľadaním súboru traceId tejto žiadosti.

Toto je predvolené správanie, jedna požiadavka dostane jednu traceId a spanId. Rozpätia však môžeme pridať manuálne, ako uznáme za vhodné. Pozrime sa na príklad, ktorý využíva túto funkciu.

3.3. Ručné pridanie rozpätia

Na začiatok pridáme nový radič:

@GetMapping ("/ new-span") public String helloSleuthNewSpan () {logger.info ("New Span"); sleuthService.doSomeWorkNewSpan (); návrat "úspech"; }

A teraz pridajme novú metódu do našej služby:

@Autowired private Tracer tracer; // ... public void doSomeWorkNewSpan () hodí InterruptedException {logger.info ("Som v pôvodnom rozpätí"); Rozsah newSpan = tracer.nextSpan (). Name ("newSpan"). Start (); try (SpanInScope ws = tracer.withSpanInScope (newSpan.start ())) {Thread.sleep (1000L); logger.info ("Som v novom rozsahu a robím skvelú prácu, ktorá si vyžaduje vlastné rozpätie"); } nakoniec {newSpan.finish (); } logger.info ("Som v pôvodnom rozpätí"); }

Všimnite si, že sme pridali aj nový objekt, Stopovač. The stopovač inštanciu vytvoril Spring Sleuth počas spustenia a je našej triede sprístupnený prostredníctvom vkladania závislostí.

Stopy musia byť spustené a zastavené ručne. Na tento účel je potrebné vytvoriť kód, ktorý sa spustí ručne rozpätie je umiestnený vo vnútri a skús-konečne blok na zabezpečenie rozpätie je uzavretá bez ohľadu na úspech operácie. Upozorňujeme tiež, že do rozsahu musí byť zaradený nový rozsah.

Reštartujte aplikáciu a prejdite na „// localhost: 8080 / new-span“. Sledujte výstup protokolu, ktorý vyzerá takto:

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-21 21 : 07: 54.924 INFO [Výukový program Baeldung Sleuth, 9cdebbffe8bbbade, 9cdebbffe8bbbade, false] 12516 --- [nio-8080-exec-6] c.baeldung.spring.session.SleuthService: Som v pôvodnom rozsahu 2017-01- 11 21: 07: 55,924 INFO [Výukový program Baeldung Sleuth, 9cdebbffe8bbbade, 1e706f252a0ee9c2, false] 12516 --- [nio-8080-exec-6] c.baeldung.spring.session.SleuthService: Som v novom rozsahu a robím nejaké super práca, ktorá si vyžaduje svoje vlastné rozpätie 2017-01-11 21: 07: 55,924 INFO [Výukový program Baeldung Sleuth, 9cdebbffe8bbbade, 9cdebbffe8bbbade, false] 12516 --- [nio-8080-exec-6] c.baeldung.spring.session. SleuthService: Som v pôvodnom rozpätí

Vidíme, že tretí protokol zdieľa traceId s ostatnými, ale má jedinečný spanId. To možno použiť na vyhľadanie rôznych sekcií v jednej žiadosti o podrobnejšie sledovanie.

Teraz sa poďme pozrieť na Sleuth podpora pre vlákna.

3.4. Spanning Runnables

Na demonštráciu možností vytvárania vlákien Sleuth najskôr pridajme konfiguračnú triedu na nastavenie fondu vlákien:

@ Konfigurácia verejná trieda ThreadConfig {@Autowired private BeanFactory beanFactory; @Bean public Executor Exekútor () {ThreadPoolTaskExecutor threadPoolTaskExecutor = nový ThreadPoolTaskExecutor (); threadPoolTaskExecutor.setCorePoolSize (1); threadPoolTaskExecutor.setMaxPoolSize (1); threadPoolTaskExecutor.initialize (); vrátiť nový LazyTraceExecutor (beanFactory, threadPoolTaskExecutor); }}

Je dôležité si tu uvedomiť použitie LazyTraceExecutor. Táto trieda pochádza z Sleuth knižnica a je to zvláštny druh vykonávateľa, ktorý bude propagovať našu traceIds na nové vlákna a vytvárať nové spanIds v procese.

Teraz poďme zapojiť tohto exekútora do nášho radiča a použiť ho v novej metóde mapovania požiadaviek:

@Autowired súkromný exekútor exekútor; @GetMapping ("/ new-thread") public String helloSleuthNewThread () {logger.info ("Nové vlákno"); Runnable runnable = () -> {try {Thread.sleep (1000L); } catch (InterruptedException e) {e.printStackTrace (); } logger.info ("Som v novom vlákne - s novým rozpätím"); }; executor.execute (spustiteľný); logger.info ("Hotovo - s pôvodným rozpätím"); návrat "úspech"; }

Po spustení spustiteľného programu reštartujte našu aplikáciu a prejdite na „// localhost: 8080 / new-thread“. Sledujte výstup protokolu, ktorý vyzerá takto:

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: Hotovo - s pôvodným rozpätím 11. 1. 2017 21: 18: 16,953 INFO [Výukový program Baeldung Sleuth, 96076a78343c364d, e3b6a68013ddfeea, false] 12516 --- [lTaskExecutor-1] cbspring.session.SleuthController: Som v novom vlákne - s novým rozsahom

Rovnako ako v predchádzajúcom príklade vidíme, že všetky protokoly zdieľajú rovnako traceId. Ale protokol pochádzajúci z spustiteľného súboru má jedinečné rozpätie, ktoré bude sledovať prácu vykonanú v tomto vlákne. Pamätajte, že sa to deje kvôli LazyTraceExecutor, ak by sme mali použiť normálneho exekútora, videli by sme stále to isté spanId použité v novom vlákne.

Teraz sa pozrime na to Sleuth podpora pre @Async metódy.

3.5. @Async podpora

Ak chcete pridať podporu asynchronizácie, najskôr upravme našu ThreadConfig triedy na povolenie tejto funkcie:

@Configuration @EnableAsync verejná trieda ThreadConfig rozširuje AsyncConfigurerSupport {// ... @Override public Executor getAsyncExecutor () {ThreadPoolTaskExecutor threadPoolTaskExecutor = nový ThreadPoolTaskExecutor (); threadPoolTaskExecutor.setCorePoolSize (1); threadPoolTaskExecutor.setMaxPoolSize (1); threadPoolTaskExecutor.initialize (); vrátiť nový LazyTraceExecutor (beanFactory, threadPoolTaskExecutor); }}

Všimnite si, že rozširujeme AsyncConfigurerSupport určiť nášho asynchronného exekútora a použiť LazyTraceExecutor aby sa zabezpečilo správne šírenie traceIds a spanIds. Tiež sme pridali @EnableAsync na vrchol našej triedy.

Teraz pridajme do našej služby asynchronnú metódu:

@Async public void asyncMethod () {logger.info ("Spustiť asynchronnú metódu"); Závit. Spánok (1 000 L); logger.info ("Ukončiť asynchronnú metódu"); }

Teraz zavoláme túto metódu od nášho kontrolóra:

@GetMapping ("/ async") public String helloSleuthAsync () {logger.info ("Before Async Method Call"); sleuthService.asyncMethod (); logger.info ("Po vyvolaní asynchronnej metódy"); návrat "úspech"; }

Nakoniec reštartujte našu službu a prejdite na adresu „// localhost: 8080 / async“. Sledujte výstup protokolu, ktorý vyzerá takto:

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 Method 2017-01-11 21:30: 41.622 INFO [Baeldung Sleuth Výukový program, c187f81915377fff, 8a9f3f097dca6a9e, false] 10072 --- [lTaskExecutor-1] c.baeldung.spring.session.SleuthService: Ukončiť asynchronnú metódu

Vidíme tu rovnako ako náš spustiteľný príklad, Sleuth rozširuje traceId do asynchronnej metódy a pridá jedinečný spanId.

Poďme si teraz predstaviť príklad, ktorý využíva jarnú podporu pre naplánované úlohy.

3.6. @Naplánovaný podpora

Na záver sa pozrime na to, ako Sleuth pracuje s @Naplánovaný metódy. Aby sme to dosiahli, aktualizujme naše ThreadConfig trieda na povolenie plánovania:

@Configuration @EnableAsync @EnableScheduling verejná trieda ThreadConfig rozširuje AsyncConfigurerSupport implementuje SchedulingConfigurer {// ... @Override public void configureTasks (ScheduledTaskRegistrar scheduledTaskRegistrar) {scheduledTaskRegistrar.setScheduler } @Bean (destruMethod = "vypnutie") verejný exekútor schedulingExecutor () {návrat Executors.newScheduledThreadPool (1); }}

Upozorňujeme, že sme implementovali SchedulingConfigurer rozhranie a prepísala jeho metódu configureTasks. Tiež sme pridali @EnableScheduling na vrchol našej triedy.

Ďalej pridáme službu pre naše naplánované úlohy:

@Service verejná trieda SchedulingService {private Logger logger = LoggerFactory.getLogger (this.getClass ()); @Autowired private SleuthService sleuthService; @Scheduled (fixedDelay = 30000) public void scheduledWork () vyvolá InterruptedException {logger.info ("Začať prácu z naplánovanej úlohy"); sleuthService.asyncMethod (); logger.info ("Ukončiť prácu od naplánovanej úlohy"); }}

V tejto triede sme vytvorili jednu naplánovanú úlohu s pevným oneskorením 30 sekúnd.

Poďme teraz reštartovať našu aplikáciu a počkať na vykonanie našej úlohy. Sledujte výstup konzoly takto:

2017-01-11 21:30: 58 866 INFO [Baeldung Sleuth Tutorial, 3605f5deaea28df2,3605f5deaea28df2, false] 10072 --- [pool-1-thread-1] cbspring.session.SchedulingService: Začať niektoré práce z naplánovanej úlohy 2017 -01-11 21: 30: 58 866 INFO [Baeldung Sleuth Tutorial, 3605f5deaea28df2,3605f5deaea28df2, false] 10072 --- [pool-1-thread-1] cbspring.session.SchedulingService: Ukončiť prácu od naplánovanej úlohy

Vidíme to tu Sleuth vytvoril pre našu úlohu nové identifikátory sledovania a rozsahu. Každá inštancia úlohy bude mať predvolene svoje vlastné sledovanie a rozsah.

4. Záver

Na záver sme videli, ako na to Spring Sleuth je možné použiť v rôznych situáciách v rámci jednej webovej aplikácie. Túto technológiu môžeme použiť na ľahkú koreláciu protokolov z jednej žiadosti, aj keď táto požiadavka pokrýva viac vlákien.

Teraz už vidíme ako Spring Cloud Sleuth nám môže pomôcť zachovať si zdravý rozum pri ladení viacvláknového prostredia. Identifikáciou každej operácie v a traceId a každý krok v spanId môžeme skutočne začať rozoberať našu analýzu zložitých úloh v našich denníkoch.

Aj keď nejdeme do cloudu, Spring Sleuth je pravdepodobná kritická závislosť takmer v každom projekte; je bezproblémové integrovať a predstavuje obrovské zvýšenie hodnoty.

Od tejto chvíle budete možno chcieť preskúmať ďalšie funkcie Sleuth. Môže podporovať sledovanie v distribuovaných systémoch pomocou RestTemplatemedzi protokolmi správ, ktoré používa RabbitMQ a Redisa bránou ako Zuul.

Ako vždy môžete nájsť zdrojový kód na Githube.