Aceasta e prima parte dintr-o serie de cinci articole despre observabilitate cu Application Insights și OpenTelemetry. Începem cu fundația conceptuală: cei trei piloni și ce întrebare răspunde fiecare. În părțile următoare: Serilog cu structured logging, distributed tracing cu OpenTelemetry, custom metrics cu dashboards și KQL pentru investigarea incidentelor.
Monitorizare vs. observabilitate
Monitorizarea răspunde la întrebări pe care le-ai anticipat: „e serviciul up?”, „e CPU-ul sub 80%?”. Observabilitatea răspunde la întrebări pe care nu le-ai anticipat: „de ce request-urile tenant-ului X din ultimele 20 de minute durează de 5 ori mai mult, dar doar pe endpoint-ul de căutare?”
Diferența e practică: în producție, incidentele interesante sunt aproape mereu cele neanticipate. Un sistem observabil îți permite să pui întrebări noi datelor deja colectate, fără să redeployezi cu logging suplimentar și să aștepți reproducerea problemei.
Cei trei piloni — log-uri, metrici, trace-uri — sunt trei forme de telemetrie cu puncte forte diferite. Confuzia dintre ele duce la sisteme care loghează tot (scump și greu de căutat) sau măsoară tot (fără context la incident).
Log-urile: ce s-a întâmplat, cu context
Un log e o înregistrare discretă a unui eveniment: „request-ul X a eșuat cu eroarea Y pentru tenant-ul Z”. Punctul forte: contextul bogat — toate detaliile momentului, exact ce ai nevoie când sapi într-un incident concret.
Punctul slab: volumul. Log-urile cresc liniar cu traficul, iar căutarea în ele fără structură devine arheologie. De aici două reguli:
- Structured logging obligatoriu — parametri numiți, nu interpolări de string; fiecare log devine un obiect interogabil (partea 2 e dedicată acestui subiect)
- Nivelurile au sens operațional — Information pentru fluxul normal semnificativ, Warning pentru anomalii recuperabile, Error pentru eșecuri care cer atenție. Debug nu ajunge în producție decât temporar și țintit.
// Log cu context -- interogabil dupa orice parametru
_logger.LogWarning(
"Rate limit atins pentru {TenantId} pe {Endpoint}, {RequestCount} requests in {WindowSeconds}s",
tenantId, endpoint, requestCount, windowSeconds);
Metricile: cât de des și cât de rău
O metrică e o valoare numerică agregată în timp: request-uri pe secundă, latență p95, adâncimea cozii, rata de erori. Punctul forte: agregarea ieftină — milioane de evenimente devin câteva serii de timp compacte, perfecte pentru dashboards și alerte.
Punctul slab: pierderea contextului individual. Metrica îți spune că rata de erori a sărit la 3%, dar nu care request-uri, pentru cine, cu ce mesaj. Metricile detectează, log-urile și trace-urile explică.
Distincția crucială la latență: media minte. O medie de 200ms poate ascunde 5% din utilizatori care așteaptă 4 secunde. Percentilele (p50, p95, p99) sunt limbajul corect — p95 = 95% din request-uri sunt sub această valoare.
Trace-urile: pe unde a trecut request-ul
Un trace urmărește un request prin toate serviciile pe care le atinge: API-ul primește cererea, apelează Cosmos DB, publică în Service Bus, un worker consumă mesajul, apelează Azure OpenAI. Fiecare pas e un span cu durată proprie; toate span-urile partajează același trace id.
Punctul forte: viziunea cap-coadă în sisteme distribuite. Request-ul durează 3 secunde — trace-ul îți arată vizual că 2.4 din ele sunt un singur apel către un serviciu extern. Fără tracing, aceeași concluzie cere corelarea manuală a log-urilor din 4 servicii.
Exemplu concret din arhitectura seriei: un mesaj de chat trece prin API → verificare limită în Cosmos → cache semantic → Azure OpenAI → salvare răspuns. Când utilizatorul raportează „chat-ul e lent”, trace-ul răspunde imediat: e OpenAI-ul, e Cosmos-ul sau e codul tău?
Cum se completează: anatomia unei investigații
Cei trei piloni nu concurează — formează un flux de investigație:
- Metrica detectează — alerta: p95 pe endpoint-ul de chat a sărit de la 800ms la 4s
- Trace-ul localizează — deschizi trace-urile lente: 90% din timp e span-ul apelului Cosmos DB, doar pentru anumite partiții
- Log-ul explică — log-urile corelate pe trace id arată retry-uri 429: ai depășit RU-urile provizionate pe o partiție hot
Fără metrici, afli de la utilizatori. Fără trace-uri, ghicești unde e problema. Fără log-uri, știi unde dar nu de ce.
| Pilon | Întrebarea | Punct forte | Punct slab | În Application Insights |
|---|---|---|---|---|
| Log-uri | Ce s-a întâmplat? | Context bogat | Volum, cost | traces (tabela) |
| Metrici | Cât de des / cât de rău? | Agregare ieftină, alerte | Fără context individual | customMetrics, performanceCounters |
| Trace-uri | Pe unde a trecut? | Viziune distribuită cap-coadă | Sampling la volum mare | requests + dependencies |
O confuzie de evitat din start: în Application Insights, tabela numită traces conține log-urile, iar trace-urile distribuite trăiesc în requests și dependencies. Nomenclatura istorică derutează pe toată lumea o dată — acum știi dinainte.
Application Insights + OpenTelemetry: direcția
Application Insights e backend-ul de telemetrie din Azure Monitor: primește, stochează și indexează toate cele trei tipuri, cu Kusto Query Language (KQL) deasupra. Istoric, instrumentarea se făcea cu SDK-ul clasic Application Insights; direcția actuală, susținută de Microsoft, e OpenTelemetry — standardul deschis de instrumentare, cu Azure Monitor ca exporter.
Practic: instrumentezi o singură dată, în standard deschis, și poți schimba backend-ul fără să rescrii instrumentarea. În partea 3 configurăm exact acest setup pentru ASP.NET Core și Azure Functions.
Ce urmează
În partea a doua facem log-urile serioase: Serilog cu structured logging, sink-ul de Application Insights, enrichers pentru context automat (tenant, versiune, instanță) și configurarea nivelurilor per namespace.
Întrebări? Scrie-mi la contact@ludoprogramming.com.