[{"data":1,"prerenderedAt":2382},["ShallowReactive",2],{"navigation_docs":3,"-use-cases-telemetry-ingest":612,"-use-cases-telemetry-ingest-surround":2377},[4,35,85,138,318,453,489,548,587],{"title":5,"path":6,"stem":7,"children":8,"page":34},"Start","\u002Fstart","1.start",[9,14,19,24,29],{"title":10,"path":11,"stem":12,"icon":13},"Introduction","\u002Fstart\u002Fintroduction","1.start\u002F1.introduction","i-lucide-info",{"title":15,"path":16,"stem":17,"icon":18},"Why start with evlog","\u002Fstart\u002Fwhy-evlog","1.start\u002F2.why-evlog","i-lucide-rocket",{"title":20,"path":21,"stem":22,"icon":23},"Installation","\u002Fstart\u002Finstallation","1.start\u002F3.installation","i-lucide-download",{"title":25,"path":26,"stem":27,"icon":28},"Quick Start","\u002Fstart\u002Fquick-start","1.start\u002F4.quick-start","i-lucide-zap",{"title":30,"path":31,"stem":32,"icon":33},"Choose your logger","\u002Fstart\u002Ftypescript-logging-library","1.start\u002F5.typescript-logging-library","i-lucide-file-code",false,{"title":36,"path":37,"stem":38,"children":39,"page":34},"Learn","\u002Flearn","2.learn",[40,45,50,55,60,65,70,75,80],{"title":41,"path":42,"stem":43,"icon":44},"Overview","\u002Flearn\u002Foverview","2.learn\u002F0.overview","i-lucide-list",{"title":46,"path":47,"stem":48,"icon":49},"Simple Logging","\u002Flearn\u002Fsimple-logging","2.learn\u002F1.simple-logging","i-lucide-terminal",{"title":51,"path":52,"stem":53,"icon":54},"Wide Events","\u002Flearn\u002Fwide-events","2.learn\u002F2.wide-events","i-lucide-layers",{"title":56,"path":57,"stem":58,"icon":59},"Structured Errors","\u002Flearn\u002Fstructured-errors","2.learn\u002F3.structured-errors","i-lucide-shield-alert",{"title":61,"path":62,"stem":63,"icon":64},"Lifecycle","\u002Flearn\u002Flifecycle","2.learn\u002F4.lifecycle","i-lucide-arrow-right-left",{"title":66,"path":67,"stem":68,"icon":69},"Sampling","\u002Flearn\u002Fsampling","2.learn\u002F5.sampling","i-lucide-filter",{"title":71,"path":72,"stem":73,"icon":74},"Auto-Redaction","\u002Flearn\u002Fredaction","2.learn\u002F6.redaction","i-lucide-eye-off",{"title":76,"path":77,"stem":78,"icon":79},"Typed Fields","\u002Flearn\u002Ftyped-fields","2.learn\u002F7.typed-fields","i-simple-icons-typescript",{"title":81,"path":82,"stem":83,"icon":84},"Catalogs","\u002Flearn\u002Fcatalogs","2.learn\u002F8.catalogs","i-lucide-book-open",{"title":86,"path":87,"stem":88,"children":89,"page":34},"CLI","\u002Fcli","3.cli",[90,93,98,103,108,113,118,123,128,133],{"title":41,"path":91,"stem":92,"icon":49},"\u002Fcli\u002Foverview","3.cli\u002F0.overview",{"title":94,"path":95,"stem":96,"icon":97},"init","\u002Fcli\u002Finit","3.cli\u002F1.init","i-lucide-wand-sparkles",{"title":99,"path":100,"stem":101,"icon":102},"map","\u002Fcli\u002Fmap","3.cli\u002F2.map","i-lucide-radar",{"title":104,"path":105,"stem":106,"icon":107},"Rules","\u002Fcli\u002Frules","3.cli\u002F3.rules","i-lucide-list-checks",{"title":109,"path":110,"stem":111,"icon":112},"Scoring","\u002Fcli\u002Fscoring","3.cli\u002F4.scoring","i-lucide-gauge",{"title":114,"path":115,"stem":116,"icon":117},"CI","\u002Fcli\u002Fci","3.cli\u002F5.ci","i-lucide-git-pull-request",{"title":119,"path":120,"stem":121,"icon":122},"doctor","\u002Fcli\u002Fdoctor","3.cli\u002F6.doctor","i-lucide-stethoscope",{"title":124,"path":125,"stem":126,"icon":127},"telemetry","\u002Fcli\u002Ftelemetry","3.cli\u002F7.telemetry","i-lucide-bar-chart-3",{"title":129,"path":130,"stem":131,"icon":132},"agents","\u002Fcli\u002Fagents","3.cli\u002F8.agents","i-lucide-bot",{"title":134,"path":135,"stem":136,"icon":137},"Observability Score","\u002Fcli\u002Fobservability-score","3.cli\u002F9.observability-score","i-lucide-activity",{"title":139,"path":140,"stem":141,"children":142,"page":34},"Integrate","\u002Fintegrate","4.integrate",[143,147,230],{"title":41,"path":144,"stem":145,"icon":146},"\u002Fintegrate\u002Foverview","4.integrate\u002F0.overview","i-lucide-plug",{"title":148,"path":149,"stem":150,"children":151,"page":34},"Adapters","\u002Fintegrate\u002Fadapters","4.integrate\u002Fadapters",[152,155,185,210],{"title":41,"path":153,"stem":154,"icon":44},"\u002Fintegrate\u002Fadapters\u002Foverview","4.integrate\u002Fadapters\u002F01.overview",{"title":156,"path":157,"stem":158,"children":159,"page":34},"Cloud","\u002Fintegrate\u002Fadapters\u002Fcloud","4.integrate\u002Fadapters\u002Fcloud",[160,165,170,175,180],{"title":161,"path":162,"stem":163,"icon":164},"Axiom","\u002Fintegrate\u002Fadapters\u002Fcloud\u002Faxiom","4.integrate\u002Fadapters\u002Fcloud\u002F01.axiom","i-custom-axiom",{"title":166,"path":167,"stem":168,"icon":169},"PostHog","\u002Fintegrate\u002Fadapters\u002Fcloud\u002Fposthog","4.integrate\u002Fadapters\u002Fcloud\u002F02.posthog","i-simple-icons-posthog",{"title":171,"path":172,"stem":173,"icon":174},"Sentry","\u002Fintegrate\u002Fadapters\u002Fcloud\u002Fsentry","4.integrate\u002Fadapters\u002Fcloud\u002F03.sentry","i-simple-icons-sentry",{"title":176,"path":177,"stem":178,"icon":179},"Better Stack","\u002Fintegrate\u002Fadapters\u002Fcloud\u002Fbetter-stack","4.integrate\u002Fadapters\u002Fcloud\u002F04.better-stack","i-simple-icons-betterstack",{"title":181,"path":182,"stem":183,"icon":184},"Datadog","\u002Fintegrate\u002Fadapters\u002Fcloud\u002Fdatadog","4.integrate\u002Fadapters\u002Fcloud\u002F05.datadog","i-simple-icons-datadog",{"title":186,"path":187,"stem":188,"children":189,"page":34},"Cloud or Self-Hosted","\u002Fintegrate\u002Fadapters\u002Fhybrid","4.integrate\u002Fadapters\u002Fhybrid",[190,195,200,205],{"title":191,"path":192,"stem":193,"icon":194},"Grafana Loki","\u002Fintegrate\u002Fadapters\u002Fhybrid\u002Floki","4.integrate\u002Fadapters\u002Fhybrid\u002F01.loki","i-simple-icons-grafana",{"title":196,"path":197,"stem":198,"icon":199},"ClickHouse","\u002Fintegrate\u002Fadapters\u002Fhybrid\u002Fclickhouse","4.integrate\u002Fadapters\u002Fhybrid\u002F02.clickhouse","i-simple-icons-clickhouse",{"title":201,"path":202,"stem":203,"icon":204},"OTLP","\u002Fintegrate\u002Fadapters\u002Fhybrid\u002Fotlp","4.integrate\u002Fadapters\u002Fhybrid\u002F03.otlp","i-simple-icons-opentelemetry",{"title":206,"path":207,"stem":208,"icon":209},"HyperDX","\u002Fintegrate\u002Fadapters\u002Fhybrid\u002Fhyperdx","4.integrate\u002Fadapters\u002Fhybrid\u002F04.hyperdx","i-custom-hyperdx",{"title":211,"path":212,"stem":213,"children":214,"page":34},"Self-Hosted","\u002Fintegrate\u002Fadapters\u002Fself-hosted","4.integrate\u002Fadapters\u002Fself-hosted",[215,220,225],{"title":216,"path":217,"stem":218,"icon":219},"File System","\u002Fintegrate\u002Fadapters\u002Fself-hosted\u002Ffs","4.integrate\u002Fadapters\u002Fself-hosted\u002F01.fs","i-lucide-hard-drive",{"title":221,"path":222,"stem":223,"icon":224},"NuxtHub","\u002Fintegrate\u002Fadapters\u002Fself-hosted\u002Fnuxthub","4.integrate\u002Fadapters\u002Fself-hosted\u002F02.nuxthub","i-simple-icons-nuxt",{"title":226,"path":227,"stem":228,"icon":229},"Memory","\u002Fintegrate\u002Fadapters\u002Fself-hosted\u002Fmemory","4.integrate\u002Fadapters\u002Fself-hosted\u002F03.memory","i-lucide-cpu",{"title":231,"path":232,"stem":233,"children":234,"page":34},"Frameworks","\u002Fintegrate\u002Fframeworks","4.integrate\u002Fframeworks",[235,239,244,249,254,259,264,269,274,279,284,289,294,299,303,308,313],{"title":41,"path":236,"stem":237,"icon":238},"\u002Fintegrate\u002Fframeworks\u002Foverview","4.integrate\u002Fframeworks\u002F00.overview","i-lucide-layout-grid",{"title":240,"path":241,"stem":242,"icon":243},"Nuxt","\u002Fintegrate\u002Fframeworks\u002Fnuxt","4.integrate\u002Fframeworks\u002F01.nuxt","i-simple-icons-nuxtdotjs",{"title":245,"path":246,"stem":247,"icon":248},"Next.js","\u002Fintegrate\u002Fframeworks\u002Fnextjs","4.integrate\u002Fframeworks\u002F02.nextjs","i-simple-icons-nextdotjs",{"title":250,"path":251,"stem":252,"icon":253},"SvelteKit","\u002Fintegrate\u002Fframeworks\u002Fsveltekit","4.integrate\u002Fframeworks\u002F03.sveltekit","i-simple-icons-svelte",{"title":255,"path":256,"stem":257,"icon":258},"Nitro","\u002Fintegrate\u002Fframeworks\u002Fnitro","4.integrate\u002Fframeworks\u002F04.nitro","i-custom-nitro",{"title":260,"path":261,"stem":262,"icon":263},"TanStack Start","\u002Fintegrate\u002Fframeworks\u002Ftanstack-start","4.integrate\u002Fframeworks\u002F05.tanstack-start","i-custom-tanstack",{"title":265,"path":266,"stem":267,"icon":268},"NestJS","\u002Fintegrate\u002Fframeworks\u002Fnestjs","4.integrate\u002Fframeworks\u002F06.nestjs","i-simple-icons-nestjs",{"title":270,"path":271,"stem":272,"icon":273},"Express","\u002Fintegrate\u002Fframeworks\u002Fexpress","4.integrate\u002Fframeworks\u002F07.express","i-simple-icons-express",{"title":275,"path":276,"stem":277,"icon":278},"Hono","\u002Fintegrate\u002Fframeworks\u002Fhono","4.integrate\u002Fframeworks\u002F08.hono","i-simple-icons-hono",{"title":280,"path":281,"stem":282,"icon":283},"Fastify","\u002Fintegrate\u002Fframeworks\u002Ffastify","4.integrate\u002Fframeworks\u002F09.fastify","i-simple-icons-fastify",{"title":285,"path":286,"stem":287,"icon":288},"Elysia","\u002Fintegrate\u002Fframeworks\u002Felysia","4.integrate\u002Fframeworks\u002F10.elysia","i-custom-elysia",{"title":290,"path":291,"stem":292,"icon":293},"React Router","\u002Fintegrate\u002Fframeworks\u002Freact-router","4.integrate\u002Fframeworks\u002F11.react-router","i-custom-reactrouter",{"title":295,"path":296,"stem":297,"icon":298},"Cloudflare Workers","\u002Fintegrate\u002Fframeworks\u002Fcloudflare-workers","4.integrate\u002Fframeworks\u002F12.cloudflare-workers","i-simple-icons-cloudflare",{"title":300,"path":301,"stem":302,"icon":79},"Standalone","\u002Fintegrate\u002Fframeworks\u002Fstandalone","4.integrate\u002Fframeworks\u002F13.standalone",{"title":304,"path":305,"stem":306,"icon":307},"Astro","\u002Fintegrate\u002Fframeworks\u002Fastro","4.integrate\u002Fframeworks\u002F14.astro","i-simple-icons-astro",{"title":309,"path":310,"stem":311,"icon":312},"oRPC","\u002Fintegrate\u002Fframeworks\u002Forpc","4.integrate\u002Fframeworks\u002F15.orpc","i-lucide-network",{"title":314,"path":315,"stem":316,"icon":317},"AWS Lambda","\u002Fintegrate\u002Fframeworks\u002Faws-lambda","4.integrate\u002Fframeworks\u002F16.aws-lambda","i-custom-lambda",{"title":319,"path":320,"stem":321,"children":322,"page":34},"Use Cases","\u002Fuse-cases","5.use-cases",[323,326,331,359,386,418,439,444,449],{"title":41,"path":324,"stem":325,"icon":107},"\u002Fuse-cases\u002Foverview","5.use-cases\u002F0.overview",{"title":327,"path":328,"stem":329,"icon":330},"Client Logging","\u002Fuse-cases\u002Fclient-logging","5.use-cases\u002F1.client-logging","i-lucide-monitor",{"title":332,"icon":333,"path":334,"stem":335,"children":336,"page":34},"AI SDK","i-simple-icons-vercel","\u002Fuse-cases\u002Fai-sdk","5.use-cases\u002F2.ai-sdk",[337,340,345,350,355],{"title":41,"path":338,"stem":339,"icon":44},"\u002Fuse-cases\u002Fai-sdk\u002Foverview","5.use-cases\u002F2.ai-sdk\u002F01.overview",{"title":341,"path":342,"stem":343,"icon":344},"Usage","\u002Fuse-cases\u002Fai-sdk\u002Fusage","5.use-cases\u002F2.ai-sdk\u002F02.usage","i-lucide-code",{"title":346,"path":347,"stem":348,"icon":349},"Options","\u002Fuse-cases\u002Fai-sdk\u002Foptions","5.use-cases\u002F2.ai-sdk\u002F03.options","i-lucide-sliders",{"title":351,"path":352,"stem":353,"icon":354},"Metadata","\u002Fuse-cases\u002Fai-sdk\u002Fmetadata","5.use-cases\u002F2.ai-sdk\u002F04.metadata","i-lucide-database",{"title":356,"path":357,"stem":358,"icon":137},"Telemetry","\u002Fuse-cases\u002Fai-sdk\u002Ftelemetry","5.use-cases\u002F2.ai-sdk\u002F05.telemetry",{"title":360,"icon":361,"path":362,"stem":363,"children":364,"page":34},"Better Auth","i-simple-icons-betterauth","\u002Fuse-cases\u002Fbetter-auth","5.use-cases\u002F3.better-auth",[365,368,373,378,382],{"title":41,"path":366,"stem":367,"icon":44},"\u002Fuse-cases\u002Fbetter-auth\u002Foverview","5.use-cases\u002F3.better-auth\u002F01.overview",{"title":369,"path":370,"stem":371,"icon":372},"Identify User","\u002Fuse-cases\u002Fbetter-auth\u002Fidentify-user","5.use-cases\u002F3.better-auth\u002F02.identify-user","i-lucide-user-check",{"title":374,"path":375,"stem":376,"icon":377},"Middleware","\u002Fuse-cases\u002Fbetter-auth\u002Fmiddleware","5.use-cases\u002F3.better-auth\u002F03.middleware","i-lucide-shield",{"title":379,"path":380,"stem":381,"icon":330},"Client Sync","\u002Fuse-cases\u002Fbetter-auth\u002Fclient-sync","5.use-cases\u002F3.better-auth\u002F04.client-sync",{"title":383,"path":384,"stem":385,"icon":112},"Performance","\u002Fuse-cases\u002Fbetter-auth\u002Fperformance","5.use-cases\u002F3.better-auth\u002F05.performance",{"title":387,"icon":388,"path":389,"stem":390,"children":391,"page":34},"Audit Logs","i-lucide-shield-check","\u002Fuse-cases\u002Faudit","5.use-cases\u002F4.audit",[392,395,400,405,410,414],{"title":41,"path":393,"stem":394,"icon":44},"\u002Fuse-cases\u002Faudit\u002Foverview","5.use-cases\u002F4.audit\u002F01.overview",{"title":396,"path":397,"stem":398,"icon":399},"Schema","\u002Fuse-cases\u002Faudit\u002Fschema","5.use-cases\u002F4.audit\u002F02.schema","i-lucide-file-text",{"title":401,"path":402,"stem":403,"icon":404},"Recording","\u002Fuse-cases\u002Faudit\u002Frecording","5.use-cases\u002F4.audit\u002F03.recording","i-lucide-pen-line",{"title":406,"path":407,"stem":408,"icon":409},"Drains","\u002Fuse-cases\u002Faudit\u002Fpipeline","5.use-cases\u002F4.audit\u002F04.pipeline","i-lucide-link",{"title":411,"path":412,"stem":413,"icon":388},"Compliance","\u002Fuse-cases\u002Faudit\u002Fcompliance","5.use-cases\u002F4.audit\u002F05.compliance",{"title":415,"path":416,"stem":417,"icon":84},"Recipes","\u002Fuse-cases\u002Faudit\u002Frecipes","5.use-cases\u002F4.audit\u002F06.recipes",{"title":356,"icon":112,"path":419,"stem":420,"children":421,"page":34},"\u002Fuse-cases\u002Ftelemetry","5.use-cases\u002F4.telemetry",[422,425,430,435],{"title":41,"path":423,"stem":424,"icon":44},"\u002Fuse-cases\u002Ftelemetry\u002Foverview","5.use-cases\u002F4.telemetry\u002F01.overview",{"title":426,"path":427,"stem":428,"icon":429},"Setup","\u002Fuse-cases\u002Ftelemetry\u002Fsetup","5.use-cases\u002F4.telemetry\u002F02.setup","i-lucide-wrench",{"title":431,"path":432,"stem":433,"icon":434},"Ingest","\u002Fuse-cases\u002Ftelemetry\u002Fingest","5.use-cases\u002F4.telemetry\u002F03.ingest","i-lucide-server",{"title":436,"path":437,"stem":438,"icon":84},"Reference","\u002Fuse-cases\u002Ftelemetry\u002Freference","5.use-cases\u002F4.telemetry\u002F04.reference",{"title":440,"path":441,"stem":442,"icon":443},"Enrichers","\u002Fuse-cases\u002Fenrichers","5.use-cases\u002F5.enrichers","i-lucide-sparkles",{"title":445,"path":446,"stem":447,"icon":448},"eve","\u002Fuse-cases\u002Feve","5.use-cases\u002F5.eve","i-custom-eve",{"title":450,"path":451,"stem":452,"icon":434},"Node.js request logging","\u002Fuse-cases\u002Fstructured-logging-nodejs","5.use-cases\u002F6.structured-logging-nodejs",{"title":454,"path":455,"stem":456,"children":457,"page":34},"Libraries","\u002Flibraries","6.libraries",[458,462,467,470,474,479,484],{"title":41,"path":459,"stem":460,"icon":461},"\u002Flibraries\u002Foverview","6.libraries\u002F0.overview","i-lucide-package",{"title":463,"path":464,"stem":465,"icon":466},"Emitting Events","\u002Flibraries\u002Femitting","6.libraries\u002F1.emitting","i-lucide-radio",{"title":56,"path":468,"stem":469,"icon":59},"\u002Flibraries\u002Ferrors","6.libraries\u002F2.errors",{"title":471,"path":472,"stem":473,"icon":132},"Errors Agents Can Act On","\u002Flibraries\u002Fagents","6.libraries\u002F3.agents",{"title":475,"path":476,"stem":477,"icon":478},"Exporting the Catalog","\u002Flibraries\u002Fexporting","6.libraries\u002F4.exporting","i-lucide-file-output",{"title":480,"path":481,"stem":482,"icon":483},"Migrating","\u002Flibraries\u002Fmigrating","6.libraries\u002F5.migrating","i-lucide-route",{"title":485,"path":486,"stem":487,"icon":488},"Testing","\u002Flibraries\u002Ftesting","6.libraries\u002F6.testing","i-lucide-flask-conical",{"title":490,"path":491,"stem":492,"children":493,"page":34},"Extend","\u002Fextend","7.extend",[494,498,503,508,512,517,521,525,529,533,538,543],{"title":41,"path":495,"stem":496,"icon":497},"\u002Fextend\u002Foverview","7.extend\u002F0.overview","i-lucide-blocks",{"title":499,"path":500,"stem":501,"icon":502},"Stream","\u002Fextend\u002Fstream","7.extend\u002F1.stream","i-lucide-radio-tower",{"title":504,"path":505,"stem":506,"icon":507},"Custom framework","\u002Fextend\u002Fcustom-framework","7.extend\u002F10.custom-framework","i-lucide-puzzle",{"title":509,"path":510,"stem":511,"icon":502},"Diagnostics channel","\u002Fextend\u002Fdiagnostics-channel","7.extend\u002F11.diagnostics-channel",{"title":513,"path":514,"stem":515,"icon":516},"FS reader","\u002Fextend\u002Ffs-reader","7.extend\u002F2.fs-reader","i-lucide-folder-search",{"title":415,"path":518,"stem":519,"icon":520},"\u002Fextend\u002Fconsumer-recipes","7.extend\u002F3.consumer-recipes","i-lucide-chef-hat",{"title":522,"path":523,"stem":524,"icon":497},"Plugins","\u002Fextend\u002Fplugins","7.extend\u002F4.plugins",{"title":526,"path":527,"stem":528,"icon":443},"Custom enrichers","\u002Fextend\u002Fcustom-enrichers","7.extend\u002F5.custom-enrichers",{"title":530,"path":531,"stem":532,"icon":69},"Tail sampling","\u002Fextend\u002Ftail-sampling","7.extend\u002F6.tail-sampling",{"title":534,"path":535,"stem":536,"icon":537},"Identity headers","\u002Fextend\u002Fidentity-headers","7.extend\u002F7.identity-headers","i-lucide-fingerprint",{"title":539,"path":540,"stem":541,"icon":542},"Custom drains","\u002Fextend\u002Fcustom-drains","7.extend\u002F8.custom-drains","i-lucide-share-2",{"title":544,"path":545,"stem":546,"icon":547},"Drain pipeline","\u002Fextend\u002Fdrain-pipeline","7.extend\u002F9.drain-pipeline","i-lucide-workflow",{"title":436,"path":549,"stem":550,"children":551,"page":34},"\u002Freference","8.reference",[552,556,561,564,569,573,578,582],{"title":41,"path":553,"stem":554,"icon":555},"\u002Freference\u002Foverview","8.reference\u002F0.overview","i-lucide-book-marked",{"title":557,"path":558,"stem":559,"icon":560},"Configuration","\u002Freference\u002Fconfiguration","8.reference\u002F1.configuration","i-lucide-settings",{"title":383,"path":562,"stem":563,"icon":112},"\u002Freference\u002Fperformance","8.reference\u002F2.performance",{"title":565,"path":566,"stem":567,"icon":568},"Vite Plugin","\u002Freference\u002Fvite-plugin","8.reference\u002F3.vite-plugin","i-custom-vite",{"title":570,"path":571,"stem":572,"icon":388},"Best Practices","\u002Freference\u002Fbest-practices","8.reference\u002F4.best-practices",{"title":574,"path":575,"stem":576,"icon":577},"vs Other Loggers","\u002Freference\u002Fvs-other-loggers","8.reference\u002F5.vs-other-loggers","i-lucide-scale",{"title":579,"path":580,"stem":581,"icon":443},"Agent Skills","\u002Freference\u002Fagent-skills","8.reference\u002F6.agent-skills",{"title":583,"path":584,"stem":585,"icon":586},"Cost","\u002Freference\u002Fcost","8.reference\u002F7.cost","i-lucide-receipt",{"title":588,"path":589,"stem":590,"children":591,"page":34},"Compare","\u002Fcompare","9.compare",[592,596,600,604,608],{"title":593,"path":594,"stem":595,"icon":577},"evlog vs Pino","\u002Fcompare\u002Fpino","9.compare\u002F1.pino",{"title":597,"path":598,"stem":599,"icon":204},"evlog vs OpenTelemetry","\u002Fcompare\u002Fopentelemetry","9.compare\u002F2.opentelemetry",{"title":601,"path":602,"stem":603,"icon":577},"evlog vs LogTape","\u002Fcompare\u002Flogtape","9.compare\u002F3.logtape",{"title":605,"path":606,"stem":607,"icon":577},"evlog vs Winston: formats and request events","\u002Fcompare\u002Fwinston","9.compare\u002F4.winston",{"title":609,"path":610,"stem":611,"icon":577},"evlog vs Consola: reporters and request context","\u002Fcompare\u002Fconsola","9.compare\u002F5.consola",{"id":613,"title":614,"body":615,"description":2365,"extension":2366,"links":2367,"meta":2373,"navigation":2374,"path":432,"seo":2375,"stem":433,"__hash__":2376},"docs\u002F5.use-cases\u002F4.telemetry\u002F03.ingest.md","Telemetry Ingest",{"type":616,"value":617,"toc":2357},"minimark",[618,632,640,645,652,657,668,673,684,779,785,799,805,817,1046,1065,1069,1076,2012,2016,2022,2330,2334,2343,2353],[619,620,621,622,626,627,631],"p",{},"You ship a CLI. Users run it on their machines. You want to know ",[623,624,625],"em",{},"which commands run, how often they fail, and which versions are out there",", without building a separate analytics SDK or reading raw ",[628,629,630],"code",{},"argv",".",[619,633,634,635,639],{},"That means a ",[636,637,638],"strong",{},"server endpoint"," your CLI POSTs to. The local outbox is only there so short CI jobs and offline runs do not lose data before the POST succeeds.",[641,642,644],"h2",{"id":643},"the-security-question-read-this-first","The security question (read this first)",[646,647,648,651],"tip",{},[636,649,650],{},"CLI telemetry is not a vault."," You are collecting anonymous usage counters (command name, duration, outcome, a few numbers), not passwords, not file paths, not tokens. Design for that threat model and you do not need impossible client-side secrets.",[619,653,654],{},[636,655,656],{},"\"I put the ingest URL in my CLI. Isn't that a secret?\"",[619,658,659,660,663,664,667],{},"No. The URL lives in your npm package or binary. Anyone can read it with ",[628,661,662],{},"strings",", by installing the package, or by watching network traffic. The same applies to an API key or ",[628,665,666],{},"Authorization"," header baked into the CLI is extractable, not a real barrier.",[619,669,670],{},[636,671,672],{},"\"So can't anyone send fake events?\"",[619,674,675,676,679,680,683],{},"In theory, yes: someone could ",[628,677,678],{},"curl"," your endpoint with forged JSON. That is why you treat the endpoint as ",[636,681,682],{},"semi-public"," (like a browser analytics key) and defend on the server:",[685,686,687,700],"table",{},[688,689,690],"thead",{},[691,692,693,697],"tr",{},[694,695,696],"th",{},"What you might worry about",[694,698,699],{},"Practical answer",[701,702,703,715,726,737,752,764],"tbody",{},[691,704,705,709],{},[706,707,708],"td",{},"Random internet bots",[706,710,711,712],{},"Validate the payload shape; reject garbage with ",[628,713,714],{},"400",[691,716,717,723],{},[706,718,719,720,722],{},"Someone spamming fake ",[628,721,119],{}," runs",[706,724,725],{},"Rate-limit by IP; data is low-value counters, not money",[691,727,728,734],{},[706,729,730,731],{},"Forged ",[628,732,733],{},"tool.name",[706,735,736],{},"Allowlist only your published tool names server-side",[691,738,739,745],{},[706,740,741,742],{},"Unexpected fields in ",[628,743,744],{},"custom",[706,746,747,748,751],{},"Filter to the keys you declared — same list as ",[628,749,750],{},"collect"," on the CLI",[691,753,754,757],{},[706,755,756],{},"Double-counting on retry",[706,758,759,760,763],{},"Dedupe on ",[628,761,762],{},"idempotencyKey"," when storing",[691,765,766,769],{},[706,767,768],{},"Leaking user secrets",[706,770,771,772,774,775,778],{},"CLI never reads raw ",[628,773,630],{},"; you only allowlisted flags and ",[628,776,777],{},"telemetry.set()"," counters",[619,780,781,784],{},[636,782,783],{},"What \"good enough\" looks like:"," validate every POST, store idempotently, rate-limit at the edge (CDN, API gateway, or middleware), and keep the payload boring (no PII by design). That is the same playbook as client-side analytics: not banking-grade auth, but reliable product insight.",[786,787,789,792,793,798],"callout",{"color":788,"icon":388},"info",[628,790,791],{},"@evlog\u002Ftelemetry"," ships ",[636,794,795],{},[628,796,797],{},"parseIngestBody()"," for your server, with the same validation rules documented here, so you do not copy-paste a validator from the docs. Pair it with your framework route and your database or evlog drain.",[641,800,802,803],{"id":801},"step-1-validate-with-parseingestbody","Step 1: Validate with ",[628,804,797],{},[619,806,807,808,811,812,814,815,631],{},"Mirror the CLI config on the server: same ",[628,809,810],{},"name",", same custom keys you allow via ",[628,813,750],{}," \u002F ",[628,816,777],{},[818,819,825],"pre",{"className":820,"code":821,"filename":822,"language":823,"meta":824,"style":824},"language-ts shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","import { parseIngestBody } from '@evlog\u002Ftelemetry\u002Fingest'\n\nexport const ingestOptions = {\n  allowedTools: ['my-tool'],\n  allowedCustomKeys: {\n    'my-tool': ['checksFailed', 'checksWarn', 'itemsSynced'],\n  },\n} as const\n\nexport function parseTelemetryBody(raw: string) {\n  return parseIngestBody(raw, ingestOptions)\n}\n","lib\u002Ftelemetry-ingest.ts","ts","",[628,826,827,860,867,886,913,923,967,973,985,990,1020,1040],{"__ignoreMap":824},[828,829,832,836,840,844,847,850,853,857],"span",{"class":830,"line":831},"line",1,[828,833,835],{"class":834},"s7zQu","import",[828,837,839],{"class":838},"sMK4o"," {",[828,841,843],{"class":842},"sTEyZ"," parseIngestBody",[828,845,846],{"class":838}," }",[828,848,849],{"class":834}," from",[828,851,852],{"class":838}," '",[828,854,856],{"class":855},"sfazB","@evlog\u002Ftelemetry\u002Fingest",[828,858,859],{"class":838},"'\n",[828,861,863],{"class":830,"line":862},2,[828,864,866],{"emptyLinePlaceholder":865},true,"\n",[828,868,870,873,877,880,883],{"class":830,"line":869},3,[828,871,872],{"class":834},"export",[828,874,876],{"class":875},"spNyl"," const",[828,878,879],{"class":842}," ingestOptions ",[828,881,882],{"class":838},"=",[828,884,885],{"class":838}," {\n",[828,887,889,893,896,899,902,905,907,910],{"class":830,"line":888},4,[828,890,892],{"class":891},"swJcz","  allowedTools",[828,894,895],{"class":838},":",[828,897,898],{"class":842}," [",[828,900,901],{"class":838},"'",[828,903,904],{"class":855},"my-tool",[828,906,901],{"class":838},[828,908,909],{"class":842},"]",[828,911,912],{"class":838},",\n",[828,914,916,919,921],{"class":830,"line":915},5,[828,917,918],{"class":891},"  allowedCustomKeys",[828,920,895],{"class":838},[828,922,885],{"class":838},[828,924,926,929,931,933,935,937,939,942,944,947,949,952,954,956,958,961,963,965],{"class":830,"line":925},6,[828,927,928],{"class":838},"    '",[828,930,904],{"class":891},[828,932,901],{"class":838},[828,934,895],{"class":838},[828,936,898],{"class":842},[828,938,901],{"class":838},[828,940,941],{"class":855},"checksFailed",[828,943,901],{"class":838},[828,945,946],{"class":838},",",[828,948,852],{"class":838},[828,950,951],{"class":855},"checksWarn",[828,953,901],{"class":838},[828,955,946],{"class":838},[828,957,852],{"class":838},[828,959,960],{"class":855},"itemsSynced",[828,962,901],{"class":838},[828,964,909],{"class":842},[828,966,912],{"class":838},[828,968,970],{"class":830,"line":969},7,[828,971,972],{"class":838},"  },\n",[828,974,976,979,982],{"class":830,"line":975},8,[828,977,978],{"class":838},"}",[828,980,981],{"class":834}," as",[828,983,984],{"class":875}," const\n",[828,986,988],{"class":830,"line":987},9,[828,989,866],{"emptyLinePlaceholder":865},[828,991,993,995,998,1002,1005,1009,1011,1015,1018],{"class":830,"line":992},10,[828,994,872],{"class":834},[828,996,997],{"class":875}," function",[828,999,1001],{"class":1000},"s2Zo4"," parseTelemetryBody",[828,1003,1004],{"class":838},"(",[828,1006,1008],{"class":1007},"sHdIc","raw",[828,1010,895],{"class":838},[828,1012,1014],{"class":1013},"sBMFI"," string",[828,1016,1017],{"class":838},")",[828,1019,885],{"class":838},[828,1021,1023,1026,1028,1030,1032,1034,1037],{"class":830,"line":1022},11,[828,1024,1025],{"class":834},"  return",[828,1027,843],{"class":1000},[828,1029,1004],{"class":891},[828,1031,1008],{"class":842},[828,1033,946],{"class":838},[828,1035,1036],{"class":842}," ingestOptions",[828,1038,1039],{"class":891},")\n",[828,1041,1043],{"class":830,"line":1042},12,[828,1044,1045],{"class":838},"}\n",[619,1047,1048,1050,1051,1054,1055,1057,1058,1061,1062,1064],{},[628,1049,797],{}," checks batch size, JSON shape, ",[628,1052,1053],{},"event: 'run'",", tool allowlist, envelope types, ISO timestamp, and strips ",[628,1056,744],{}," keys you did not declare. Throws ",[628,1059,1060],{},"IngestValidationError"," on failure, so return ",[628,1063,714],{}," from your route.",[641,1066,1068],{"id":1067},"step-2-wire-your-route","Step 2: Wire your route",[619,1070,1071,1072,1075],{},"Same contract for any framework: read the raw body, validate, store, return ",[636,1073,1074],{},"204"," so the CLI clears its outbox:",[1077,1078,1079,1449,1706],"code-group",{},[818,1080,1083],{"className":820,"code":1081,"filename":1082,"language":823,"meta":824,"style":824},"import { defineEventHandler, readRawBody, setResponseStatus } from 'h3'\nimport { IngestValidationError } from '@evlog\u002Ftelemetry\u002Fingest'\nimport { parseTelemetryBody } from '~\u002Flib\u002Ftelemetry-ingest'\nimport { storeRunEvents } from '~\u002Flib\u002Ftelemetry-store'\n\nexport default defineEventHandler(async (event) => {\n  const raw = await readRawBody(event, 'utf8')\n  if (!raw) {\n    setResponseStatus(event, 400)\n    return { error: 'empty body' }\n  }\n\n  try {\n    const events = parseTelemetryBody(raw)\n    await storeRunEvents(events)\n    setResponseStatus(event, 204)\n    return null\n  } catch (err) {\n    setResponseStatus(event, err instanceof IngestValidationError ? 400 : 500)\n    return { error: 'invalid payload' }\n  }\n})\n","server\u002Fapi\u002Ftelemetry\u002Fingest.post.ts (Nitro)",[628,1084,1085,1115,1134,1153,1173,1177,1204,1235,1253,1270,1292,1297,1301,1309,1328,1343,1359,1367,1385,1417,1437,1442],{"__ignoreMap":824},[828,1086,1087,1089,1091,1094,1096,1099,1101,1104,1106,1108,1110,1113],{"class":830,"line":831},[828,1088,835],{"class":834},[828,1090,839],{"class":838},[828,1092,1093],{"class":842}," defineEventHandler",[828,1095,946],{"class":838},[828,1097,1098],{"class":842}," readRawBody",[828,1100,946],{"class":838},[828,1102,1103],{"class":842}," setResponseStatus",[828,1105,846],{"class":838},[828,1107,849],{"class":834},[828,1109,852],{"class":838},[828,1111,1112],{"class":855},"h3",[828,1114,859],{"class":838},[828,1116,1117,1119,1121,1124,1126,1128,1130,1132],{"class":830,"line":862},[828,1118,835],{"class":834},[828,1120,839],{"class":838},[828,1122,1123],{"class":842}," IngestValidationError",[828,1125,846],{"class":838},[828,1127,849],{"class":834},[828,1129,852],{"class":838},[828,1131,856],{"class":855},[828,1133,859],{"class":838},[828,1135,1136,1138,1140,1142,1144,1146,1148,1151],{"class":830,"line":869},[828,1137,835],{"class":834},[828,1139,839],{"class":838},[828,1141,1001],{"class":842},[828,1143,846],{"class":838},[828,1145,849],{"class":834},[828,1147,852],{"class":838},[828,1149,1150],{"class":855},"~\u002Flib\u002Ftelemetry-ingest",[828,1152,859],{"class":838},[828,1154,1155,1157,1159,1162,1164,1166,1168,1171],{"class":830,"line":888},[828,1156,835],{"class":834},[828,1158,839],{"class":838},[828,1160,1161],{"class":842}," storeRunEvents",[828,1163,846],{"class":838},[828,1165,849],{"class":834},[828,1167,852],{"class":838},[828,1169,1170],{"class":855},"~\u002Flib\u002Ftelemetry-store",[828,1172,859],{"class":838},[828,1174,1175],{"class":830,"line":915},[828,1176,866],{"emptyLinePlaceholder":865},[828,1178,1179,1181,1184,1186,1188,1191,1194,1197,1199,1202],{"class":830,"line":925},[828,1180,872],{"class":834},[828,1182,1183],{"class":834}," default",[828,1185,1093],{"class":1000},[828,1187,1004],{"class":842},[828,1189,1190],{"class":875},"async",[828,1192,1193],{"class":838}," (",[828,1195,1196],{"class":1007},"event",[828,1198,1017],{"class":838},[828,1200,1201],{"class":875}," =>",[828,1203,885],{"class":838},[828,1205,1206,1209,1212,1215,1218,1220,1222,1224,1226,1228,1231,1233],{"class":830,"line":969},[828,1207,1208],{"class":875},"  const",[828,1210,1211],{"class":842}," raw",[828,1213,1214],{"class":838}," =",[828,1216,1217],{"class":834}," await",[828,1219,1098],{"class":1000},[828,1221,1004],{"class":891},[828,1223,1196],{"class":842},[828,1225,946],{"class":838},[828,1227,852],{"class":838},[828,1229,1230],{"class":855},"utf8",[828,1232,901],{"class":838},[828,1234,1039],{"class":891},[828,1236,1237,1240,1242,1245,1247,1250],{"class":830,"line":975},[828,1238,1239],{"class":834},"  if",[828,1241,1193],{"class":891},[828,1243,1244],{"class":838},"!",[828,1246,1008],{"class":842},[828,1248,1249],{"class":891},") ",[828,1251,1252],{"class":838},"{\n",[828,1254,1255,1258,1260,1262,1264,1268],{"class":830,"line":987},[828,1256,1257],{"class":1000},"    setResponseStatus",[828,1259,1004],{"class":891},[828,1261,1196],{"class":842},[828,1263,946],{"class":838},[828,1265,1267],{"class":1266},"sbssI"," 400",[828,1269,1039],{"class":891},[828,1271,1272,1275,1277,1280,1282,1284,1287,1289],{"class":830,"line":992},[828,1273,1274],{"class":834},"    return",[828,1276,839],{"class":838},[828,1278,1279],{"class":891}," error",[828,1281,895],{"class":838},[828,1283,852],{"class":838},[828,1285,1286],{"class":855},"empty body",[828,1288,901],{"class":838},[828,1290,1291],{"class":838}," }\n",[828,1293,1294],{"class":830,"line":1022},[828,1295,1296],{"class":838},"  }\n",[828,1298,1299],{"class":830,"line":1042},[828,1300,866],{"emptyLinePlaceholder":865},[828,1302,1304,1307],{"class":830,"line":1303},13,[828,1305,1306],{"class":834},"  try",[828,1308,885],{"class":838},[828,1310,1312,1315,1318,1320,1322,1324,1326],{"class":830,"line":1311},14,[828,1313,1314],{"class":875},"    const",[828,1316,1317],{"class":842}," events",[828,1319,1214],{"class":838},[828,1321,1001],{"class":1000},[828,1323,1004],{"class":891},[828,1325,1008],{"class":842},[828,1327,1039],{"class":891},[828,1329,1331,1334,1336,1338,1341],{"class":830,"line":1330},15,[828,1332,1333],{"class":834},"    await",[828,1335,1161],{"class":1000},[828,1337,1004],{"class":891},[828,1339,1340],{"class":842},"events",[828,1342,1039],{"class":891},[828,1344,1346,1348,1350,1352,1354,1357],{"class":830,"line":1345},16,[828,1347,1257],{"class":1000},[828,1349,1004],{"class":891},[828,1351,1196],{"class":842},[828,1353,946],{"class":838},[828,1355,1356],{"class":1266}," 204",[828,1358,1039],{"class":891},[828,1360,1362,1364],{"class":830,"line":1361},17,[828,1363,1274],{"class":834},[828,1365,1366],{"class":838}," null\n",[828,1368,1370,1373,1376,1378,1381,1383],{"class":830,"line":1369},18,[828,1371,1372],{"class":838},"  }",[828,1374,1375],{"class":834}," catch",[828,1377,1193],{"class":891},[828,1379,1380],{"class":842},"err",[828,1382,1249],{"class":891},[828,1384,1252],{"class":838},[828,1386,1388,1390,1392,1394,1396,1399,1402,1404,1407,1409,1412,1415],{"class":830,"line":1387},19,[828,1389,1257],{"class":1000},[828,1391,1004],{"class":891},[828,1393,1196],{"class":842},[828,1395,946],{"class":838},[828,1397,1398],{"class":842}," err",[828,1400,1401],{"class":838}," instanceof",[828,1403,1123],{"class":1013},[828,1405,1406],{"class":838}," ?",[828,1408,1267],{"class":1266},[828,1410,1411],{"class":838}," :",[828,1413,1414],{"class":1266}," 500",[828,1416,1039],{"class":891},[828,1418,1420,1422,1424,1426,1428,1430,1433,1435],{"class":830,"line":1419},20,[828,1421,1274],{"class":834},[828,1423,839],{"class":838},[828,1425,1279],{"class":891},[828,1427,895],{"class":838},[828,1429,852],{"class":838},[828,1431,1432],{"class":855},"invalid payload",[828,1434,901],{"class":838},[828,1436,1291],{"class":838},[828,1438,1440],{"class":830,"line":1439},21,[828,1441,1296],{"class":838},[828,1443,1445,1447],{"class":830,"line":1444},22,[828,1446,978],{"class":838},[828,1448,1039],{"class":842},[818,1450,1453],{"className":820,"code":1451,"filename":1452,"language":823,"meta":824,"style":824},"import { IngestValidationError } from '@evlog\u002Ftelemetry\u002Fingest'\nimport { parseTelemetryBody } from '@\u002Flib\u002Ftelemetry-ingest'\nimport { storeRunEvents } from '@\u002Flib\u002Ftelemetry-store'\n\nexport async function POST(request: Request) {\n  const raw = await request.text()\n  try {\n    const events = parseTelemetryBody(raw)\n    await storeRunEvents(events)\n    return new Response(null, { status: 204 })\n  } catch (err) {\n    const status = err instanceof IngestValidationError ? 400 : 500\n    return Response.json({ error: 'invalid payload' }, { status })\n  }\n}\n","app\u002Fapi\u002Ftelemetry\u002Fingest\u002Froute.ts (Next.js App Router)",[628,1454,1455,1473,1492,1511,1515,1541,1562,1568,1584,1596,1624,1638,1661,1698,1702],{"__ignoreMap":824},[828,1456,1457,1459,1461,1463,1465,1467,1469,1471],{"class":830,"line":831},[828,1458,835],{"class":834},[828,1460,839],{"class":838},[828,1462,1123],{"class":842},[828,1464,846],{"class":838},[828,1466,849],{"class":834},[828,1468,852],{"class":838},[828,1470,856],{"class":855},[828,1472,859],{"class":838},[828,1474,1475,1477,1479,1481,1483,1485,1487,1490],{"class":830,"line":862},[828,1476,835],{"class":834},[828,1478,839],{"class":838},[828,1480,1001],{"class":842},[828,1482,846],{"class":838},[828,1484,849],{"class":834},[828,1486,852],{"class":838},[828,1488,1489],{"class":855},"@\u002Flib\u002Ftelemetry-ingest",[828,1491,859],{"class":838},[828,1493,1494,1496,1498,1500,1502,1504,1506,1509],{"class":830,"line":869},[828,1495,835],{"class":834},[828,1497,839],{"class":838},[828,1499,1161],{"class":842},[828,1501,846],{"class":838},[828,1503,849],{"class":834},[828,1505,852],{"class":838},[828,1507,1508],{"class":855},"@\u002Flib\u002Ftelemetry-store",[828,1510,859],{"class":838},[828,1512,1513],{"class":830,"line":888},[828,1514,866],{"emptyLinePlaceholder":865},[828,1516,1517,1519,1522,1524,1527,1529,1532,1534,1537,1539],{"class":830,"line":915},[828,1518,872],{"class":834},[828,1520,1521],{"class":875}," async",[828,1523,997],{"class":875},[828,1525,1526],{"class":1000}," POST",[828,1528,1004],{"class":838},[828,1530,1531],{"class":1007},"request",[828,1533,895],{"class":838},[828,1535,1536],{"class":1013}," Request",[828,1538,1017],{"class":838},[828,1540,885],{"class":838},[828,1542,1543,1545,1547,1549,1551,1554,1556,1559],{"class":830,"line":925},[828,1544,1208],{"class":875},[828,1546,1211],{"class":842},[828,1548,1214],{"class":838},[828,1550,1217],{"class":834},[828,1552,1553],{"class":842}," request",[828,1555,631],{"class":838},[828,1557,1558],{"class":1000},"text",[828,1560,1561],{"class":891},"()\n",[828,1563,1564,1566],{"class":830,"line":969},[828,1565,1306],{"class":834},[828,1567,885],{"class":838},[828,1569,1570,1572,1574,1576,1578,1580,1582],{"class":830,"line":975},[828,1571,1314],{"class":875},[828,1573,1317],{"class":842},[828,1575,1214],{"class":838},[828,1577,1001],{"class":1000},[828,1579,1004],{"class":891},[828,1581,1008],{"class":842},[828,1583,1039],{"class":891},[828,1585,1586,1588,1590,1592,1594],{"class":830,"line":987},[828,1587,1333],{"class":834},[828,1589,1161],{"class":1000},[828,1591,1004],{"class":891},[828,1593,1340],{"class":842},[828,1595,1039],{"class":891},[828,1597,1598,1600,1603,1606,1608,1611,1613,1616,1618,1620,1622],{"class":830,"line":992},[828,1599,1274],{"class":834},[828,1601,1602],{"class":838}," new",[828,1604,1605],{"class":1000}," Response",[828,1607,1004],{"class":891},[828,1609,1610],{"class":838},"null,",[828,1612,839],{"class":838},[828,1614,1615],{"class":891}," status",[828,1617,895],{"class":838},[828,1619,1356],{"class":1266},[828,1621,846],{"class":838},[828,1623,1039],{"class":891},[828,1625,1626,1628,1630,1632,1634,1636],{"class":830,"line":1022},[828,1627,1372],{"class":838},[828,1629,1375],{"class":834},[828,1631,1193],{"class":891},[828,1633,1380],{"class":842},[828,1635,1249],{"class":891},[828,1637,1252],{"class":838},[828,1639,1640,1642,1644,1646,1648,1650,1652,1654,1656,1658],{"class":830,"line":1042},[828,1641,1314],{"class":875},[828,1643,1615],{"class":842},[828,1645,1214],{"class":838},[828,1647,1398],{"class":842},[828,1649,1401],{"class":838},[828,1651,1123],{"class":1013},[828,1653,1406],{"class":838},[828,1655,1267],{"class":1266},[828,1657,1411],{"class":838},[828,1659,1660],{"class":1266}," 500\n",[828,1662,1663,1665,1667,1669,1672,1674,1677,1679,1681,1683,1685,1687,1690,1692,1694,1696],{"class":830,"line":1303},[828,1664,1274],{"class":834},[828,1666,1605],{"class":842},[828,1668,631],{"class":838},[828,1670,1671],{"class":1000},"json",[828,1673,1004],{"class":891},[828,1675,1676],{"class":838},"{",[828,1678,1279],{"class":891},[828,1680,895],{"class":838},[828,1682,852],{"class":838},[828,1684,1432],{"class":855},[828,1686,901],{"class":838},[828,1688,1689],{"class":838}," },",[828,1691,839],{"class":838},[828,1693,1615],{"class":842},[828,1695,846],{"class":838},[828,1697,1039],{"class":891},[828,1699,1700],{"class":830,"line":1311},[828,1701,1296],{"class":838},[828,1703,1704],{"class":830,"line":1330},[828,1705,1045],{"class":838},[818,1707,1710],{"className":820,"code":1708,"filename":1709,"language":823,"meta":824,"style":824},"import { Hono } from 'hono'\nimport { IngestValidationError } from '@evlog\u002Ftelemetry\u002Fingest'\nimport { parseTelemetryBody } from '..\u002Flib\u002Ftelemetry-ingest'\nimport { storeRunEvents } from '..\u002Flib\u002Ftelemetry-store'\n\nconst app = new Hono()\n\napp.post('\u002Fapi\u002Ftelemetry\u002Fingest', async (c) => {\n  const raw = await c.req.text()\n  try {\n    const events = parseTelemetryBody(raw)\n    await storeRunEvents(events)\n    return c.body(null, 204)\n  } catch (err) {\n    const status = err instanceof IngestValidationError ? 400 : 500\n    return c.json({ error: 'invalid payload' }, status)\n  }\n})\n\nexport default app\n","src\u002Froutes\u002Ftelemetry.ts (Hono)",[628,1711,1712,1732,1750,1769,1788,1792,1808,1812,1846,1870,1876,1892,1904,1923,1937,1959,1989,1993,1999,2003],{"__ignoreMap":824},[828,1713,1714,1716,1718,1721,1723,1725,1727,1730],{"class":830,"line":831},[828,1715,835],{"class":834},[828,1717,839],{"class":838},[828,1719,1720],{"class":842}," Hono",[828,1722,846],{"class":838},[828,1724,849],{"class":834},[828,1726,852],{"class":838},[828,1728,1729],{"class":855},"hono",[828,1731,859],{"class":838},[828,1733,1734,1736,1738,1740,1742,1744,1746,1748],{"class":830,"line":862},[828,1735,835],{"class":834},[828,1737,839],{"class":838},[828,1739,1123],{"class":842},[828,1741,846],{"class":838},[828,1743,849],{"class":834},[828,1745,852],{"class":838},[828,1747,856],{"class":855},[828,1749,859],{"class":838},[828,1751,1752,1754,1756,1758,1760,1762,1764,1767],{"class":830,"line":869},[828,1753,835],{"class":834},[828,1755,839],{"class":838},[828,1757,1001],{"class":842},[828,1759,846],{"class":838},[828,1761,849],{"class":834},[828,1763,852],{"class":838},[828,1765,1766],{"class":855},"..\u002Flib\u002Ftelemetry-ingest",[828,1768,859],{"class":838},[828,1770,1771,1773,1775,1777,1779,1781,1783,1786],{"class":830,"line":888},[828,1772,835],{"class":834},[828,1774,839],{"class":838},[828,1776,1161],{"class":842},[828,1778,846],{"class":838},[828,1780,849],{"class":834},[828,1782,852],{"class":838},[828,1784,1785],{"class":855},"..\u002Flib\u002Ftelemetry-store",[828,1787,859],{"class":838},[828,1789,1790],{"class":830,"line":915},[828,1791,866],{"emptyLinePlaceholder":865},[828,1793,1794,1797,1800,1802,1804,1806],{"class":830,"line":925},[828,1795,1796],{"class":875},"const",[828,1798,1799],{"class":842}," app ",[828,1801,882],{"class":838},[828,1803,1602],{"class":838},[828,1805,1720],{"class":1000},[828,1807,1561],{"class":842},[828,1809,1810],{"class":830,"line":969},[828,1811,866],{"emptyLinePlaceholder":865},[828,1813,1814,1817,1819,1822,1824,1826,1829,1831,1833,1835,1837,1840,1842,1844],{"class":830,"line":975},[828,1815,1816],{"class":842},"app",[828,1818,631],{"class":838},[828,1820,1821],{"class":1000},"post",[828,1823,1004],{"class":842},[828,1825,901],{"class":838},[828,1827,1828],{"class":855},"\u002Fapi\u002Ftelemetry\u002Fingest",[828,1830,901],{"class":838},[828,1832,946],{"class":838},[828,1834,1521],{"class":875},[828,1836,1193],{"class":838},[828,1838,1839],{"class":1007},"c",[828,1841,1017],{"class":838},[828,1843,1201],{"class":875},[828,1845,885],{"class":838},[828,1847,1848,1850,1852,1854,1856,1859,1861,1864,1866,1868],{"class":830,"line":987},[828,1849,1208],{"class":875},[828,1851,1211],{"class":842},[828,1853,1214],{"class":838},[828,1855,1217],{"class":834},[828,1857,1858],{"class":842}," c",[828,1860,631],{"class":838},[828,1862,1863],{"class":842},"req",[828,1865,631],{"class":838},[828,1867,1558],{"class":1000},[828,1869,1561],{"class":891},[828,1871,1872,1874],{"class":830,"line":992},[828,1873,1306],{"class":834},[828,1875,885],{"class":838},[828,1877,1878,1880,1882,1884,1886,1888,1890],{"class":830,"line":1022},[828,1879,1314],{"class":875},[828,1881,1317],{"class":842},[828,1883,1214],{"class":838},[828,1885,1001],{"class":1000},[828,1887,1004],{"class":891},[828,1889,1008],{"class":842},[828,1891,1039],{"class":891},[828,1893,1894,1896,1898,1900,1902],{"class":830,"line":1042},[828,1895,1333],{"class":834},[828,1897,1161],{"class":1000},[828,1899,1004],{"class":891},[828,1901,1340],{"class":842},[828,1903,1039],{"class":891},[828,1905,1906,1908,1910,1912,1915,1917,1919,1921],{"class":830,"line":1303},[828,1907,1274],{"class":834},[828,1909,1858],{"class":842},[828,1911,631],{"class":838},[828,1913,1914],{"class":1000},"body",[828,1916,1004],{"class":891},[828,1918,1610],{"class":838},[828,1920,1356],{"class":1266},[828,1922,1039],{"class":891},[828,1924,1925,1927,1929,1931,1933,1935],{"class":830,"line":1311},[828,1926,1372],{"class":838},[828,1928,1375],{"class":834},[828,1930,1193],{"class":891},[828,1932,1380],{"class":842},[828,1934,1249],{"class":891},[828,1936,1252],{"class":838},[828,1938,1939,1941,1943,1945,1947,1949,1951,1953,1955,1957],{"class":830,"line":1330},[828,1940,1314],{"class":875},[828,1942,1615],{"class":842},[828,1944,1214],{"class":838},[828,1946,1398],{"class":842},[828,1948,1401],{"class":838},[828,1950,1123],{"class":1013},[828,1952,1406],{"class":838},[828,1954,1267],{"class":1266},[828,1956,1411],{"class":838},[828,1958,1660],{"class":1266},[828,1960,1961,1963,1965,1967,1969,1971,1973,1975,1977,1979,1981,1983,1985,1987],{"class":830,"line":1345},[828,1962,1274],{"class":834},[828,1964,1858],{"class":842},[828,1966,631],{"class":838},[828,1968,1671],{"class":1000},[828,1970,1004],{"class":891},[828,1972,1676],{"class":838},[828,1974,1279],{"class":891},[828,1976,895],{"class":838},[828,1978,852],{"class":838},[828,1980,1432],{"class":855},[828,1982,901],{"class":838},[828,1984,1689],{"class":838},[828,1986,1615],{"class":842},[828,1988,1039],{"class":891},[828,1990,1991],{"class":830,"line":1361},[828,1992,1296],{"class":838},[828,1994,1995,1997],{"class":830,"line":1369},[828,1996,978],{"class":838},[828,1998,1039],{"class":842},[828,2000,2001],{"class":830,"line":1387},[828,2002,866],{"emptyLinePlaceholder":865},[828,2004,2005,2007,2009],{"class":830,"line":1419},[828,2006,872],{"class":834},[828,2008,1183],{"class":834},[828,2010,2011],{"class":842}," app\n",[641,2013,2015],{"id":2014},"step-3-store-idempotently","Step 3: Store idempotently",[619,2017,2018,2019,2021],{},"Retries and backlog drains can POST the same ",[628,2020,762],{}," twice. Upsert (or skip) so metrics stay correct:",[818,2023,2026],{"className":820,"code":2024,"filename":2025,"language":823,"meta":824,"style":824},"import type { RunEvent } from '@evlog\u002Ftelemetry'\n\nexport async function storeRunEvents(events: RunEvent[]): Promise\u003Cvoid> {\n  for (const run of events) {\n    await db.telemetryRun.upsert({\n      where: { idempotencyKey: run.idempotencyKey },\n      create: {\n        tool: run.tool.name,\n        version: run.tool.version,\n        command: run.command,\n        outcome: run.outcome,\n        durationMs: run.durationMs,\n        custom: run.custom,\n        recordedAt: run.timestamp,\n      },\n      update: {},\n    })\n  }\n\n  \u002F\u002F Or forward into evlog's drain pipeline for Axiom \u002F Datadog \u002F OTLP:\n  \u002F\u002F await ingestWideEvents(events.map(run => ({ source: 'telemetry', ...run })))\n}\n","lib\u002Ftelemetry-store.ts",[628,2027,2028,2050,2054,2092,2113,2134,2157,2166,2186,2206,2222,2238,2254,2269,2285,2290,2300,2307,2311,2315,2321,2326],{"__ignoreMap":824},[828,2029,2030,2032,2035,2037,2040,2042,2044,2046,2048],{"class":830,"line":831},[828,2031,835],{"class":834},[828,2033,2034],{"class":834}," type",[828,2036,839],{"class":838},[828,2038,2039],{"class":842}," RunEvent",[828,2041,846],{"class":838},[828,2043,849],{"class":834},[828,2045,852],{"class":838},[828,2047,791],{"class":855},[828,2049,859],{"class":838},[828,2051,2052],{"class":830,"line":862},[828,2053,866],{"emptyLinePlaceholder":865},[828,2055,2056,2058,2060,2062,2064,2066,2068,2070,2072,2075,2078,2081,2084,2087,2090],{"class":830,"line":869},[828,2057,872],{"class":834},[828,2059,1521],{"class":875},[828,2061,997],{"class":875},[828,2063,1161],{"class":1000},[828,2065,1004],{"class":838},[828,2067,1340],{"class":1007},[828,2069,895],{"class":838},[828,2071,2039],{"class":1013},[828,2073,2074],{"class":842},"[]",[828,2076,2077],{"class":838},"):",[828,2079,2080],{"class":1013}," Promise",[828,2082,2083],{"class":838},"\u003C",[828,2085,2086],{"class":1013},"void",[828,2088,2089],{"class":838},">",[828,2091,885],{"class":838},[828,2093,2094,2097,2099,2101,2104,2107,2109,2111],{"class":830,"line":888},[828,2095,2096],{"class":834},"  for",[828,2098,1193],{"class":891},[828,2100,1796],{"class":875},[828,2102,2103],{"class":842}," run",[828,2105,2106],{"class":838}," of",[828,2108,1317],{"class":842},[828,2110,1249],{"class":891},[828,2112,1252],{"class":838},[828,2114,2115,2117,2120,2122,2125,2127,2130,2132],{"class":830,"line":915},[828,2116,1333],{"class":834},[828,2118,2119],{"class":842}," db",[828,2121,631],{"class":838},[828,2123,2124],{"class":842},"telemetryRun",[828,2126,631],{"class":838},[828,2128,2129],{"class":1000},"upsert",[828,2131,1004],{"class":891},[828,2133,1252],{"class":838},[828,2135,2136,2139,2141,2143,2146,2148,2150,2152,2154],{"class":830,"line":925},[828,2137,2138],{"class":891},"      where",[828,2140,895],{"class":838},[828,2142,839],{"class":838},[828,2144,2145],{"class":891}," idempotencyKey",[828,2147,895],{"class":838},[828,2149,2103],{"class":842},[828,2151,631],{"class":838},[828,2153,762],{"class":842},[828,2155,2156],{"class":838}," },\n",[828,2158,2159,2162,2164],{"class":830,"line":969},[828,2160,2161],{"class":891},"      create",[828,2163,895],{"class":838},[828,2165,885],{"class":838},[828,2167,2168,2171,2173,2175,2177,2180,2182,2184],{"class":830,"line":975},[828,2169,2170],{"class":891},"        tool",[828,2172,895],{"class":838},[828,2174,2103],{"class":842},[828,2176,631],{"class":838},[828,2178,2179],{"class":842},"tool",[828,2181,631],{"class":838},[828,2183,810],{"class":842},[828,2185,912],{"class":838},[828,2187,2188,2191,2193,2195,2197,2199,2201,2204],{"class":830,"line":987},[828,2189,2190],{"class":891},"        version",[828,2192,895],{"class":838},[828,2194,2103],{"class":842},[828,2196,631],{"class":838},[828,2198,2179],{"class":842},[828,2200,631],{"class":838},[828,2202,2203],{"class":842},"version",[828,2205,912],{"class":838},[828,2207,2208,2211,2213,2215,2217,2220],{"class":830,"line":992},[828,2209,2210],{"class":891},"        command",[828,2212,895],{"class":838},[828,2214,2103],{"class":842},[828,2216,631],{"class":838},[828,2218,2219],{"class":842},"command",[828,2221,912],{"class":838},[828,2223,2224,2227,2229,2231,2233,2236],{"class":830,"line":1022},[828,2225,2226],{"class":891},"        outcome",[828,2228,895],{"class":838},[828,2230,2103],{"class":842},[828,2232,631],{"class":838},[828,2234,2235],{"class":842},"outcome",[828,2237,912],{"class":838},[828,2239,2240,2243,2245,2247,2249,2252],{"class":830,"line":1042},[828,2241,2242],{"class":891},"        durationMs",[828,2244,895],{"class":838},[828,2246,2103],{"class":842},[828,2248,631],{"class":838},[828,2250,2251],{"class":842},"durationMs",[828,2253,912],{"class":838},[828,2255,2256,2259,2261,2263,2265,2267],{"class":830,"line":1303},[828,2257,2258],{"class":891},"        custom",[828,2260,895],{"class":838},[828,2262,2103],{"class":842},[828,2264,631],{"class":838},[828,2266,744],{"class":842},[828,2268,912],{"class":838},[828,2270,2271,2274,2276,2278,2280,2283],{"class":830,"line":1311},[828,2272,2273],{"class":891},"        recordedAt",[828,2275,895],{"class":838},[828,2277,2103],{"class":842},[828,2279,631],{"class":838},[828,2281,2282],{"class":842},"timestamp",[828,2284,912],{"class":838},[828,2286,2287],{"class":830,"line":1330},[828,2288,2289],{"class":838},"      },\n",[828,2291,2292,2295,2297],{"class":830,"line":1345},[828,2293,2294],{"class":891},"      update",[828,2296,895],{"class":838},[828,2298,2299],{"class":838}," {},\n",[828,2301,2302,2305],{"class":830,"line":1361},[828,2303,2304],{"class":838},"    }",[828,2306,1039],{"class":891},[828,2308,2309],{"class":830,"line":1369},[828,2310,1296],{"class":838},[828,2312,2313],{"class":830,"line":1387},[828,2314,866],{"emptyLinePlaceholder":865},[828,2316,2317],{"class":830,"line":1419},[828,2318,2320],{"class":2319},"sHwdD","  \u002F\u002F Or forward into evlog's drain pipeline for Axiom \u002F Datadog \u002F OTLP:\n",[828,2322,2323],{"class":830,"line":1439},[828,2324,2325],{"class":2319},"  \u002F\u002F await ingestWideEvents(events.map(run => ({ source: 'telemetry', ...run })))\n",[828,2327,2328],{"class":830,"line":1444},[828,2329,1045],{"class":838},[641,2331,2333],{"id":2332},"step-4-rate-limit-at-the-edge","Step 4: Rate-limit at the edge",[619,2335,2336,2338,2339,2342],{},[628,2337,797],{}," is your last line of schema defense, not your only one. Add rate limits where traffic enters (CDN, API gateway, or middleware), especially per IP. Optional: also bucket by ",[628,2340,2341],{},"machineId"," hash inside the handler if you need tighter control.",[619,2344,2345,2346,2348,2349,2352],{},"Non-2xx responses keep events in the user's outbox; they will retry on the next CLI invocation. Return ",[636,2347,1074],{}," (or any ",[628,2350,2351],{},"2xx",") only when storage succeeded.",[2354,2355,2356],"style",{},"html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .sHdIc, html code.shiki .sHdIc{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#EEFFFF;--shiki-default-font-style:italic;--shiki-dark:#BABED8;--shiki-dark-font-style:italic}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}",{"title":824,"searchDepth":862,"depth":862,"links":2358},[2359,2360,2362,2363,2364],{"id":643,"depth":862,"text":644},{"id":801,"depth":862,"text":2361},"Step 1: Validate with parseIngestBody()",{"id":1067,"depth":862,"text":1068},{"id":2014,"depth":862,"text":2015},{"id":2332,"depth":862,"text":2333},"Build the ingestion endpoint for @evlog\u002Ftelemetry: the threat model, parseIngestBody validation, framework routes, storage, and rate limiting.","md",[2368,2371,2372],{"label":41,"icon":44,"to":423,"color":2369,"variant":2370},"neutral","subtle",{"label":426,"icon":429,"to":427,"color":2369,"variant":2370},{"label":436,"icon":84,"to":437,"color":2369,"variant":2370},{},{"title":431,"icon":434},{"title":614,"description":2365},"rFp9uwlFbw94P_AK3Grez6dlVtWQc2B56C4Go2gQXgc",[2378,2380],{"title":426,"path":427,"stem":428,"description":2379,"icon":429,"children":-1},"Wire @evlog\u002Ftelemetry into citty CLIs, standalone scripts, and GitHub Actions — delivery config, automatic flag capture, telemetry.set(), and debug mode.",{"title":436,"path":437,"stem":438,"description":2381,"icon":84,"children":-1},"RunEvent envelope, extending the schema with collect and custom fields, privacy rules, TELEMETRY.md disclosure, and consent \u002F outbox reliability.",1789294028301]