Home

Posts

Tags

Understanding OpenTelemetry

An observability framework has following steps in pipeline

The framework does not provide a database to store the gigabytes of traces and metrics you generate. It simply delivers the package to the door. Storing telemetry is a massive scaling challenge. Different data types require different specialized databases. Common tools used here:

The framework doesn’t provide the “single pane of glass” or the dashboards you look at during an incident. It provides the raw material, not the UI. Visualization is subjective. One team might want a real-time heat map, while another wants a simple line graph or an automated Slack alert. Common tools used here:

Instrumentation

Zero code instrumentation (or auto instrumentation), is the “Path of Least Resistance” for getting observability into an application. Instead of we manually writing code to start timers or log metadata, the agent does it for you by “hooking” into your runtime.

When you run your application via the opentelemetry-instrument agent, it intercepts calls to popular libraries (like FastAPI, Flask, requests, or SQLAlchemy).

If your app makes a database query, the agent “sees” it, measures how long it took, and automatically creates a Span for that query.

I will be using Python programming lanague, with fastapi for api server.

To get started with zeo code instrumentation, install the following package opentelemetry-distro. When you install opentelemetry-distro, it sets up several critical components behind the scenes:

Traces

Check out the source code for this project:

  • Loading...
Select a file to view code
// Code will appear here

This is what printed on console when I make request to / endpont:

aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaappppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii--------------------------------------------------------------------------------------------------------11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111I{}{}{}NFO:""}"""""}"}"""}""}"""""}"}"""}""}"""""}"}"""}nc,kpses,a,elrnc,kpses,a,elrnc,kpses,a,elraoiatnttvieaoiatnttvieaoiatnttviemnnradatensmnnradatensmnnradatenset"""der_t"r""nko"}"et"""der_t"r"nko"}"et"""der_t"r"""""""""""""nko"}""etst"nttusiahtsua,s"etst"nttusiatsua,s"etst"nttusihhnhhhhhhnnhhtsua,s1:xrpr:t_istbsts"rtc:xrpr:t_istbss"rtc:xrpr:t_istbttetttttteetts"rtc7taaa_tm"augt":cthtaaa_tm"aug":cthtaaa_tm"auttttttttttttt":cth2""cnc"iie:ttip:er"""""e""cnc"iie:tti:er"""""e""cnc"iie:ttpp.pppppp..pp:er"""""e.G:e_eSdm"ue..["itttstmG:e_eSdm"ue.["itttstmG:e_eSdm"ue..h......pp..["itttstm2E_i_p"e:{sses[]:beeeeeaE_i_p"e:{sse[]:beeeeeaE_i_p"e:{ssshoftumsueers[]:beeeeea2T{idsa:"_"vt],ulllrl_T{idsa:"_"v],ulllrl_T{idsa:"_"coslareeseeot],ulllrl_.d"tn:"c:ea,{teeeveud"tn:"c:e,{teeeveud"tn:"c:hstarltrerrua,{teeeveu0/":aK"2ontemmmimr/":aK"2onemmmimr/":aKn2oet.vg"hvr..ttemmmimr.:ti0"0d{tuseeecel:ti0"0d{tseeecel":tiu"0d{m"poe:oe_ipeuseeecel1h"enx22e.s"tttet"h"enx22e."tttet","enl22ee:ortdrapo"s"tttet":t"0"d206"t_:rrr.r:t"0"d206"t:rrr.r:"0"dl06""r""""_g"r:_:rrr.r:5t0x:.b2-:ycyyynyt0x:.b2-:yyyyny0x:.,2-::"t::h:ne:tcyyyny9pxcI660po{...a."pxdI660p{...a."x2S601"tan""{...a."972"N2-5"edsssma"7b"N2-5"esssma"7b"E-5""7:""t"mt":dsssma"7sae[T80-U"edddeusa3[T80-U"dddeua6[R0-Uh21pGe"1"edddeu8e99]E950N:"kkk"te9a]E950N:kkk"t92]V50Nt.8.":E":75,"kkk"tn42"R6-7S:...:on43"R6-7S...:o48"E-7St201,/T:29:...:o-d0bN90TE"lnv.d05N90TE"lnv.09R0TEp20"/"".9lnv."27A371Th2aae"v"21A371Thaae"v26"71T".0,1,"M272aae"v",8cLdT2"t0nmrme,81LdT2"tnmrme89,T2",0,21o280nmrmeG95"71:t0gesyr90"71:tgesyr931:.72z.,0gesyrEeb,823pu"i_se8,823pu"i_sed232.7i0u"i_sT397:6.a:oai387:6.a:oai37:6:0.l.a:oai2e73:rgnpo2973:rgnpo283:8.0l1gnpo/36c62ee""in37c62ee""in376200.a"e""in5db:5s"o:_"54b:5s"o:_"57:50.0,"o:_"Hf6"2.p:ps:f6"2.p:ps:fc2.01.5:ps:T31,57oe"e3b,57oe"e3b57":1.e"eT9".8n"n1r"9".8n"n1r"9".8,8:0"n1r"P8,77spt.v08,78spt.v08,7808pt.v0/488eye4i.482eye4i.48200(ye4i.1277.tl1c6284.tl1c626700Mtl1c6.981she.e2920bhe.e2977/0ahe.e2183Ztom1"b83Zoom1"b87Z""com1"b"45"ane",140"dne",140",,ine",16Z,r"t,"6Z,y"t,"6Z,n"t,"2d"t,rd"",rd"t,r02,"y2,y2,oy05,"5"5s"f,f,fh,O111;Kbbb222I555nffft"""e,,,lMacOSX10.15;rv:150.0)Gecko/20100101Firefox/150.0",

The line INFO: 172.22.0.1:59978 - "GET / HTTP/1.1" 200 OK tells you what happened (a 200 OK), but not how it happened. This is where OTel takes over to provide the “how.”

The three JSON blobs that follow are all part of the same request. You can tell because they all share the exact same trace_id: 0x7a940289e3235f398429846d25f1b25f.

A. The Parent Span

Look for the one named GET / with kind": "SpanKind.SERVER.

parent_id": null This is the “Root Span.” It represents the total time the server spent on this request.

Duration: It started at .786 and ended at .788 seconds.

B. The Child Spans

The other two spans named GET / http send are children of the parent.

parent_id: 0x2b6289693d7877cb Notice this ID matches the span_id of the parent GET / span.

asgi.event.type since FastAPI is an ASGI framework, the OTel agent is catching the specific moments the server started the response (http.response.start) and finished sending the body (http.response.body).

Metrics

Metrics are “time-driven.”, they are snapshots of your system’s health.

It aggregates data (like how many total requests have hit /) over a period of time. Every 60 seconds (the default interval), it “exports” the current totals to your terminal.

You should see JSON like following after certain interval,

{}"]reso{}urce"]_smceotp{}rei_cmse"]"tm:reit[cr{}si"c:s"""}[:ndaa[mtea"]""d::at"{a{}h_tptopi""""".ncsmmastouiatesumnxtr"n"""rv:t:::ie"br[:124u.2.5tr1410ee50,.sq,.0"u5,:e,s{t."dhutrtapt.imoent"h,od":"GET","http.route":"/"}

Logs

The OTel agent can automatically “bridge” your standard Python logs into the OpenTelemetry pipeline. When you use logging.info("hello"), OTel intercepts it and attaches the current trace_id.

We have following log added in API endpoint:

il@dmoaepgpfogpre.rlrtrgeoeeagtl=tdguo(_ergl"rrngo/o.ig"oi{ng)tn"gi(fHn)oeg:(l."lgToeh"ti:Lso"glWgooegrrl(wd_i"_l}nlamneo_w_)includethetrace_idautomatically!")

You should see following printed in console

aaaaaaaaaaaaaaaaaaaaaaapppppppppppppppppppppppiiiiiiiiiiiiiiiiiiiiiii-----------------------11111111111111111111111{}"""""""""""}"bssadtotstr,eoeetribrprevdvvtomsaaaseyeerpeecnco"}"n"rripsre_eua,st:iibetv_i_rtc_ttudaeidfcthn"yyt_mdd"ler"""""eaT__eap_":a"itttstmmhntst"t:g:beeeeeaeiue"t:i"sulllrl_"smx:rm"0"{teeeveu:bti"e0x:emmmimrle"nb2sx2seeecel"or:uu0t591"tttet""g"lt2a79,:rrr.r::"le6m03yyynywI,s-p37{...a."i9N"0"5csssma"l,F:5:2bdddeulO-6akkk"t"00"06...:on,,72celnv.oT093aae"vw2223nmrme3639gesyri:-bbu"i_sn10e8a:oaic35d5gnpol:-b"e""inu205,"o:_"d670:ps:e.T9e"e22e"n1r"t237pt.v0h9:eye4i.e813tl1c6837he.e2t4:dom1"brZ22ne",1a"64"t,"c,.f,re29y_33"i07,d0a0"a3,uZt"o,matically!",

Visualization

For visualization, we shall be using Grafana with different storage backends.

SignalStorage BackendVisualization UI
TracesTempo (or Jaeger)Grafana (Explore tab)
MetricsPrometheus (or Mimir)Grafana (Dashboards)
LogsLokiGrafana (Log Explorer)

The signals (traces, metrics, and logs) from services will be sent to the Collector, so that,

Tags: