OpenTelemetry v JavaScriptu nestačí zapnout. Bez Collectoru rychle ztrácíte kontrolu

OpenTelemetry v JavaScriptu má smysl hlavně v Node.js: stabilní jsou traces a metrics, logs zůstávají ve vývoji a browserová instrumentace je experimentální. SDK ale není architektura observability. Sampling, sanitizaci citlivých atributů, kardinalitu i export má držet Collector, ne samotná aplikace.
Nálepky:
OpenTelemetry v JavaScriptu dnes dává dobrý smysl hlavně v Node.js: oficiální dokumentace uvádí traces a metrics jako stabilní, logs v JS zůstávají ve vývoji a klientská instrumentace v prohlížeči je z velké části experimentální. SDK ale není architekturou observability. Aplikace má vyrábět smysluplné signály; objem, sampling, citlivá data a export patří do Collectoru nebo jiné centrální vrstvy.
OpenTelemetry se v JavaScriptu snadno prodává jako jednoduchý krok: přidáte SDK, zapnete auto‑instrumentaci, nastavíte OTLP endpoint do SaaS a najednou máte traces, metrics a časem i logs. U malého pilotu to může stačit. V produkci je to zkratka, která začne bolet ve chvíli, kdy observability přestane být hezký dashboard a začne být součástí provozu.
Problém není v tom, že by OpenTelemetry v JavaScriptu bylo nepoužitelné. Pro Node.js dnes dává velmi dobrý smysl, hlavně u traces, základních metrik a běžných auto‑instrumentací pro HTTP i běžně používané knihovny. Problém je v představě, že SDK samo vyřeší architekturu sběru, transportní chování, sampling, čištění citlivých dat, kardinalitu a budoucí změnu backendu. Nevyřeší. SDK běží v aplikaci. Pravidla pro telemetrii mají být mimo ni.
Stabilita není rovnoměrná
Nejdřív stav věcí. OpenTelemetry JavaScript dnes uvádí traces a metrics jako stable, logs jako development. Ve stejné dokumentaci stojí, že browser client instrumentation je experimentální a z velké části ještě nespecifikovaná. „OpenTelemetry v JS“ proto není jeden stejně zralý celek, ale několik rozdílně hotových částí.
Důležitý je i rozdíl mezi specifikací a implementací. Specifikace OpenTelemetry už logging vede jako stabilní oblast včetně Bridge API, SDK a OTLP protokolu. Stabilní implementace logů pro JavaScript na úrovni traces a metrics tam ale ještě není. Balík @opentelemetry/api-logs je popsaný jako experimentální API pro unstable Logs Bridge API a také OTLP log exportery v JS ekosystému, například @opentelemetry/exporter-logs-otlp-http, zůstávají v experimentální části stromu balíků. Jestli dnes v Node.js potřebujete spolehlivé aplikační logy, rozumnější cesta často zůstává strukturovaný JSON na stdout a ingest přes Collector nebo existující log pipeline.
Node.js má ještě jeden detail: balík @opentelemetry/sdk-node je stále označený jako experimentální, i když nad ním stojí běžné quickstarty a poskytuje pohodlný jednotný vstup pro tracing a metrics. To neznamená „nepoužívat“. Znamená to „nevnímat jako důkaz zralosti celého stacku“.
Browser je pohyblivější část ekosystému. Samostatný repozitář opentelemetry-browser popisuje budoucí domov browser SDK a instrumentací, zaměřený mimo jiné na instrumentace událostí pro měření výkonu a uživatelských interakcí. Současně rozlišuje stabilnější základní browserové balíky od experimentálních instrumentací typu fetch, XHR, document load, long task nebo user interaction. Pro frontend to znamená vyšší pohyb pod nohama než u Node.js.
Co patří do SDK a co do Collectoru
Častá chyba je brát SDK jako architekturu observability. Není jí. SDK v aplikaci umí vytvořit spans, metriky a kontext, ale neumí být neutrálním kontrolním bodem mezi službami a backendem. Jakmile exportujete přímo do SaaS, dáváte pravidla do každé aplikace zvlášť: co se sampleuje, co se zahazuje, co se maskuje, jak se chová retry, co se stane při výpadku ingestu a jak se jednou změní backend.
Dokumentace OpenTelemetry k variantě bez Collectoru popisuje právě tyhle nevýhody: silnější vazbu aplikace na backend, nutnost měnit kód nebo konfiguraci při změně zpracování dat a omezení podle exporterů dostupných v daném jazyce. Přímý export je dobrý pro první pokus, lokální vývoj nebo malou službu. Jako výchozí produkční model pro více služeb je to technický dluh s hezkým názvem.
Collector plní jinou roli. Přijímá telemetry, zpracovává je a posílá dál. V praxi je to místo, kde se řeší batch, retry, fronty, komprese, filtrování, routing, fan‑out do více backendů, mazání nebo maskování citlivých polí a sampling. Komponenty Collectoru – receivers, processors, exporters, connectors a jejich konfigurace – existují právě proto, aby se podobná pravidla nekopírovala do každé služby.
Architektonicky je to důležitější než volba konkrétního SaaS. SaaS backend můžete vyměnit. Aplikační kód naplněný exportery konkrétního vendora, speciálními atributy, ad hoc filtry a náhodným samplingem se mění mnohem hůř.
Praktické dělení může být jednoduché. Přímý export stačí pro lokální vývoj, demo, proof of concept nebo jednu malou interní službu s nízkým objemem dat. Lokální Collector jako agent dává smysl tam, kde chcete standardizovat transport a odlehčit aplikaci. Gateway Collector je vhodný ve chvíli, kdy potřebujete sdílenou politiku napříč službami, více backendů, centrální mazání nebo úpravu atributů a kontrolu nákladů. Agent‑to‑gateway topologie je pak přirozená volba pro větší systémy, zejména pokud chcete dělat tail sampling nad celými traces.
Co má zůstat v Node.js
V Node.js má SDK dělat hlavně to, co žádná mezivrstva sama nevymyslí: aplikační sémantiku. Auto‑instrumentace vám dá HTTP requesty, databázové dotazy, fronty a runtime signály. Jenže neví, že payment.capture je pro vás důležitější než GET /api/v1/payments/123, nezná rozdíl mezi free a enterprise tenantem, neví, která feature‑flag varianta je relevantní a nepojmenuje interní operace tak, aby je po incidentu pochopil někdo mimo tým.
Dobrá ruční instrumentace v Node.js proto přidává doménové spans, stabilní názvy operací a atributy s nízkou kardinalitou: tenant.plan, payment.provider, cache.result, feature_flag.variant, queue.name, job.type. Špatná instrumentace přidává user.id, session.id, plnou URL, raw User‑Agent, e‑mail, query string a náhodné request headers. V trace to může mít forenzní hodnotu, ale pro metriky a dlouhodobý provoz je to téměř vždy problém.
HTTP je dobrý příklad. Semantic conventions pro HTTP spans říkají, že http.route má být hodnota s nízkou kardinalitou, kde dynamické části cesty reprezentují placeholdery. Tedy /users/:id/orders/:orderId, ne /users/123/orders/987. Stejná logika platí pro metriky ještě přísněji. Metrika má agregovat, ne nést kompletní diagnostický otisk každého requestu.
Collector má naopak dostat pravidla, která mají platit napříč službami: drop healthchecků, mazání authorization a cookie, hashování nebo odstranění user.email, limity front, retry, rozdělení podle prostředí, export do dvou backendů nebo tail sampling. Taková pravidla nemají být knihovna v každé službě. Mají být platformní politika.
Collector ale není omluva pro sběr všeho. Co aplikace nemá sbírat vůbec, nemá se do pipeline dostat ani dočasně. Následující fragment proto není kompletní konfigurace, spíš ukázka hranice mezi aplikací a platformou:
<a href="#cb1-1"></a>processors:
<a href="#cb1-2"></a> memory_limiter:
<a href="#cb1-3"></a> check_interval: 1s
<a href="#cb1-4"></a> limit_mib: 512
<a href="#cb1-5"></a>
<a href="#cb1-6"></a> filter/drop-noise:
<a href="#cb1-7"></a> error_mode: ignore
<a href="#cb1-8"></a> traces:
<a href="#cb1-9"></a> span:
<a href="#cb1-10"></a> - attributes["http.route"] == "/healthz"
<a href="#cb1-11"></a> - attributes["http.route"] == "/metrics"
<a href="#cb1-12"></a>
<a href="#cb1-13"></a> attributes/sanitize:
<a href="#cb1-14"></a> actions:
<a href="#cb1-15"></a> - key: http.request.header.authorization
<a href="#cb1-16"></a> action: delete
<a href="#cb1-17"></a> - key: http.request.header.cookie
<a href="#cb1-18"></a> action: delete
<a href="#cb1-19"></a> - key: user.email
<a href="#cb1-20"></a> action: hash
<a href="#cb1-21"></a>
<a href="#cb1-22"></a> batch:Code language: HTML, XML (xml)
action: hash berte jen jako technickou ukázku. U e‑mailů nebo zákaznických identifikátorů je často lepší atribut vůbec neposílat; hash sám o sobě není anonymizace, pokud je vstupní prostor malý a předvídatelný.
Aplikace má poslat správný kontext a správně pojmenované operace. Collector má rozhodnout, co z toho smí odejít dál, v jakém objemu a komu.
Sampling patří tam, kde má dost informací
Sampling je další místo, kde přímý export rychle narazí. JavaScript SDK umí head sampling: rozhoduje na začátku trace a je levný. Zároveň ale neví, jestli request později skončí chybou, bude pomalý nebo povede přes drahou integraci. Head sampling je dobrá brzda objemu, ne chytrá provozní politika.
Tail sampling rozhoduje až po zpracování celého trace. Umí zachovat všechny chybové nebo pomalé traces a zbytek zředit. Jenže potřebuje vidět celý trace. Proto agent‑to‑gateway pattern doporučuje držet tail sampling na gateway vrstvě a zajistit, aby všechny spans jednoho trace dorazily do stejné Collector instance. Lokální Collector u každé služby nebo přímý export do SaaS tohle obvykle neřeší čistě.
V malém systému se to dá ignorovat. Ve větším skončíte buď s přestřeleným objemem, nebo se samplingem, který zahazuje přesně ty traces, které jste při incidentu potřebovali.
Kardinalita je účet, který přijde později
Kardinalita není estetický problém dashboardů. Je to paměť, ingest, cena, latence dotazů a nepřehlednost signálů. Doplňkové pokyny pro metriky ukazují jednoduchý příklad: sedm atributů po třiceti hodnotách dává přes 21 miliard kombinací. V produkci se k podobné situaci obvykle nedostanete přes jeden špatný atribut, ale přes sérii „užitečných detailů“, které nikdo nezastavil.
Typický scénář vypadá nevinně. Někdo přidá do span atributů request ID, tenant slug, plnou cestu, e‑mail uživatele, user agent a pár hlaviček přes headersToSpanAttributes z @opentelemetry/instrumentation-http. Dokud se na to díváte v jednom trace, působí to prakticky. Jakmile se stejná data dostanou do metrik, agregací nebo indexů backendu, zaplatíte za ně víckrát.
Ještě horší je smíchání observability a osobních údajů. OpenTelemetry security guidance říká napřímo, že odpovědnost za citlivá data je na implementátorovi. Collector umí mazat, hashovat, maskovat a transformovat atributy, ale sám za vás nerozhodne, že user.email, token v query stringu nebo interní customer ID nemají odejít do externího backendu.
Pravidlo pro metriky je prosté: atribut má být použitelný jen tehdy, když předem umíte odhadnout rozumný počet hodnot. http.method, http.route, http.response.status_code, deployment.environment, tenant.plan nebo payment.provider obvykle projdou. user.id, session.id, url.full, order.id, raw User‑Agent a query string obvykle ne.
Browser má jiná pravidla než server
Na frontendu se přidává další sada limitů. Browser není malý server. Dokumentace JS exporterů připomíná, že v browseru není k dispozici OTLP/gRPC, používá se OTLP/HTTP a musíte řešit CORS, CSP a veřejně dostupný endpoint. Stejná dokumentace doporučuje nedávat Collector přímo na veřejný internet, ale schovat ho za reverzní proxy, která řeší TLS, CORS a další webové požadavky.
První brzda je tedy technická. Druhá souvisí s povahou dat. Frontend observability není jen error monitoring. Pokud chcete měřit skutečné UX, budete řešit Core Web Vitals, navigace, soft navigations ve SPA, latenci fetch/XHR z pohledu uživatele, user actions, korelaci s backend trace a někdy i session replay. To všechno má jiný objem dat, jinou hodnotu a jiné dopady na soukromí.
Web Vitals dnes stojí hlavně na LCP, INP a CLS. FID byl 12. března 2024 nahrazen INP jako jedna z metrik Core Web Vitals; přechod popisuje web.dev článek k zavedení INP. CrUX release notes potvrzují odstranění FID z CrUX a samostatný web.dev článek o konci podpory FID uvádí, že FID už není podporovaný v Chrome performance nástrojích. Pokud frontend observability pořád staví hlavně na FID, zůstává u starých dashboardů.
Session replay je ještě citlivější. rrweb, na kterém stojí řada replay řešení, má maskování, blokování elementů a ignorování input eventů. To ale není bezpečnostní kouzlo. Příliš široký replay může sebrat osobní údaje z DOM textu, formulářů, URL nebo chybových hlášek. Do stejné pipeline jako běžné web vitals to nepatří.
U frontendu proto nejdřív vyřešte právní režim sběru včetně případného souhlasu, rozsah dat a sampling. Exporter přijde až potom. Teprve pak dává smysl normalizovat route, zahodit nebo maskovat citlivé atributy, omezit objem, poslat data přes vlastní edge endpoint a až odtud do Collectoru nebo observability backendu. U evropských služeb je potřeba posoudit sběr podle ePrivacy, GDPR a národní implementace. Jako evropský opěrný bod se hodí zejména EDPB Guidelines 2/2023 k technickému rozsahu článku 5(3) ePrivacy Directive. ICO guidance ke storage a access technologies sice není český ani unijní výklad po brexitu, ale dobře ukazuje, jak úzce se mohou vykládat výjimky pro měření bez souhlasu.
Přímý export má své místo, ale nemá být cílová architektura
Přímý export do SaaS někdy dává smysl. Pro proof of concept, jednu interní službu, demo nebo lokální vývoj je nejrychlejší. Někde může zůstat i v produkci, pokud tým vědomě přijme silnou vazbu na backend, malý objem dat a nízké riziko úniku citlivých údajů.
Jakmile ale máte více služeb, frontend, několik prostředí, compliance požadavky nebo potřebu udržet náklady pod kontrolou, SDK‑only model přestává být pohodlný. V Node.js instrumentujte doménové operace, stabilní šablony rout a atributy s omezeným počtem hodnot. V Collectoru držte batch, retry, fronty, transformace, mazání citlivých dat, sampling a export. V browseru začněte úzce: Web Vitals, chyby, vybrané navigace, agresivní sampling a žádný replay bez jasných pravidel ochrany soukromí.
OpenTelemetry má v JavaScriptu smysl. Jen se nesmí nasadit jako nový způsob, jak poslat neupravený provozní šum do jiného backendu. OTLP je jen transportní jazyk. Rozdíl udělá až disciplína v tom, co sbíráte, kde to krátíte a kdo za to platí.