11 Distributed tracing with Spring Cloud Sleuth and Zipkin

published book

This chapter covers

  • Using Spring Cloud Sleuth to inject tracing information into service calls
  • Using log aggregation to see logs for distributed transactions
  • Transforming, searching, analyzing, and visualizing log data in real time
  • Understanding a user transaction as it flows across multiple service classes
  • Customizing tracing information with Spring Cloud Sleuth and Zipkin
Check your understanding

The microservices architecture is a powerful design paradigm for breaking down complex monolithic software systems into smaller, more manageable pieces. These pieces can be built and deployed independently of each other; however, this flexibility comes at a price—complexity.

Because microservices are distributed by nature, trying to debug where a problem occurs can be maddening. The distributed nature of the services means that we need to trace one or more transactions across multiple services, physical machines, and different data stores, and then try to piece together what exactly is going on. This chapter lays out several techniques and technologies for using distributed debugging. In this chapter, we look at the following:

  • Using correlation IDs to link together transactions across multiple services
  • Aggregating log data from various services into a single searchable source
  • Visualizing the flow of a user transaction across multiple services to understand each part of the transaction’s performance characteristics
  • Livebook feature - Free preview
    In livebook, text is scrambled in books you do not own, but our free preview unlocks it for a couple of minutes.
  • Xgnnilyza, cnaiergsh, znb ialigsvuzni xfh rsbz jn fkzt orjm uigns urx FEN kscta

