Hoppa till innehållet
Kom igång
Kom igång

Fyra steg till första händelsen

Installera paketet, anropa initTelemetry med er nyckel, kör install för de globala felhanterarna, och fånga det ni själva vill fånga med captureError. Maskningen är redan på, och taket är redan satt.

3Rader för att börja skickainitTelemetry, install och er nyckel
21Fältnamn som maskas innan något lämnar enhetenDEFAULT_SCRUB i packages/telemetry
0 krPlanen Fri, 500 000 händelser i månadenPriser ur @gaddr/pricing
Från installation till första felet i vyn, med maskningen redan på.
Tre steg

Ett paket, en nyckel, och första felet är inne

Inget agentpaket att installera på servern och ingen sidovagn att driva. Klienten skickar direkt, och buffrar när nätet är nere.

  • En optisk transceiver isärtagen
    Ett. Installera paketet och sätt nyckeln i miljön.
  • Ett kretskort med komponenter
    Två. Fånga felet där det uppstår, med källkodskarta.
  • Ett datacenter utifrån
    Tre. Se det i panelen, grupperat och med spår.
  • Klienten skickar direkt och buffrar när nätet är nere.
  • Ingen agent på maskinen och ingen sidovagn bredvid tjänsten.
  • Första felet ligger i vyn med spår och källkodsrad.
Steg 1

Installera klienten

Ett paket i er kodbas. Ingen agent på maskinen, ingen sidovagn bredvid tjänsten, och ingenting som ska startas om när ni ändrar en inställning.

  • Paketet fungerar i webbläsaren, i Node, i Deno och i Bun.
  • Inmatningsnyckeln är publik och får ligga i klientbygget. Den skriver bara, den läser aldrig.
  • Kör ni redan OpenTelemetry behöver ni inte det här paketet alls. Se vägen in via OTLP.
terminalInstallation
npm install @gaddr/telemetry
# eller
pnpm add @gaddr/telemetry
# eller
bun add @gaddr/telemetry

Nyckeln hämtar ni i projektets inställningar. Den börjar på gdr_pk_ och är publik, alltså behöver den ingen hemlighetshantering.

Nyckeln som bara skriverEn nyckel sitter i ett lås mitt i bilden. Ovanifrån går en ström in genom låset och vidare till lagret bakom. Nedanifrån möter en ström en spärr, stannar och vänder tillbaka.
Ett paket i kodbasen, ingenting att starta om.
Steg 2

Anropa initTelemetry

initTelemetry tar emot inställningarna, skapar klienten och sparar den som en singleton. Anropa den en gång, tidigt, i webbläsarens ingång.

app/entry.client.tsxTypeScript
1import { initTelemetry } from "@gaddr/telemetry";
2
3const log = initTelemetry({
4  ingestKey: "gdr_pk_din_nyckel",
5  environment: "production",
6  release: "web@2026.8.15",
7});
8
9log.install();

Tre rader räcker. Fältet release kopplar felet till versionen som körde, och därmed till commiten som byggde den. Utan release fungerar allt, men stackspåret pekar inte tillbaka på någon utgåva.

Vill ni nå klienten någon annanstans i koden gör ni det med telemetry(), som returnerar samma instans, eller null om initTelemetry inte har körts än.

app/lib/fel.tsTypeScript
1import { telemetry } from "@gaddr/telemetry";
2
3export function rapportera(fel: unknown) {
4  telemetry()?.captureError(fel);
5}

Frågetecknet är med flit. Körs koden på servern innan initTelemetry har anropats är telemetry() null, och raden gör då ingenting i stället för att kasta.

Varje inställning, med sitt standardvärde