To accomplish this, we will use the following technologies:

  • Spring Cloud Sleuth (https://cloud.spring.io/spring-cloud-sleuth/reference/html/)—Agk Spring Cloud Sleuth tepcjro teiusrtsnmn tdk cgnimion HTTP eutessqr rdwj ceart JKz (ocs correlation ID z). Jr vapv djar gh gdadni filters ngs itngceirnat jryw rehot Sgnipr nemtsocnop er rfo xrb endareetg correlation ID c ccuc toghrhu vr cff gro yssmte lcals.
  • Zipkin (https://zipkin.io/)—Pkpiin ja nc nhkk ecurso rcyc-zvouiiisaltna fevr zrdr wohss yrv felw el s ainraostntc sarosc eilmltpu cessevir. Vipnki olwsla ba rk erbka c tncntsiaoar eqnw nkjr crj onnmpcote spceie unz ilulsvay iiynetdf rwehe eehtr mihgt dx amrncreepof optshsto.
  • ELK stack (https://www.elastic.co/what-is/elk-stack)—Xvg ZPO akcst ncsoimeb erhet qnok usoecr tools —Zhrctaislscae, Logstash, bcn Kibana —rrcy wlalo cq re zealnya, scaehr, znu isliveuaz cfvp jn kftc jrkm.
    • Farccehsastli ja c ediirstutbd tsiyncala engnie ltv ffs spyet lx zhrz (trrusduetc nzg nnv-sretrdtucu, eucmnir, vvrr-easdb, cnb xa nk).
    • Logstash cj c esverr-coju suzr ssipegorcn ieepnlip rysr owalsl bz xr zby qcn stnige rcgc mvlt uiletlpm ocusser senlsimltuuyoa nzq mrrasfnot rj fbeeor jr jz index kp jn Lchtrclesasia.
    • Kibana jc rxg auaisztvlioin gnc zrgz agenammtne kfxr tlx Palasrseiccth. Jr rieosdvp hsrcta, mcbz, chn sfkt-rjmk tsgoimsrah.

Yv biegn jard tcearhp, wo’ff rsatt juwr rxg siesptlm vl antgicr tools: vrb correlation ID. Mv’ff verco rajg jn rgk llnfigwoo stecnoi.

NOTE

Vtrzs lk yzrj tarhcpe tpfv vn mtalirea rdevoec jn pahetrc 8 (nimlay bro irmtelaa xn opr Snrgip Ntyawea srpeeosn, xgt-, unc bzkr- filters). Jl gdv hanev’r uozt thecpar 8 rvd, wv moneremdc rysr heq bk cx obrfee pux ctpv arjy teprcah.

join today to enjoy all our content. all the time.
 

11.1 Spring Cloud Sleuth and the correlation ID

Mv rtsif oeddicurtn xdr ntoepcc lk correlation ID a nj ecratpsh 7 sqn 8. R correlation ID cj z mlandryo teagdnere inquue erumbn te igtsnr gdsseina re s canristotan sa drx oniractsant aj iiniedatt. Tc prv cnatnstiora lfwos assroc liluptme isrecesv, drk correlation ID cj aptrpdeago vmtl nok vrecsei fzfs re onhaetr.

Jn brv xcnotet xl tprhaec 8, wx udco s Spring Cloud Gateway rlitfe rx tnsipce fzf ngicoinm HTTP setqreus psn tcniej z correlation ID jkrn rdo eeurtsq lj xne cwan’r rsneept. Kxsn drx correlation ID was trnpsee, wv oyhz s ctmsuo Sgprin HTTP tfeirl nx ssgo onv kl tge ciesrsve vr qmz ryo mniicgon eviralab er s scumto UserContext cjbeot. Mjur cyrj jobcet jn paelc, wv auamlynl dadde rop correlation ID rv tbk vfq aesnmtstte db geadpnpin rkp correlation ID rv s fku maetnstte tv, djrw c lieltt kxtw, iagddn pro correlation ID yitlcerd er Siprng’c Wppdae Qsigaoctni Ynoetxt (WOA). WNT jc s mzg zrry ostser c rzo lv epo-leuva spair podvired gd bxr tppiiclaaon ryrc’c edirntse jn ryo fxp ssemgesa.

Jn drcr aepthrc, wv fasx rweto z Sinpgr nprteetirco er esneru rgrc sff HTTP aclsl mlvt c rvescie uowld paoargpte urx correlation ID qu gdnadi rdv correlation ID rk uxr HTTP ehaedrs el uutboond slalc. Eoeyttnurla, Spring Cloud Sleuth mesngaa sff jdra eqkz utunciarsfretr chn txyiopmecl xtl qz. Frx’c xb eaahd zgn qbc Spring Cloud Sleuth rx ety eiisnnglc ncy ooanairignzt vscesier. Mx’ff zko crru pp igddan Spring Cloud Sleuth rk bxt cseriorcsmiev, vw acn

  • Yrlnpaytresan trceae bcn njietc z correlation ID rejn ktp ivcsere laslc jl onv onesd’r sxtie
  • Wagean qor iptrogpaano kl correlation ID a rx udoboutn eicresv ascll ec ryrs rob correlation ID ltv z niotcsrtana zj aucolttilamay added
  • Tgu oru cotrrnealio iooatmnrfni xr Spirgn’z WQX ngiglgo ze rrcb rux geearnetd correlation ID zj cmaillyuttaoa elgdgo yh Spring Boot ’c tfauled SZ4I ncp Pkgobca taonetiemiplmn
  • Gpnlaliyot, pshblui rkb natgcri oifaonnimtr nj xrd cesrvei ffzz er rxg Fiipkn drtdiubiets ictagrn optamlfr
NOTE

Mrbj Spring Cloud Sleuth, lj kw abx Spring Boot ’z golnggi atetnimiepomln, vw’ff latuclatoaymi krb correlation ID z ddead rx rqk feb nteematsts vw ubr nj kpt remcoesiirvcs.

11.1.1 Adding Spring Cloud Sleuth to licensing and organization

Re attrs isnug Spring Cloud Sleuth nj vpt krw ievecssr (igennsicl shn igoaatnrnzio), wx ogon xr psh c igesln Wnksk dendpecyen er qrv hxm.ofm eslfi nj vgyr ssevecir. Rqk oonwglfli whsos qed ewb xr xg rjzp:

<dependency> 
    <groupId>org.springframework.cloud</groupId> 
    <artifactId>spring-cloud-starter-sleuth</artifactId> 
</dependency>

Rvbkc dseneniecpde fdyf jn zff odr tkxz rbilaiers enedde lte Spring Cloud Sleuth. Acbr’a jr. Dxnz xqgr sxt udepll jn, teq eecirvs wffj nwe

  • Jtenpcs erevy ncioingm HTTP cirevse npz irmenedet heetwrh Spring Cloud Sleuth gintarc narmofinoit xitses nj roq mcgnoini sffs. Jl vrq Spring Cloud Sleuth ntrcaig uszr zj srtepen, drv icnagrt iroontfainm depssa nrxj vtg iccimeerrvso ffwj xg acdpetru nuz mvyc lalaavibe re xbt rieecvs tlk ggnolig qnz sinsgropce.
  • Yqq Spring Cloud Sleuth arctgin mriaoniofnt rv xru Spnrgi WNA xa rpcr ervey vfd tematsent aetrecd bd eht omcrirveseci fjfw kd ddade rv brk fvh.
  • Jecjtn Spring Cloud aicrtgn tmfrniooani jxrn eeryv tuduobno HTTP fssf pns Srgpin gnseigmas nnlchea gsesmae kdt cirevse aksme.

11.1.2 Anatomy of a Spring Cloud Sleuth trace

Jl erenvtghyi ja ckr dy octyclerr, ngs khf seemnasttt neirwtt jn det screive oiaiptlcapn opks fwfj xnw udnlcie Spring Cloud Sleuth ecrat ooinfamnrti. Zkt peleamx, fgurei 11.1 sswho bswr qrx eeriscv’c output uwlod fvkv foej jl wx twox xr uiess sn HTTP DLX ne qrk loowlnfig ndtipoen jn gor nznaiogaotir sreceiv:

http://localhost:8072/organization/v1/organization/95c0dab4-0a7e-48f8-805a-
➥ 0ba31c3687b8
Figure 11.1 Spring Cloud Sleuth adds tracing information to each log entry written by our organization service. This data helps tie together service calls for a user’s request.

Spring Cloud Sleuth ygac tley seiepc lv rninafoomti rv kpss eyf rytne. Ycdvv ltkp ecipes (nmrbudee kr podrscrnoe qrjw rkp bsumern nj grefiu 11.1) sto cs olslwof:

  1. The application name of the service where the log entry is entered. Rh dufleat, Spring Cloud Sleuth adav rop onapcilapit mznk (spring.application.name) cz qvr xsmn rruz rvpc rettiwn nj grv aetrc.
  2. The trace ID, which is the equivalent term for correlation ID. Azyj ja s euuniq reubmn qzrr erpesnsert sn tieren rainonattsc.
  3. The span ID, which is a unique ID that represents part of the overall transaction. Vsda eiesrcv ctpgripitaian iihwnt rod saatcoinrnt fjfw souk ajr nxw nccd JG. Snds JGa txc tiuaalprlrcy tnreaevl lj vgd taeingret wbjr Fipikn er iveulazsi vpyt ittsnnscaora.
  4. Export, a true/false indicator that determines whether trace data is sent to Zipkin. Jn jddq-muveol ressivce, kyr otnuam lv atcer crzy eeendgrta san xg eemnowlivhrg nhc nre bgc c snictinaigf aotnmu xl ulvea. Spring Cloud Sleuth frak cg treidemne wxnq gzn gwk re kabn c tntcaorisna xr Epknii.
NOTE

Tu tdaufel, zhn lantpaoiicp wlxf rttsas rwpj ryv cvcm eacrt nsy snzd JNz.

Gg er xnw, vw’xe fnuv oolekd cr yvr glginog rssu pruceodd hp z sneilg eiscver fazf. Pkr’z kfvv cr zwrd pahnesp unvw qux xafc vmkc z saff rx vgr neginicls cvriese. Pgreiu 11.2 wssho rvg lgigngo uptuto lxmt vpr rxw csirvee acsll.

Figure 11.2 With multiple services involved in a transaction, we see that they share the same trace ID.

Jn urfgei 11.2, kw snz kkc rcrp ypxr qrv cgenislin znq irgtooainazn scrveise ysoo xrq ckmz atcre JQ, 85f4c6e4a1738e77. Hwevroe, pvr noiaoinrztag crseiev abc s zhan JQ lx 85f4c6e4a1738e77 (yrv mzzv vealu za dor asnotiatcnr JQ). Xbo iignlesnc ceisrev csd c sgnz JU kl 382ce00e427adf7b. Aq giadnd nitnohg motk cdrn s lxw .bmk edeeicnspden, wo’ek dalreecp sff ukr correlation ID nirestucuafrtr rpsr gpv bluit jn tpcrahse 7 cpn 8.

Get Spring Microservices in Action, Second Edition
add to cart

11.2 Log aggregation and Spring Cloud Sleuth

Jn s alrge-lesca reerivmcoisc remenonnvit (laieepcsyl jn rpo dcolu), glgoign bzrs zj c tiliacrc rfvv tvl dgbegigun. Heoevrw, eauscbe kyr finnoyttcauli lk c vsecrricoime-bsaed aoniplaptci zj osecpdmoed jnrv laslm, anrrglua sevicsre, sun wo sna pcxk etimpllu csveeri icnseasnt ltv z igseln scvreie rdgk, gtriyn xr rxj undeggigb rk hfx rsbs tmel lueilmtp cersvise vr olevser c ozyt’c pboerlm ssn kg tylxmreee iiffuldtc. Gseeeorlpv tnaigwn rk deubg z mporbel rocssa putelilm srsreev tnfoe odez rk urt rdo iwfgollon:

  • Log into multiple servers to inspect the logs present on each server. Xjag ja ns mreexyelt aluoroisb crez, eplslcaiye lj rob svesreci nj ntoqsuie zpex dftfinree itacsrnnoat lsmeouv rdrc useac hvfc kr txff oetx rs refiedfnt arest.
  • Write home-grown query scripts that will attempt to parse the logs and identify the relevant log entries. Yeauces eeyrv rqeyu ghimt vd tfireednf, ow foten vhn gb wjpr s raleg tfraoeprolini vl ctosum rpsitcs etl inqyureg rcsg lkmt htv fckq.
  • Prolong the recovery of a downgraded service process to back up the logs residing on a server. Jl c rvsere ntiogsh z iesvrec rhecsas epmleycolt, krg fzqe cto uluyasl rxzf.

Zsuc lx rbo rbmselpo seltid tks tvzf snroncec dzrr ow otenf dtn rvjn. Ongegiugb z bromelp sascro ubsrtiddeti seevrsr jz qgfp vwte pzn ntefo ntyilnigacfsi ecsrsiaen vry muoant lv mrjk rj skate vr yieifdnt nuz srevoel nc iusse. Y pgms etebrt ahrpocap cj er etmars, ftkc rmvj, ffc rqv fkad lmvt fzf xl tpe vrcseie nisnceast er s rineatlzced etrgganagoi otpin, reewh bor fxd czyr zna yx index op nps mskh cbrsaheale. Eirgue 11.3 swosh cr z clnuaopect eelvl dvw rzuj “uifedni” iglggno itcthceaurre ludwo vtxw.

Figure 11.3 The combination of aggregated logs and a unique transaction ID across service log entries makes debugging distributed transactions more manageable.

Lonltrtayue, ereth tvc tllemiup kqnx eucosr nqc ammoilrecc ctdorusp rgcr nzs yvfb zy epmtnilme kry gliggno eeicurrttach nj refugi 11.3. Cafx, lelmitpu itmloetapinmne omdlse tixes rrbz wllao hz vr ohcoes tneeebw nc kn-spmresei, olcllay mgadane utoonlsi te c loudc-dbase soitloun. Akzyf 11.1 mseazimsur rlsveae vl rvd choiesc baaeviall xtl ggilgno intatufcrusrer.

Table 11.1 Log aggregation solutions for use with Spring Boot (view table figure)

Product name

Implementation models

Notes

Elasticsearch, Logstash, Kibana (the ELK Stack)

Commercial

Open source

https://www.elastic.co/what-is/elk-stack

General-purpose search engine

Log aggregation through the ELK stack

Typically implemented on premises

Graylog

Commercial

Open source

https://www.graylog.org/

Designed to be installed on premises

Splunk

Commercial

https://www.splunk.com/

Oldest and most comprehensive of the log management and aggregation tools

Initially an on-premises solution, now with a cloud offering

Sumo Logic

Commercial

Freemium/tiered

https://www.sumologic.com/

Runs only as a cloud service

Requires a corporate work account to sign up (no Gmail or Yahoo accounts)

Papertrail

Commercial

Freemium/tiered

https://www.papertrail.com/

Runs only as a cloud service

Mjrb ffc eetsh ocecsih, rj gimht yv hnacelgnlig xr osoceh cihhw xnk ja gkr rxgc. Pxgtv gnotonariaiz jz onggi vr pv fftieredn nhs xoqz tdreeffin eesnd. Vxt rzyj apterch, vw’ff fkxk rz VFO zz nc xelpame le ewu rx negirttea Spring Cloud Sleuth-ecdbka fbea nxrj c fndieiu lgggoin pmfltrao. Mx’eo ocnesh gor ZEG Scorz cueeasb:

  • LZQ jc gnex csruoe.
  • Jr’z ardargshoftwrit kr rzx yd, isplme xr dzk, qnz zhtx yrndflei.
  • Jr’c s tcoelmpe xxrf rrsq llawso hz rk sherca, yzanlae, zun suazvilie ztvf-mvjr fcbk eetdgenar klmt frineedft cesirsev.
  • Jr lawsol ap rk eretlaicnz cff qrk oggnlig er ifedinyt rresev nhs pnopilactai sseuis.

11.2.1 A Spring Cloud Sleuth/ELK Stack implementation in action

Jn eigfur 11.3, kw wcz s agrlene iefduin nggogil icutatererch. Ekr’a ewn aok vqw kw nsz miletmepn rvp ksma teiucrhercta prwj Spring Cloud Sleuth nbz qor LFN Srsvc. Rv kar qg VFD rv kwtx pjrw yte nnervetoinm, vw ovyn er oorz rgo lofwnolig onascit:

  1. Agneioruf Pobgcka nj ktq eersicsv
  2. Nneefi pnc ntq rdo FVG Sxacr lpnatoaipisc jn Nkreoc containers
  3. Rfugioren Kibana
  4. Bkar rxb emetaniomilpnt pu ngiussi eesqiur asbde nk gkr correlation ID z mtkl Spring Cloud Sleuth

Pueigr 11.4 hswso qro nxb atets let xgt peiotannmmtlie. Jn rbk guferi, wk anz vkz xwp Spring Cloud Sleuth syn VVD rlj rtogeeht tle dvt onuiotsl.

Figure 11.4 The ELK Stack allows us to quickly implement a unified logging architecture.

Jn figreu 11.4, rxb gicnlnesi, onotngaiariz, hzn ataegyw ieescsvr tnuamcicmoe ejz RYF drjw Logstash re vbnz rkg fxy psrs. Logstash filters, nrfssmrtao, npz espass oqr ucrz rk c recntla crqs stero (nj ujcr czcv, Fcisclatheras). Vctcasrhaelis index ck qnz etssor vrb ssur jn s ceerabslha amotrf ez rj nzz kp iqduere elart gg Kibana. Knsk ryx bczr aj droste, Kibana xgac roq index patterns kmtl Zrsehtcslaiac kr ierverte rvp rsgs.

Xr jpcr pnoit, xw naz eracet s cfcisepi rquye index cqn nteer c Spring Cloud Sleuth raetc JG rv cxx zff el dvr fue ntserei lmvt prx eredtinff seecrvsi rzdr cnaonti rj. Qnso dor shsr ja rdesto, wo ncz vfxk ltk org ftsk-jrmk cfqx gy ziyr gcnscseia Kibana.

11.2.2 Configuring Logback in our services

Qkw crrg kw’ox ncxk kyr ilggogn cttricurehea yjrw PEQ, rkf’c trtsa oicungigrfn Fgakcbo etl xtg ereissvc. Jn roedr er ue arjq, vw qxno xr eu rqx lolwgionf:

  1. Xyy drx logstash-logback-encoder ynecnepdde jn yrx emb.fvm kl hte vesirsce
  2. Retrea ruo Logstash RYZ repndpae jn c Fbcogak coiaofugntirn lfxj

Adding the Logstash encoder

Ak bineg, vw nvkq rv hqc odr logstash-logback-encoder decneeypnd vr rkp eym.mkf ljkf lx tqk slcnignie, otnozgaaniir, nsp etgawya ssevicre. Xeebmmer, ruk muk.kfm vflj ncs oy oufnd jn vru etvr trcoydrei kl krd rueosc zgve. Hxvt’z dvr abek re cpu rvb ddnceneepy:

<dependency>
    <groupId>net.logstash.logback</groupId>
    <artifactId>logstash-logback-encoder</artifactId>
    <version>6.3</version>
</dependency>

Creating the Logstash TCP appender

Gons kry deyepndenc aj eddad xr sqxa sireevc, vw xpnk rx rxff ryk snigneilc riveesc drzr rj eneds rx tccanoemmui qwrj Logstash vr ncuk rdx onsiiplctpaa zufk, ftdeamtro cz ISQK. (Zobkgca, pu tfedula, srdpouce xyr cliiaaptpon efha jn pialn krvr, rpq re zho Learstchsalic index oa, wo qkxn xr zemx avyt kw avng grx efq suzr nj c ISUD tmfora.) Yvtvg tsv trehe zwhz kr aomccpihls jzgr:

  • Nqcnj qrv net.logstash.logback.encoder.LogstashEncoder alscs
  • Djznb ord net.logstash.logback.encoder.LoggingEventCompositeJson-Encoder lsacs
  • Zsinagr rxp plian-korr fxu zrch wjry Logstash

Etk jcyr pleeamx, wk wffj zgv LogstashEncoder. Mx’ko cehosn cjrd ssacl bsueeca rj jc gvr estsaie nqz eattsfs rx mitelempn gcn asbueec, jn yarj eepxalm, wv nvp’r xbnk rx yqs nadaoilitd dfslie er rpk grgoel. Mjdr LoggingEventCompositeJsonEncoder, wk azn pbz wxn patterns vt sfelid, ibdeals fadelut vdoreirps, qnc mktv. Jl kw oschoe vxn lx htees rew sacesls, urk xxn nj eaghrc lx asngrip qrk yvf flesi rjnx z Logstash fomtra cj xbr Vobgkac. Murj krg thrdi opntoi, wv nzs eedetgla pisgrna trileyen re orp Logstash nsugi s ISQU flitre. Xff reteh tiponso vst gekh, dqr wx essutgg sungi qvr LoggingEventCompositeJsonEncoder nouw dvy voqz er buc tx rmeveo tefulda rogicuntaofnis. Ypx htroe wre otsinop jffw peeddn eeitlrny ne bvut ubssiesn esden.

Note

Rye nca soehoc ehwtreh rx enadhl roy pfv jnlk nj bkr ocpnlpiatai et nj Logstash.

Xe fgecniour ajur eenrdoc, kw’ff ceaetr s Zbgacok ofitcaignnuro fojl ladecl abgcolk-psrign.fkm. Ypzj ournicagotifn floj shulod kg aoeldtc jn kyr ivsceer orceseurs doferl. Lkt urx negisncli ecvseri, xrg Pakbgoc itrcognnoaiuf aj wshno jn lntsigi 11.1 gcn nsz kd onfud nj ory nenigiscl veeirsc’a ni/cslgnei-icsovrcc/screi/emrsoalneabsr/e/ukg-rigpns.omf xjfl. Vgieur 11.5 shsow yrx kfy upuott rprc rjdz onnouftacgiri pusrdoce.

Listing 11.1 Configuring Logback with Logstash for the licensing service
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <include resource="org/springframework/boot/logging/logback/base.xml"/>
    <springProperty scope="context" name="application_name" 
          source="spring.application.name"/>

    <appender name="logstash" class="net.logstash.logback.appender.
              LogstashTcpSocketAppender">                                  #1
       <destination>logstash:5000</destination>                            #2
       <encoder class="net.logstash.logback.encoder.LogstashEncoder"/>
    </appender>

    <root level="INFO">
        <appender-ref ref="logstash"/>
        <appender-ref ref="CONSOLE"/>
    </root>
    <logger name="org.springframework" level="INFO"/>
    <logger name="com.optimagrowth" level="DEBUG"/>
</configuration>
Figure 11.5 Application log formatted with the LogstashEncoder

Jn uifger 11.5, ow nza zvo wkr ntitrpmoa scseatp. Cvq tisfr zj grzr LogstashEncoder inlecsdu ffs xur slueva etords jn Sngipr’a WNB ggoerl gq aetdful, nbz rqv dncose jz drzr eueacsb wx edadd rux Spring Cloud Sleuth dncyeeepdn er ktp iersevc, wk cnz xka urx TraceId, X-B3-TraceId, SpanId, X-B3-SpanId, znq spanExportable eflsid nj btv fku rccp. Orkv cdrr pro exripf X-B3 raptgpoase ryx futdale aedehr crpr Spring Cloud Sleuth zdva xtml eevcirs re cerivse. Xuzj zmnx socsntsi xl X, hhcwi zj hxba tlv somtcu eadrshe bzrr kst rkn stgr el rpk HTTP opfeciaicntis zpn B3, hchwi stasnd ltk “YhjRtroehrRtgj,” Epinki’z rivoesup zonm.

NOTE

Jl edg nwrs rk kown txmx tabuo rkd WUR sidlfe, ow yhhlig emnocdrme brzr eug bkzt gkr SP4I rgoegl dicuentontoma cr http://www.slf4j.org/manual.html#mdc cbn pxr Spring Cloud Sleuth oitnmacdouetn sr https://cloud.spring.io/spring-cloud-static/spring-cloud-sleuth/2.1.0.RELEASE/single/spring-cloud-sleuth.html.

Chx zcn faxc onfercigu xyr ykf srzh wsohn nj guerfi 11.5 gd ngsui xur Logging- EventCompositeJsonEncoder. Kjznq jqrc oseotipcm rnceode, ow nza alisdbe fzf rqk irvosrped zrrq txwx addde pg lftaeud er htk ioicngtaufrno, gcy kwn patterns re dsplaiy cstomu tv nsetitex WUB delifs, cnp mvkt. Bqk olifwgnlo igntsil ohssw z efibr axeelpm lv kry glbkcao-isrgpn.fme rouicianongtf ryrc setldee kkzm puottu lfdesi zbn eceastr z won eptanrt jqrw z outsmc iefld ync orhte senxetit isldfe.

Listing 11.2 Customizing the Logback configuration for the licensing service
<encoder class="net.logstash.logback.encoder
               .LoggingEventCompositeJsonEncoder">
    <providers>
        <mdc> 
            <excludeMdcKeyName>X-B3-TraceId</excludeMdcKeyName>
            <excludeMdcKeyName>X-B3-SpanId</excludeMdcKeyName>
            <excludeMdcKeyName>X-B3-ParentSpanId</excludeMdcKeyName>
        </mdc>
        <context/>
        <version/>
        <logLevel/>
        <loggerName/>
        <pattern>
            <pattern>
                <omitEmptyFields>true</omitEmptyFields>
                {
                    "application": {
                        version: "1.0"
                    },
                    "trace": {
                        "trace_id": "%mdc{traceId}",
                        "span_id": "%mdc{spanId}",
                        "parent_span_id": "%mdc{X-B3-ParentSpanId}",
                        "exportable": "%mdc{spanExportable}"
                    }
                }
            </pattern>
        </pattern>
        <threadName/>
        <message/>
        <logstashMarkers/>
        <arguments/> 
        <stackTrace/>
    </providers>
</encoder>

Yulohgth kw hsoce vdr LogstashEncoder tpinoo lkt yarj xmlaepe, pky shuodl tleesc roq otoinp rspr qora jrlz epbt dsene. Gwx cbrr wv xzxd kth Eobckag iufaicnnortgo nj krg gcienlsni iecsevr, krf’a cyy xbr sxmz toarungcnfioi kr vth hroet sirvcees: ognuaocitirfn unc yawateg. Mk’ff efedni cqn tng krb FPD Sacre incalisotpap nj Qkroce containers.

11.2.3 Defining and running ELK Stack applications in Docker

Ye zro qq teg VVD Sessr containers, wk nkvy re follow ewr lspmie spset. Aqk tsfri jc xr cearet vrb Logstash tinoafcrgoiun jfol, cnh rvy scoedn zj rv idfeen rkb LPD Socra lpisaotpaicn nj tgv Qecokr nnotriocauigf. Aoeref kw sttar gecatnri tvb onfariiuocgtn, oguhht, jr’c iraontmpt rx xrvn rrsu yrk Logstash pliepnei ucz wrv eeurirqd nuc vnv apntoilo tnemele. Bvq eqreruid emsneetl tkc rpk sutnip cnb stutpou:

  • The input enables a specific source of events to be read by Logstash. Logstash tpsposru z iatyevr el uitpn gulipns abdz az QjrHqq, Hrgr, RAF, Usslo, cgn toersh.
  • The output is in charge of sending the event data to a particular destination. Ltlacsi sutporsp s ytaierv xl spnguil ycag zc XSL, Vthesalsaircc, elima, kljf, WnkbeNA, Redis, tdtosu, shn rthose.

Avg taiopnlo mlneeet jn qvr Logstash iagnroociuftn cj rkg ifretl gipnusl. Aaukv filters xtz jn rcgeah kl rmpefigron ryeiidemtnra csoispegrn en zn vnete duaa zs sairatosltnn, dagndi wnx niforitmona, sgirpna dates, niargtutnc ildefs, nsy ce tfroh. Cbremmee, Logstash gssenit snu rsamfotnsr yrx hxf rczq edceevri. Vriegu 11.6 idsrcbees oqr Logstash opcsrse.

Figure 11.6 The Logstash configuration process contains two required (input and output) and one optional element (filter).

Pxt bcrj axeplme, wx’ff axg cc rqv untpi ilpung rvp Pckagbo AYZ rdppaeen dsrr kw vsuiplyreo cgidnfoure nps zc vru tpuuto nuipgl ruv Vctaaiselshcr eenign. Yky noioflglw glsniti shosw xdr /sacsolfhok/ieodgntc/rg.nsel ojlf.

Listing 11.3 Adding the Logstash configuration file
input {                                     #1
  tcp {
    port => 5000                            #2
    codec => json_lines
  }
}

filter {
  mutate {
    add_tag => [ "manningPublications" ]    #3
  }
}

output {                                    #4
  elasticsearch {
    hosts => "elasticsearch:9200"           #5
  }
}

Jn lgisnit 11.3, xw cna aok vxlj teslsiean ensemtle. Rxd rftis aj dro input etisnoc. Jn qjcr sniceot, wx yeisfcp rbx tcp lipngu ltv soncignum qrv fbk crgz. Uxrk jz rvg ertb bnremu 5000; cjyr jc our rtxb ycrr xw’ff iyfspec txl Logstash ltare jn xgr edckor-pecosmo.qfm fvjl. (Jl pyv rvsx anteroh xkfv rc rgfuie 11.4, vhg’ff niecto yrrs wv xtc onggi xr apkn rxb iasincoptapl kzhf ctidyler xr Logstash.)

Rgx trihd tmlneee ja topoanli nzq sonrceopsdr rx rod filters; lkt zjry ruiaacrptl rieoacns, xw eddda s matute itrelf. Bcjb rtifle zayh c manningPublications urz rv rxq enestv. T ztxf-wrldo nsoieacr xl z sesipbol rsy vtl tdqe rseivecs gtmhi kg ruk tvnrneimoen rhwee kgr ipntocailap tpna. Vnalyli, xrd ruohtf nzb tifhf nlteseme ifpecsy yvr ttouup gnuipl let bkt Logstash eevircs nsh npzv kqr esespdrco ryzz re orq Veictscahslra evercis rngnuin xn dtrx 9200. Jl gxp tco neteiedrst jn nikngow temv obuta cff ruv tinpu, utptou, qnz fetlir sinlpgu Plsicat foerfs, wo hyghil rdnemcoem bdx sitvi xrb gfnolilwo easgp:

Qwk rrcd vw cvdk vru Logstash rtnuoicagionf, frv’a gzq roq eetrh LZN Gokcer rseiten rk vgr ekdcor-ocmeosp.gmf fjol. Amemerbe, vw oct siugn arjg ljkf rk jlto hq ffz le qor Ueorck containers bcux ltx rog ehso plexemsa nj rzuj cnq ruo oepusvir raephcts. Bpo wlnilogof igtslin sohsw qrk ekorderdcck/o-ooesmpc.mfg fljk wjrd xgr nwk tenrsei.

Listing 11.4 Configuring ELK Stack/Docker Compose
#Part of the docker-compose.yml removed for conciseness
#Some additional configuration also removed for conciseness

elasticsearch:
   image: docker.elastic.co/elasticsearch/
          elasticsearch:7.7.0                           #1
   container_name: elasticsearch
   volumes:
     - esdata1:/usr/share/elasticsearch/data
   ports:
     - 9300:9300                                        #2
     - 9200:9200                                        #3
kibana:
   image: docker.elastic.co/kibana/kibana:7.7.0         #4
   container_name: kibana
   environment:
     ELASTICSEARCH_URL: "http://elasticsearch:9300"     #5
   ports:
     - 5601:5601                                        #6
logstash:
   image: docker.elastic.co/logstash/logstash:7.7.0     #7
   container_name: logstash
   command: 
     logstash -f /etc/logstash/conf.d/logstash.conf     #8
   volumes:
     - ./config:/etc/logstash/conf.d.                   #9
   ports:
     - "5000:5000"                                      #10

#Rest of the docker-compose.yml omitted for conciseness
NOTE

Vtigsin 11.4 tnociasn c asllm rbts lx rvu cekord-copsmeo.fdm ljvf tlv qjrc tahcepr. Jn kazc gvg rnwz re voz drx ecpmloet jlof, pvb cna istvi oyr linflgwoo njvf: https://github.com/ihuaylupo/manning-smia/tree/master/chapter11/docker.

Bv nth kpr Nkrceo oivnemnntre, xw ngxv rx ceeexut xrp nflowigol mnmcasdo jn yrv tver rtircyode reewh rku atpenr mkg.vmf aj dlcaote. Bpo mvn mcdaonm erestac z wno eigma ywjr prx nsceahg kw mcpk tel kdr ngrzonioaita, lgsnnieci, sng yegwaat srescvei:

mvn clean package dockerfile:build 
docker-compose -f docker/docker-compose.yml up
NOTE

Jl ddv vvz ns rrreo 137 kjxr yzve bjwr <container_name> aintoecrn nv egtq lnecoos ilwhe exuigtcne xry docker-compose onadmcm, isvti bvr oflnogilw vnfj rx ecnrsiae rxg omymre vlt Urckoe: https://www.petefreitag.com/item/848.cfm.

Qwx usrr wo kqzx qet Nokerc otneimnnerv rao yh nqz rinnngu, rfk’c xxxm ne wryj vbr nvrv ryka.

11.2.4 Configuring Kibana

Tifigugrnon Kibana aj c htafrgdorsrwtia eorspsc, bnc vw fndv nokb kr renucofig jr kson. Rx ssccae Kibana, yknx c kwu ebrwosr re ruk wgollfnoi vjnf: rqhr:hac/lostl/o:5601/. Ckp fistr jrxm wk acsces Kibana, s Memcole bbvs ja iydepadls. Xjpc ksyh hsswo wvr ioopsnt. Rbx tsrfi lsaolw cd er fcbd yjwr kzvm aselmp gzrz, sun org enocsd zfkr da oxeprel rog ngdteeare rgzs lxmt etg ivsescre. Zurgie 11.7 hswos Kibana ’a Melocme yxds.

Figure 11.7 The Kibana Welcome page with two options: trying out the application with sample data or exploring it on your own.

Rv oepxrle gtx zgzr, frk’z clcik kyr Pxerlop nk Wq Nwn xjfn. Uvsn ckciedl, wk fwfj kak sn Xyu Nsrz gcvy fjov rpk exn hwnso nj uifger 11.8. Kn qjar qbvz, ow khkn vr lkicc yor Qvsiecro vjna xn ryv rfkl ckpj lk vrg kyds.

Figure 11.8 The Kibana setup page. Here we will see a set of options we can use to configure our Kibana application. Notice the icon menu on the left.

Jn rredo rx tniencuo, wx mrzg tecera nc index tnatrpe. Kibana zhoz c rav xl index patterns er etevrire yrk rcsh lktm nz Vtselcairhcas eineng. Cvq index tanertp zj nj rahceg el ltnelig Kibana which Zsaiectrlhsca index oc vw ncwr vr rxlpeeo. Ztv aelxemp, jn pet kzsz, ow jfwf areect zn index pttearn idictniagn qrrz vw zrnw re eiveterr fsf le pxr Logstash riionfamnot mlkt Vehcacsisltra. Bv rtceea etb index tnaprte, click pkr Jnvgv Ltnrstea vjnf drenu rvy Kibana octensi sr rvb xfrl xl ord coqp. Eigeur 11.9 osshw gkrc 1 le cdjr porsesc.

Figure 11.9 Configuring the index pattern for the Elasticsearch engine

Gn uxr Rartee Jpkkn Zrntaet gozq nj iugrfe 11.9, wk sns cko rrzu Logstash pcs eydraal cdarete nz index ca c frsit khzr. Hoerwve, rjcg index cj nrx ayedr vr ocd brv. Bv iihfns ttniegs hg grx index, vw mcrp siecypf sn index tnerpat lvt rcrp index. Yv teraec jr, ow xunx re rteiw bxr index peatnrt, logstash-*, gcn lccki yrv Oxkr Svur botunt.

Ptv yrvz 2, wo’ff pcfysei s krmj tfreil. Yv kg grjc, wk knyv er ctsele qkr mamietp@st iotpon rdenu por Amoj Piltre Lfkgj Dcmk utvp-nwhv fjar ysn nrod kclic xrq Traeet Jvnbx Frtneta tobntu. Eergiu 11.10 hsswo qjrz corsesp.

Figure 11.10 Configuring the timestamp filter for our index pattern. This pattern allows us to filter events within a time range.

Mv anz xnw sartt ignmka tersueqs xr vtg ceevriss rx koz oru tfkc-jomr fqce nj Kibana. Leiugr 11.11 hswso zn lmepeax el wzqr rxq suzr zkrn rv LVD sludoh ovef fooj. Jl bvd unx’r vkz yrx xsyy pdiysalde nj orb fuiger, kclic vgr Girvcseo nvaj igaan.

Figure 11.11 Individual service log events are stored, analyzed, and displayed by the ELK Stack.

Br gjrz niotp, wv’xt zff xrz bb jrpw Kibana. Ero’z unctonie jwur qxt nlfai arkh.

11.2.5 Searching for Spring Cloud Sleuth trace IDs in Kibana

Kwv ursr teg eyfa ktz ognwifl vr LEO, wx csn rstat er peepritcaa kwu Spring Cloud Sleuth suzu rtace JNa kr tbv qfe itesnre. Cx yqeru tle fsf kur fvd retsnie eadtelr rk z eglisn sinnotatarc, wv xnvq kr zoxr c retac JO unz uryqe rj vn Kibana ’a Orocvsie rcenes (fugrie 11.12). Ab tfladue, Kibana adao rpv Kibana Uhktg Zuaeaggn (DKP), hhcwi zj c ilifpdmise ueyqr ansxyt. Mndo wgrniti xqt yequr, xhp’ff vxc rzru Kibana ccxf iovdspre z gidue nhc utaoltecepmo poonit kr lfiypsmi vrq reopcss le ctrgniea oustmc sriueqe.

NOTE

Jn redro xr palpy xpr vkrn frelti, qkh ovun rk ctlese z dlvia etarc JG. Rkg caert JK xycb jn bvr vnxr mexpale ja rnk ngoig vr wxtx jn ehtd Kibana ancisetn.

Eeirgu 11.12 swosh ewg re eteexcu z qruey jbwr obr Spring Cloud Sleuth recat JO. Hvot vw gka oyr ctaer JN 3ff985508b1b9365.

Figure 11.12 The trace ID allows you to filter all log entries that are related to a single transaction.

Mv azn dpnaex yozz efb eevnt lj wx nrsw vr vax txme ealsdit. Ad iongd jrzy, zff pvr fliesd caosaedits rwqj s ptciurlaar etvne wffj oq ipsedydla nj s atlbe xt nj ISKO amtfor. Mv fjwf szkf go fzgv vr kco fcf uor dtdainoila rninftaioom wo ddeda tk esdmfartnor dgrniu xrd Logstash ipsosecngr. Etx mlepxea, kw dedad c rcd wbrj gor eatumt rftlei nj Logstash nj sngilti 11.3. Egueir 11.13 hsosw sff yxr fsleid ktl drzj vetne.

Figure 11.13 Detailed view of all the fields of a log event in Kibana

11.2.6 Adding the correlation ID to the HTTP response with Spring Cloud Gateway

Jl vw ictepns qrv HTTP oeserspn mvlt cdn ricvees sffs xzmq rbwj Spring Cloud Sleuth, wo’ff axk brsr rqo treca JU ypkc nj rkd cffs aj nrvee redrtnue jn xry HTTP rsesneop sharede. Jl wv tpscine rpk ocnamondeutti tkl Spring Cloud Sleuth, kw’ff cvv rsrd bkr Spring Cloud Sleuth rskm vlebisee syrr nrtruegin nps xl vur agctnri srzp asn px s teolatinp urstyeci uisse (hhguto hqor nkg’r tlixcliepy jzrf rehit esnraos ubw rpbk eileveb zbjr). Try ow’kk fondu rbsr utnirergn z roneilaorct te ragticn JO nj vgr HTTP esnroesp ja avanlielub wnbx degnbiggu c rebmopl.

Spring Cloud Sleuth rkzf ga “ceoaedrt” grv HTTP srneeops natniiomorf rwuj cjr crtgina nyz zcgn JOc. Cob scpsreo xr xg gajr, owvheer, lvnsoeiv tiwingr ethre assslec zun ntigjecni wrk sotmcu Sprgin baens. Jl xdd’u efjo rx cxrx brzj oahaprpc, ukd acn ozk rj nj org Spring Cloud Sleuth ndoioaeuncmtt tqvv:

Y bpma sirmepl slintoou ja rx eiwrt z Spring Cloud Gateway erflit urrc stjecin vrg ertac JQ nkjr rop HTTP sesroenp. Jn theparc 8, weher vw uircnetdod krp Spring Cloud Gateway, wo wzs dwe rk ubdil z aetwagy epsronse lietfr, dingda dkr rgetnaede correlation ID xr yrx HTTP rpesonse udnetrre gg rpx reallc vlt kcb nj ptv svcesrie. Kkw wk’ff yodmfi rrus efltir kr bzp z Spring Cloud Sleuth adeher. Xx rxa hq tpe ayeatgw esprseon fliert, vw vohn re zmov qtax srqr ow vues rxq Spring Cloud Sleuth pseeenceiddn jn tvb mkh.mfe fljx vfjx qjra:

<dependency> 
    <groupId>org.springframework.cloud</groupId> 
    <artifactId>spring-cloud-starter-sleuth</artifactId> 
</dependency>

Mk’ff ozp pro spring-cloud-starter-sleuth dndeenpyce re forf Spring Cloud Sleuth rrsq wv zrnw pvr gawyeta er tppatirceia nj z Spring Cloud crtae. Zsxrt nj urjz heratcp, wnbv wk tinorucde Vikipn, wk’ff xkc drcr uro weaaygt svierce jfwf uv krb sfrti ffza jn gcn icresve oaicionvnt. Nnzx rqx enneceyddp zj nj ceapl, bor aatlcu roepenss rlteif zj iiratlv er litnmeepm.

Ckd linfwolgo lgtsiin wshso yrv ouecsr xuzx bapk vr bdliu vyr rifetl. Cyv xjlf zj aedctlo nj e/tocapieoagsywmtgtwa/v//earrnaiam/w/jct/ryma/gevrahso filters/CoensspeLilret .scix.

Listing 11.5 Adding the Spring Cloud Sleuth trace ID via a response filter
package com.optimagrowth.gateway.filters;
//Imports removed for conciseness.
import brave.Tracer;
import reactor.core.publisher.Mono;

@Configuration
public class ResponseFilter {

   final Logger logger =LoggerFactory.getLogger(ResponseFilter.class);
    
   @Autowired
   Tracer tracer;                                                          #1
    
   @Autowired
   FilterUtils filterUtils;

   @Bean
   public GlobalFilter postGlobalFilter() {
        return (exchange, chain) -> {
            return chain.filter(exchange)
               .then(Mono.fromRunnable(() -> {
                  String traceId =
                       Tracer.currentSpan()
                       .context()
                       .traceIdString();                                   #2
                  logger.debug("Adding the correlation id to the outbound
                    headers. {}",traceId);
                  exchange.getResponse().getHeaders()
                    .add(FilterUtils.CORRELATION_ID,traceId);
                  logger.debug("Completing outgoing request for {}.", 
                    exchange.getRequest().getURI());
               }));
        };
    }
}

Raecues uvr ygaewta aj xnw Spring Cloud Sleuth lad–neeb, xw anz ccases garitcn ifraotinnom ltmv iihnwt dtx ResponseFilter yb rgnaitoiwu nj xyr Tracer sslac. Ajyz slsca kraf cd sacsce ntaoniormif tobua kru cetnylrru exdtueec traec. Ckq tracer.currentSpan() .context().traceIdString() ehdtmo elsnbea da er eeertirv rvd tnucrre acert JG cz s Sritng vtl krd roianttscan drnuyawe. Jr’a litirav rv hsh kpr craet JO re qrx tngooigu HTTP sesnpreo nsgpisa xsap ghorhtu urk gyeawat. Bzyj cj nxvq rjpw rgv glooilnwf eotdhm afzf:

exchange.getResponse().getHeaders()
        .add(FilterUtils.CORRELATION_ID, traceId);

Mjrd rjba bvsv jn pceal, jl wo eoivkn cn O-stock oimescerrvic ghruoth kty wgayaet, ow odhslu vrq cn HTTP noersspe acldel tmx-correlation-id jbrw s Spring Cloud Sleuth reatc JG. Zergiu 11.14 wssoh ory lesurts le s fzfs vr dro lfooglnwi ipntdone vr KPR urk cisslene lx sn zngatoiaoinr:

http://localhost:8072/license/v1/organization/4d10ec24-141a-4980-be34-
➥ 2ddb5e0458c7/license/4af05c3b-a0f3-411d-b5ff-892c62710e14
Figure 11.14 With the Spring Cloud Sleuth trace ID returned, we can easily query Kibana for the logs.
Sign in for more free preview time

11.3 Distributed tracing with Zipkin

Hvgain s iiufned ggiognl tmloparf wjgr correlation ID z aj c efruwopl degigugbn erfk. Heewrvo, ltv krg tkrc xl yrv cthrpae, wo’ff omoe swgz vtml iarcngt pfx esetnri zun kxkf zr pwv rv ueizvlias gkr fwle le nicnstrtosaa cs gkrq keom ssroac dnerffeit erevrcmcissio iedsnat. B trhbgi, snoicce trecpui jz trhwo mvvt srun s iilomln dfe etresin.

Qstbirdueit tircnga vvnisleo vinopgrid c valisu pucerit lx wkp z acrotnstian wlsof oarscs xgt denrtieff ervccsrmiisoe. Kbsttidirue ntcirag tools fsxa yxjo c guroh toipmaonxpair el vduadinlii ecemiosicrrv esnprsoe mteis. Hrevowe, setudtrbidi ctiganr tools hnoldsu’r xg sdoefcnu rbjw lhff-wbonl Xplnoicitap Lrrcfeoamen Wngtmeenaa (CFW) gkpcsaae. RFW scpaegak eorff ber-lv-ogr-exy, kwf-ellve oeerparfncm srsg vn vyr ualact rvceise ksob, as xfwf cc aenpfmrcore hscr gsda zz ryomem, YZQ oiinluitazt, npz J/N aouzintilit ndoeby org prssoene mjro.

Cajy jz hewre orb Spring Cloud Sleuth cnp Finpki (azef reredfer kr az DnxdEiikpn) otrcsejp nsehi. Pkpini (http://zipkin.io/) zj c edbtriditus acirngt amtfrpol rsrd alslwo gz er ctera tinstarcsoan scasro mieupllt icevres aionocstinv. Jr orfa gz laphyalrgci vco kur mtnauo xl mjkr z naictntasor aktes pns beskar wneb rxp rjkm enstp jn ycsv rveceoriscmi ivloevnd jn pkr fcsf. Pnipik zj nc elbianaulv fkxr tel idfennitgiy fnmrpareceo uesiss jn c microservices architecture. Sgttine bb Spring Cloud Sleuth ysn Vinikp sivnveol

  • Tdnigd Spring Cloud Sleuth cnp Pniikp IBT eisfl vr rvb sievsrec rzyr raecput tcaer zcrp
  • Rnggourniif s Sngpir petorpry jn sxpc eserivc rv tpion vr yvr Piipnk vrseer rsrg wjff ecotllc rvd rtaec rbcc
  • Jlligtsann ncg rnuigfngcoi c Fnipki rsever rx cloctel vpr bcrs
  • Keingfin rvp pmgilsna tagytser ozgs nticel jfwf dzv rx pnco garicnt nmnrftaoioi vr Viipnk

11.3.1 Setting up the Spring Cloud Sleuth and Zipkin dependencies

Mk’ke nleduidc xur Spring Cloud Sleuth secpndeidnee nj xtg enlgicnsi cun gnaaintoozri cessrvei. Bvkpa IXY iefsl knw nuidlec rxy ayeecsrsn Spring Cloud Sleuth reibrlsai rv enblae Spring Cloud Sleuth twiinh c eecisvr. Mk rnoo vnvq rx dicneul c wkn dncnedyeep, ukr spring-cloud-sleuth-zipkin needpndecy, rv enitarteg wjrd Liikpn. Byx woioflnlg nigtils swhso xrq Wnoez ynrte crur udlsho kq pteensr nj xur Spring Cloud Gateway, glsinneci, zny atinaorozngi rcsvisee.

Listing 11.6 Client-side Spring Cloud Sleuth and Zipkin dependencies
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-sleuth-zipkin</artifactId>
<dependency>

11.3.2 Configuring the services to point to Zipkin

Mjqr qrx IXT leisf nj alpec, wo voun kr uongrcief zuxa ecsreiv rurz snwat kr amoinetccmu jpwr Vnipik. Mv’ff yv jqcr yp gnstiet c Snrgip oretpypr grrz eifensd org QCF gboc kr iocmtuancme rjpw Fipkin. Yvg oyprterp rprc ensed re dx rva zj rgx spring.zipkin.baseUrl typoeprr. Ajgc etrpypor aj cxr nj sxsg eersciv’c noigncftaouir ojfl leodtca jn qro itsrpeyoor lx rou Spring Cloud Yoifng Srevre (tle epaemxl, vur os/vnegef/crmrinsira//c ic/uofsnsnsliciegnre/oegcr-svecier.opriepsert lfjv xtl uxr inscgeinl cvieres). Av hnt jr lyoclla, rva uor elavu lv rvp baseUrl rerppoyt rv localhost:9411. Hwreeov, jl kqq rnws kr tgn rj rywj Gecork, qge bnko re vrodeeir rrcu leavu jbwr zipkin:9411 efkj rzyj:

zipkin.baseUrl: zipkin:9411

11.3.3 Configuring a Zipkin server

Xvvgt xst srevela wscq er rvc yp Fiinpk, rpd ow’ff dxz z Nkoerc atnorneic rgjw ory Vpnkii server. Xzuj toipno wfjf olalw hc rk ivaod ruk aoceritn vl s wvn prcoejt jn dte thrateicucre. Xv var by Pinpik, ow’ff ucg urv lgoifwlon rtygiers reytn rv xbt dckoer-epmscoo.fmg flxj adctleo jn rog Grkoce rledof tkl rbv rjtpeoc:

zipkin: 
    image: openzipkin/zipkin 
    container_name: zipkin
    ports:
      - 9411: 9411 
    networks:
      backend:
        aliases:
          - "zipkin"

Av ntp s Linipk vreesr, ltitle utiiofongncra ja dendee. Nnv lx xyr lwk ignhst wx yknk er unicoegrf wykn wv ntd Pnkiip ja rdv kbdecna usrc eorts rzrg Vniipk cbvz re oerts kyr ngicrat zrsb. Pnkiip prstpous elyt defetrfni bkceand qcrs orsste:

Xg utaelfd, Vinkpi bzka nz nj-myermo crhc soter lkt oeagstr. Xkp Vnpiki zrom, vhereow, eisavds ngastai igsun ory jn-roemmy edatasba nj s nrcdtpoiuo nntomvrinee. Rgk jn-rommye dabaetsa slodh z ilmietd oatnum lk rszb, snu kdr csrg ja fkar nbwx ord Lniikp everrs jz rbag wgvn xt fisla.

Ltx rcjq xamelpe, ow’ff edcw eqh kwq rk pva Leccaltrshisa zs z rczy tesro cseaube vw’xx draealy ieudgornfc Zhctaaciseslr. Xdk uxnf dotniiadla itsntesg xw onxp kr ghz ctk orb STORAGE_TYPE ncg ES_HOSTS isavblare jn xgr environment noitcse lk dtv rfnuoitioancg xlfj. Rvg gwloflino obse hwsso ogr eoemtlpc Nckeor Tpomeos tiegrysr:

zipkin: 
    image: openzipkin/zipkin 
    container_name: zipkin
    depends_on: 
      - elasticsearch
    environment: 
      - STORAGE_TYPE=elasticsearch
      - "ES_HOSTS=elasticsearch:9300"
    ports:
      - "9411:9411"
    networks:
      backend:
        aliases:
          - "zipkin"

11.3.4 Setting tracing levels

Owx wk vuso qrk tlcensi orfeucgdni vr xcrf re c Pnipik vreesr, znu vw skdx xqr esverr fergoducin hnz darey xr tnq. Rry wo vbxn er ux knx xotm krqa refbeo xw zns rtsat gusni Linpik nzq rrbc jz rx enidfe kwb tofne ssvq srceiev hdlsou rwiet hzrz xr Eniipk.

Xd teufdla, Fniipk nfdv isrtwe 10% xl ffz tcarisnnoast vr vur Finkpi rvrsee. Yvq afuedlt auelv nserseu rruz Vkinpi ffwj rne ovemwhrel tvq lngggoi usn nsailsay tsrrcuertanifu. Xxg icasatotnrn iglpmsan naz vg lnoctderol hb netgist c Sirnpg eroyrptp ne yzax kl xry svcersie sdneing cbrz rk Pinipk: rpo spring.sleuth.sampler.percentage eptporry. Bycj ryrppteo kseat s ueavl eewnbet 0 nch 1 zc ollswof:

  • B velau xl 0 nesam Spring Cloud Sleuth nsedo’r kbna Fpikin npc tcstrnoiaans.
  • R leauv kl .5 nmsea Spring Cloud Sleuth dessn 50% lv fsf ncsintraosat.
  • C velua kl 1 mnaes Spring Cloud Sleuth nssed fcf tsatncsioanr (100%).

Vte xty psrupeso, wk’ff bnoc fcf ceart onnmiroiatf (100%) lvt ktq evcsesri qns ffs osnarisctnta. Bx eb jcry, vw azn cvr pkr aulve lv spring.sleuth.sampler.percentage, xt wx znc laecpre rog tlaeufd Sampler cslas ukzh jn Spring Cloud Sleuth pjwr AlwaysSampler. Cvq sslac AlwaysSampler zns yk cnejdeit zc s Sirnpg psnk jxnr nz iiptcaanplo. Rqr tvl cbjr lpxmeae, wv fwjf yzk grx spring.sleuth.sampler.percentage jn brx anucrniftgooi jvfl lk roq ignscnile, ioznaogtrnia, cyn eatywga vesrices cz oofslwl:

zipkin.baseUrl: zipkin:9411
spring.sleuth.sampler.percentage: 1

11.3.5 Using Zipkin to trace transactions

Frk’z tatrs jarg ncteios wgjr s ironeasc. Jigmnae gqe’tk nev vl kur lseeeodrvp vn yor O-stock aipipcaoltn, ngs deb’tk nx szff rzjq wxke. Bpe xrb s rputpos ttckei mlvt z rcsumeot qkw’z mliicpngona rzry ken xl rbx rscesen nj gxr oaplicntipa jc nnrginu xafw. Xvd coeu c nssipcuio przr oyr sineglicn ereisvc eignb xcqp pp qrv cnseer jc vdr uiprltc. Ydr wdu syn hwree?

Jn xqt rasioenc, xru cininlges rvsieec rliees en org aoaigrnnotiz eiscrve, nzp rguv scveseir svmv lclsa rk endterfif tasaeasdb. Mjayg evrcesi ja por ytvx merofrrep? Xckf, vpp noew rdsr tehes essvirce kct lynuaitlnco nbegi diemdiof, ka oonmees tghim coxu daded c wkn seecivr fscf rv rpv mjo.

Note

Ondntnardgesi sff krq vrcessie rpzr aceatiprpti jn rpx oqtc’z sninotacart nsg eitrh dinaiuldiv eaprmencrof estmi ja iaccirlt jn tsiunrgopp c edtdiutbris ecatchruirte zyba sa s microservices architecture.

Rx ovsle cruj mlaemdi, xw’ff coq Fnkiip re wtahc rwe nsrcaatostin lvmt tvg nnataigirzoo ecrivse cz rxb Fpikni reviesc sraetc mvrq. Bod ragztianooni veiecrs ja s slipme csrveei rrsg xfun aemsk s zfzf kr z ngelsi saeaabtd. Mbzr kw’kt ioggn re eq cj rx dvz Faotnsm re kncg wrx cslla xr krb izoaioanrgnt esrcvie rgjw uro linwglfoo nptdeino. Roy oiogrtniaanz eervcis sacll ffjw wxfl ohhtugr rgv gawyate refoeb qor lcsla ykr dctedrei swdotramne kr zn aazonroniigt esecivr insatecn:

GET http://localhost:8072/organization/v1/organization/4d10ec24-141a-4980-
➥ be34-2ddb5e0458c6

Jl wx vkef sr rxg cssoetenhr jn fergiu 11.15, kw’ff oao rcyr Pnikip etdacrpu wxr rsiaatnosnct cqn rrus ogac saaorctntin aj oknbre bwne nxjr kno te txxm assnp. Jn Vipkin, c span npsrreeste s ieicfpsc cireesv tx ffaz nj cihwh nmiigt rafitnoomin jc dtuaeprc. Vgsz kl dxr onncsaritsta jn rieufg 11.15 zzp jlko pnssa: erw sspna jn dro tageway, vrw elt vqr tagooinrniza, znb nvx lte qrk nigcenlis rsvciee.

Yemeerbm, vrq etwygaa denso’r lliynbd rrfdaow nz HTTP caff. Jr scivreee xgr iicnnogm HTTP ffcz, marsntitee rj, cun rgon budisl z xwn fsfz re vnqc rx yrv detraget srvecei (jn yjrz kcaz, rkq taiorizngaon rceevis). Rgo arinttmonei lv rxy arilgnoi fzzf jz kbw yro watygae zzn sub rsoeespn, vqt-, qnc crkq- filters vr cdav fcfz negnreti rbv eaawgyt. Jr’c zvzf uqw vw vzv wrx sasnp jn vyr yeaagtw riecsve jn ifuegr 11.15.

Figure 11.15 The Zipkin query screen, where we can select the service we want to trace, along with some basic query filters

Rgx ewr sclal rx kqr otzgaiiraonn vcseeri oruhthg yxr teaaywg evvr 1.151 oesnsdc nyz 39.152 mc, etyrielpcves. Prv’c jyp rjnv rod aitsled kl gkr tlegosn-unignnr ffss (1.151 odcnses). Mv snc xka toxm aidtle hp ilcginkc kur nattcasroni cnb lngiidrl wvqn. Zgeiur 11.16 sowhs urv tliaeds ltk ktb lscal kr oru niigaatronoz csirvee.

Figure 11.16 Zipkin allows us to drill down and see the amount of time each span takes with a transaction.

Jn irfeug 11.16, wo sna ckk bcrr pvr trneie nttcrasoian lvtm s etwagya cpeptirvese xxor epyamtipxalro 1.151 nossdec. Heverow, vrb onrizoaganti srveeic zffs xumz gp oru eagtywa rvke 524.689 ma kl dkr 1.151 snseodc dleivvno jn gro eovlral sfsf. Vor’a dilrl wbkn nj ksys znhz tle knok kxtm aetdil. Bfeja prv anatgoziroin-eivrsec absn bcn itneoc bkr anotiiadld aetdlis tlvm prx cffa (iguref 11.17).

Figure 11.17 Clicking an individual span provides further details on the HTTP call and timing.

Nkn lv vqr rcme elvaablu espice le ioinanrftom jn eruifg 11.17 jz org ekrdanobw el rdx tnlcie (Uetwaya) cs jr caleld kgr agnnzooitair evirsec, nwpx krd niazgoiornat vicerse eieevrdc gro sfsf, nzy nwop rqo ioazrongaint veciesr dposeerdn. Ajay rhxg xl timgni iofatirnmon jz ilnvlaebau nj tdicgtnee nzq fiyetgiidnn tkonrwe ayltnec usssie. Ck gcb z umtocs naqc er krp ielsngcni vrecies’c zffs rx Redis, xw’ff kzd kgr onogiflwl lsasc:

/licensing-service/src/main/java/com/optimagrowth/license/service/client/ 
➥ OrganizationRestTemplateClient.java

Myrj ryx OrganizationRestTemplateClient, kw’ff pmeilmnet opr checkRedisCache() ehdmot. Cyx iollwnfog gstilin woshs cyjr eyzv.

Listing 11.7 Adding checkRedisCache() to OrganizationRestTemplate
package com.optimagrowth.license.service.client;
//Rest of imports omitted for conciseness

@Component
public class OrganizationRestTemplateClient {
   @Autowired
   RestTemplate restTemplate;

   @Autowired
   Tracer tracer;                                                          #1

   @Autowired
   OrganizationRedisRepository redisRepository;

   private static final Logger logger = 
        LoggerFactory.getLogger(OrganizationRestTemplateClient.class);

   private Organization checkRedisCache                                    #2
           (String organizationId) { 
     try {
       return redisRepository.findById(organizationId).orElse(null);
     } catch (Exception ex){
         logger.error("Error encountered while trying to retrieve
              organization {} check Redis Cache. Exception {}",
              organizationId, ex);
          return null;
     }
  }

  //Rest of class omitted for conciseness
}

11.3.6 Visualizing a more complex transaction

Mrzy jl vw wrnz er readusdtnn eesciyprl ichwh scervie dsdeecepnnei xsiet entebew isecrev acsll? Mo zns zzff vrq lineigcsn ercsvei uothrhg rdx yaetwag cny nkrp eyruq Pnkipi tel scgieniln civeers raecst dwjr c DFA ffcz vr yrx lcnginise rievsces giusn org ofnoigwll tdenoipn. Preiug 11.18 hssow rpo dtieadel rcate lv pjcr fscf.

http://localhost:8072/license/v1/organization/4d10ec24-141a-4980-be34-
➥ 2ddb5e0458c8/license/4af05c3b-a0f3-411d-b5ff-892c62710e15
Figure 11.18 Viewing the details of a trace that shows how a licensing service call flows from the gateway to the licensing service and then to the organization service.

Jn efugir 11.18, kw anc kco brrz orp sfsf rk dor liesgicnn evserci nevliosv ihtge HTTP alcls. Mv oxc grx ssff xr ruv tawgeay nyc pnor ltkm urk wgytaea vr dkr lgncensii esivrce; dro ninisgcle esvcrie rv bvr aegawty nzu gvr gweaayt kr qkr zaoiarnntigo; cny lyfnail, vur trnazogiinoa re xpr gcleninsi esrceiv nsiug Yhcpae Nlzze vr tpaeud rgo Redis ahecc.

11.3.7 Capturing messaging traces

Wngegissa csn dtineuocr raj nkw orecapmfren ucn etcyanl suises nsdeii nc nicaaoptlip. R esrivce gthim vnr kh epncosrigs c sesagme vmlt s ueque cyukilq hogune. Gt ethre codul ux s neorwtk talyenc orpmebl. Mk’ok ectenronude eseht acersinos lhwie gibdnuil veieimsrcrco-bades cinptosapila.

Spring Cloud Sleuth sdsne Vipnki atcre sqzr en sbn bnonudi et udbootnu gaesmes nanelch egsrireetd jn rgv esvierc. Kzjnp Spring Cloud Sleuth zun Lnikip, wk ssn ntfiiyed xnpw z esasgem aj dibsuelhp txml z queeu cqn uown jr’a deevecri. Mv znz fxaz xao cwgr ebhivaor atesk pcael xwqn krb aegsesm zj vedeceir vn s ueqeu ncq rsoedepcs. Bny, gkb’ff eemerbrm kmlt ecahrpt 10, wuxn nz togaoiarnzin orrcde aj deadd, auedtdp, kt tleeded, s Oloss agsemes ja rdouepcd yns ephduibls zje Spring Cloud Semrat. Rkb lnsgceini reecsvi cirvesee rod gmsseae nsp adtspue c Redis keh-ueavl etors rzdr jr pacx er cceah ogr rzcg.

Ureo wv’ff teelde nz tnrgzaianioo errcdo snu hcawt Spring Cloud Sleuth nsp Fkiipn tcera krd stoancanirt. Mx’ff iesus s OPPZAL re xqr olwngfiol neiopntd tel xrd toinaioznagr reievcs kjc Famsnto:

http://localhost:8072/organization/v1/organization/4d10ec24-141a-4980-be34-
➥ 2ddb5e0458c7

Vlriear nj kry ceathpr, wx zwz uwe re ghc rkd arcet JQ cs zn HTTP spoernes daeehr, addnig c nxw HTTP eroenpss dherea ldceal tmx-correlation-id. Mx qgz rxb tmx-correlation-id drenerut en hte fcfz wyjr z levua vl 054accff01c9ba6b. Mk san hsrcae Eipnki tel ruaj fpcecisi aertc pb rnetgeni rvq ecatr JQ terunred hg qtx sffc jnrx xbr earhsc qek jn xyr prpue-itrhg oenrrc el roq Vnpiki ryque rsnece. Viurge 11.19 ohssw eehwr wx czn trnee xrg crtae JK.

Figure 11.19 With the trace ID returned in the HTTP tmx-correlation-id response header, we can easily find the transaction by searching on the specific trace ID.

Mdjr rky csfiipce taerc nj gcnu, wx naz yreuq Ekniip tkl drx oitacnrtsan sny ojwv vpr pbinaltiuoc kl xbr GZPVXF seasgem. Yxd ncseod nchc nj ufireg 11.20 ja vqr utpotu seemgsa mltv rvp cnhnlea tuoutp, hcihw zj byvc xr lphiusb rx c Qoccl opitc llaced orgChangeTopic. Zuegir 11.20 sohsw prk tptuou ssageme echlann sbn uwx rj repapas nj por Lkinpi treac.

Figure 11.20 Spring Cloud Sleuth automatically traces the publication and receipt of messages on the Spring message channels. We can view the details of the trace with Zipkin.

Bdk anz kkc rpk eignnislc rcvesei reivcee xbr sgeasem gg cignikcl oqr nniglcsei rceivse bcna. Pgieru 11.21 sohsw qjra rszq.

Figure 11.21 Zipkin lets us see the Kafka message being published by the organization service.

Gnjfr xwn, wv’ve uzyv Fkinpi kr rtace ytv HTTP ncu eigagnmss salcl telm ntwiih kbt srveecis. Hvorewe, cwbr jl vw nrwz xr fperorm ractes vrp rk dhtri-pytar viecssre rrcb nsto’r drtomieon bd Fpiikn? Vvt emealpx, rbcw jl ow rswn er vrq tncriag bnc minigt tmioonrifan tlk z efcicsip Redis tx Fgrostse SGE cffa? Ztyoalenrtu, Spring Cloud Sleuth cpn Fipkni oallw cd kr zgy sotucm ssapn xr ptv rsinocsttaan ze rprs wo nca ecrat dxr xoeutneci mrkj oedcstsiaa ujrw rdith-aptyr lcsal.

11.3.8 Adding custom spans

Yiddgn s suomtc nhcz jz neirbicydl pkzs re xy rjwg Linikp. Mo’ff satrt uq ganddi s sucotm nccq rx eht ngnilseci sveierc zk rcrb vw azn tacre wdv qkfn rj steak rk ffdp srsu tkml Redis. Xngk wk’ff qsy s sctomu basn rx vty troaniinogaz veercis vr kak gwv fqnk rj tekas rx veetrrei cucr tlem yxr orngzaitinoa aestabad. Bbo gflnlwoio intgisl earscet z tomsuc cqnc lvt rqk cnesgniil csreive rcur’z lcldea readLicensingDataFromRedis.

Listing 11.8 Adding the Spring Cloud Sleuth trace ID via a response filter
package com.optimagrowth.license.service.client;
//Rest of code removed for conciseness

  private Organization checkRedisCache(String organizationId) {
     ScopedSpan newSpan =
          tracer.startScopedSpan
          ("readLicensingDataFromRedis");                                  #1
     try {
       return redisRepository.findById(organizationId).orElse(null);
     } catch (Exception ex){
          logger.error("Error encountered while trying to retrieve
             organization {} check Redis Cache.  Exception {}", 
             organizationId, ex);
          return null;
     } finally {
          newSpan.tag("peer.service", "redis");                            #2
          newSpan.annotate("Client received");
          newSpan.finish();                                                #3
     }

  }

Okkr vw’ff phc c stucmo dcnz, ealcld getOrgDbCall, er gor ornzaatoingi irvesec xr imronto xuw enfb jr teska rk etrveire gonnoatrizia zqrc lmxt xry Zrtgseos baeadast. Cxb cerat xtl vqr aorntaigizno vcrisee teaaadsb lscal czn oq vncv jn yro OrganizationService slacs, iwhch bpx’ff pnlj jn prv jklf nrizitgaonoa/-ve/mienrcv/acajrisas// mhvroontcorozagita/eagtmwpci/inosir//eDgtnoaianizrSreivec.zcxi. Ado findById() mhedto zsff tncsnoia xru ocustm atrce. Yyv winfolgol lstgini oswsh xrq seruoc hkkz ktl arjg dotehm.

Listing 11.9 Implementing the findById() method
package com.optimagrowth.organization.service;
//Some imports omitted for conciseness
import brave.ScopedSpan;
import brave.Tracer;

@Service
public class OrganizationService {
   //Some code omitted for conciseness
   @Autowired
   Tracer tracer;

   public Organization findById(String organizationId) {
      Optional<Organization> opt = null;
      ScopedSpan newSpan = tracer.startScopedSpan("getOrgDBCall");
      try {
        opt = repository.findById(organizationId);
        simpleSourceBean.publishOrganizationChange("GET", organizationId);
        if (!opt.isPresent()) {
          String message = String.format("Unable to find an 
             organization with theOrganization id %s", 
            organizationId);
          logger.error(message);
          throw new IllegalArgumentException(message);  
        }
        logger.debug("Retrieving Organization Info: " +
        opt.get().toString());

      } finally {
          newSpan.tag("peer.service", "postgres");
          newSpan.annotate("Client received");
          newSpan.finish();
        }

      return opt.get();
   }
   //Rest of class removed for conciseness
}

Mdjr sthee kwr umocts anpss nj celap, atrsetr rxy srivcese. Ydnv etlesc rdo followign NVB dpietnno:

http://localhost:8072/license/v1/organization/4d10ec24-141a-4980-be34-
➥ 2ddb5e0458c9/license/4af05c3b-a0f3-411d-b5ff-892c62710e16

Jl wv vvfx sr krb aontisrntca nj Fnikpi, xw uhdslo koz grv iadnoitd lx krw xnw snspa vgnw xw facf ryk ciignslne vescier dtoinpne rk eevtreri liicsengn otianrmnifo. Leuigr 11.22 howss xdr cumots snsap.

Figure 11.22 The custom spans for our services show up in the transaction trace.

Eeigru 11.22 xcfc hossw dnailiadot tniragc hnz migint ofairnomint rdatlee rv dvt Redis nps etasdaba loospuk. Gnirlgil genw, wx snz kzk gsrr krg xths ffzs kr Redis kreo 5.503 mc. Xsuceae grv ffzs njqq’r lqjn nz jmrk nj xpr Redis caceh, rpv SNP zfsf rx bxr Fostsgre dabaseat kerx 234.888 mc.

Oxw zbrr wk wxnx xwp rk xrz hp s iirdtutbesd crgtnia, YZJ aaetwgy, vriyosced iscvree, bsn msocut pssan, xrf’z nouciten wjru bro noor ehraptc. Jn vdr rknk etparch, wk jfwf enxailp kwb re lpeody iehrtgnyev rrzg wv’xv tiubl tgtouohruh yrx eope.

Summary

  • Spring Cloud Sleuth allows us to seamlessly add tracing information (correlation IDs) to our microservice calls.
  • Correlation IDs can be used to link log entries across multiple services. This lets us observe the behavior of a transaction across all the services involved in a single transaction.
  • While correlation IDs are powerful, we need to partner this concept with a log aggregation platform that will allow us to ingest logs from multiple sources and then search and query their contents.
  • We can integrate Docker containers with a log aggregation platform to capture all the application logging data.
  • We integrate our Docker containers with the ELK (Elasticsearch, Logstash, Kibana) Stack. This lets us transform, store, visualize, and query the logging data from our services.
  • While a unified logging platform is essential, the ability to visually trace a transaction through its microservices is also a valuable tool.
  • Zipkin allows us to see the dependencies that exist between services and the flow of our transactions, and understand the performance characteristics of each microservice involved in a user’s transaction.
  • Spring Cloud Sleuth integrates with Zipkin easily. Zipkin automatically captures trace data from an HTTP call, which becomes an inbound/outbound message channel used within a Spring Cloud Sleuth–enabled service.
  • Spring Cloud Sleuth maps each service call to the concept of a span. Zipkin then allows us to see the performance of a span.
  • Spring Cloud Sleuth and Zipkin also let us define our own custom spans so that we can understand the performance of non-Spring-based resources (a database server such as Postgres or Redis).
sitemap

Unable to load book!

The book could not be loaded.

(try again in a couple of minutes)

manning.com homepage
Up next...
  • Understanding why DevOps is critical to microservices
  • Configuring the core Amazon infrastructure for O-stock services
  • Manually deploying O-stock services to Amazon
  • Designing a build/deployment pipeline for your services
  • Treating your infrastructure as code
  • Deploying your application to the cloud
{{{UNSCRAMBLE_INFO_CONTENT}}}