Fälten i TelemetryConfig, med typ, standardvärde och vad de gör.
FältStandardVad det gör
ingestKeykrävsProjektets inmatningsnyckel. Publik, får ligga i klientbygget.
environmentkrävsdevelopment, staging eller production. Är den development skickas ingenting alls.
endpointhttps://log.gaddr.com/api/ingest/v1Var Gaddr Log tar emot. Byts bara vid drift i egen miljö.
releasesaknasVersionen som körs. Kopplar felet till en commit.
maxEventsPerSession100Taket per session. En loop som kastar tiotusen fel producerar hundra händelser.
sampleRate1Andel som skickas alls, mellan 0 och 1. Resten räknas i dropped.sampled.
scrubKeystom listaEgna fältnamn som alltid ska maskas. Läggs till standardlistan, ersätter den aldrig.

Fälten och standardvärdena är hämtade ur TelemetryConfig och konstruktorn i packages/telemetry/src/index.ts.

Taket och maskningen står satta redan i konstruktorn.
Steg 3

install kopplar in de globala felhanterarna

Ett anrop kopplar in tre lyssnare i webbläsaren och returnerar en funktion som kopplar loss dem igen. Körs koden på servern gör install ingenting och returnerar en tom funktion, så raden är säker att låta ligga.

  • error på fönstret fångar fel som inte tas om hand någon annanstans, med filnamnet och radnumret som kontext.
  • unhandledrejection fångar avvisade löften, med flaggan unhandledRejection i kontexten.
  • visibilitychange tömmer kön när fliken göms, så att det sista som hände inte försvinner med fliken.

Den returnerade funktionen tar bort alla tre lyssnarna och tömmer kön en sista gång. Det gör att en komponent som satte upp telemetrin kan städa efter sig, och att en omladdning under utveckling inte staplar lyssnare på varandra.

app/entry.client.tsxTypeScript
1const kopplaLoss = log.install();
2
3// Vid nedmontering, till exempel i en effekt eller i ett test:
4kopplaLoss();

install returnerar en funktion. Anropas den tas fönstrets och dokumentets lyssnare bort, och kön töms en sista gång innan allt släpps.

RÅHÄNDELSEREN ORSAKTypeErrorcart.total is undeffp 8c1d2f1282413771 NOTIS, INTE 377
De globala felhanterarna kopplas in med ett anrop.
Steg 4

Fånga det ni själva vill fånga

captureError tar felet och ett fritt objekt med sammanhang. Den plockar ut meddelande, stackspår, kod och spår-id ur felet, och maskar allt innan det lämnar enheten.

app/routes/kassa.tsxTypeScript
1try {
2  await slutforKop(order);
3} catch (fel) {
4  log.captureError(fel, {
5    ordernummer: order.id,
6    epost: "anna@example.se",
7    steg: aktivtSteg,
8  });
9  visaFelruta();
10}

Fältet epost träffar standardlistan och ersätts med [maskerad]. Hade adressen legat inuti meddelandet i stället hade mönstret för e-post ersatt den med [epost]. Båda vägarna är stängda.

Är det som kastades inte ett Error görs det om till ett, så att raden fungerar även när något kastar en sträng. Bär felet fälten code eller traceId plockas de upp och följer med händelsen.

server/jobb.tsTypeScript
1log.capture({
2  kind: "log",
3  level: "warning",
4  message: "Kön växer snabbare än den töms",
5  traceId: aktivtSpar,
6  context: { koLangd, arbetare },
7});
8
9await log.flush();
10log.stats(); // { sent, queued, dropped: { quota, sampled, transport } }

capture är den generella vägen in, med kind satt till error, log, span eller metric. flush skickar kön direkt i stället för att vänta ut timern på två sekunder, vilket är det ni vill i ett kortlivat jobb som avslutas.

  • dropped.quota räknas upp när taket per session är nått. Kvoten gjorde sitt jobb.
  • dropped.sampled räknas upp när ni själva har sänkt sampleRate.
  • dropped.transport räknas upp när överföringen misslyckades. Det är den siffran som ska vara noll.
Sammanhanget ni skickar med är det som gör felet läsbart.
På som standard

Det här maskas innan något lämnar enheten

Det finns ingen inställning som stänger av maskningen. Ni kan lägga till egna fältnamn, aldrig ta bort de som redan står i listan.

21 fältnamn, ordagrant ur DEFAULT_SCRUB

  • password
  • losenord
  • lösenord
  • token
  • secret
  • authorization
  • cookie
  • apikey
  • api_key
  • personnummer
  • ssn
  • card
  • kortnummer
  • cvc
  • cvv
  • iban
  • email
  • epost
  • e-post
  • phone
  • telefon

Jämförelsen görs gemen och på delsträng. Ett fält som heter kundEpost träffar alltså epost, och ett fält som heter API_KEY_V2 träffar api_key. Värdet ersätts med [maskerad].

Listan och jämförelsen ligger i DEFAULT_SCRUB och i funktionen scrub i packages/telemetry/src/index.ts.

5 mönster, oavsett vilket fält de står i

Mönstren i PATTERNS, med vad de träffar och vad de ersätts med.
VadFormenBlir
PersonnummerSex siffror, valfritt bindestreck eller plus, sedan fyra siffror[personnummer]
KortnummerTretton till nitton siffror, med eller utan mellanslag och bindestreck[kortnummer]
E-postadressNamn, snabel-a, domän och toppdomän[epost]
Nycklarsk_, pk_ eller rk_ följt av live eller test och minst tio tecken[nyckel]
BärartokenOrdet Bearer följt av ett värdeBearer [maskerad]
app/entry.client.tsxTypeScript
1const log = initTelemetry({
2  ingestKey: "gdr_pk_din_nyckel",
3  environment: "production",
4  scrubKeys: ["kundnummer", "leveransadress", "fodelsedatum"],
5});

scrubKeys läggs till standardlistan. Mönstren gäller alltid, också i meddelandet och i stackspåret, eftersom scrubString körs på båda.

Mönstren ligger i PATTERNS och körs av scrubString i packages/telemetry/src/index.ts. Maskningen går sex nivåer ned i ett nästlat objekt, och en lista kortas till femtio poster innan den skickas.

  • Maskningen är på från första händelsen.
  • Ingen inställning stänger av den.
Frågor

Det som brukar dyka upp under installationen

Svaren pekar på filen där beteendet ligger, inte på den här sidan.

Vanliga frågor

Får inmatningsnyckeln ligga i klientbygget?

Ja. Den är publik och skriver bara. Den läser ingenting och den ger ingen åtkomst till era data. Läcker den ändå återkallar ni den och skapar en ny i projektets inställningar.

Varför skickas ingenting när jag kör lokalt?

För att environment är satt till development. capture returnerar direkt i det läget, alltså kostar era lokala fel ingenting av kvoten. Sätt staging eller production när ni vill se händelserna.

Kan ett fel i telemetrin krascha vår app?

Nej. Misslyckas överföringen fångas det och räknas som transport i stats. Inget kastas vidare in i er kod, och den som besöker sajten märker ingenting.

Hur ofta skickas kön?

En timer på 2000 millisekunder samlar kön och skickar den i en bunt. Kön töms också när fliken göms, och ni kan tömma den själva med flush när ni vill.

Vad används för att skicka?

navigator.sendBeacon i första hand, eftersom den överlever att fliken stängs. Finns den inte, eller returnerar den falskt, används fetch med keepalive.

Hur vet jag att något faktiskt kommer fram?

log.stats() returnerar sent, queued och dropped. Är sent noll och dropped.transport högt når ni inte fram. Är dropped.quota högt fungerar taket som det ska.

Kostar det något att börja?

Planen Fri kostar 0 kr och tar emot 500 000 händelser i månaden. Behöver ni mer kostar Team det som står på prissidan, och taket är hårt i båda.

Vi kör inte JavaScript. Vad gör vi då?

Skickar OTLP från er egen instrumentering. Det ingår i planen Fri och kräver ingen agent på maskinen. Se språken.

Nästa steg

Delarna i produkten har varsin sida med vad de gör och var i koden påståendet går att kontrollera.

Första händelsen kan ligga inne i kväll.