From 7a42e89349c3438fa9549af9a2895d16472854f8 Mon Sep 17 00:00:00 2001 From: Rohil Surana Date: Wed, 10 Jun 2026 12:24:40 +0530 Subject: [PATCH 1/5] fix: drop metrics for unmatched routes to prevent cardinality explosion --- .../src/server/plugins/telemetry.test.ts | 9 +++++++++ .../chronicle/src/server/plugins/telemetry.ts | 16 +++++++++++----- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/packages/chronicle/src/server/plugins/telemetry.test.ts b/packages/chronicle/src/server/plugins/telemetry.test.ts index 003634d..c50e016 100644 --- a/packages/chronicle/src/server/plugins/telemetry.test.ts +++ b/packages/chronicle/src/server/plugins/telemetry.test.ts @@ -44,4 +44,13 @@ describe('toEndpoint', () => { expect(toEndpoint('/v1/docs/intro')).toBe('/docs/:slug') expect(toEndpoint('/v2/guides/setup')).toBe('/docs/:slug') }) + + test('scanner/unmatched routes return null', () => { + expect(toEndpoint('/.env')).toBeNull() + expect(toEndpoint('/.aws/credentials')).toBeNull() + expect(toEndpoint('/wp-config.bak')).toBeNull() + expect(toEndpoint('/$(pwd)/.git/config')).toBeNull() + expect(toEndpoint('/.circleci/context/secrets.yml')).toBeNull() + expect(toEndpoint('/application.properties')).toBeNull() + }) }) diff --git a/packages/chronicle/src/server/plugins/telemetry.ts b/packages/chronicle/src/server/plugins/telemetry.ts index e17e9fa..db43ef2 100644 --- a/packages/chronicle/src/server/plugins/telemetry.ts +++ b/packages/chronicle/src/server/plugins/telemetry.ts @@ -37,13 +37,16 @@ const ENDPOINT_MAP: [string, string | null][] = [ const STATIC_ROUTES = new Set(['/llms.txt', '/robots.txt', '/sitemap.xml', '/og']) -export function toEndpoint(pathname: string): string { +const DOC_PATH_PREFIX = /^\/(?:docs|developer|v\d+)\// + +export function toEndpoint(pathname: string): string | null { if (pathname === '/') return ROUTES.ROOT; for (const [prefix, template] of ENDPOINT_MAP) { if (pathname.startsWith(prefix)) return template ?? pathname; } if (STATIC_ROUTES.has(pathname)) return pathname; - return ROUTES.DOCS; + if (DOC_PATH_PREFIX.test(pathname)) return ROUTES.DOCS; + return null; } export default definePlugin((nitroApp) => { @@ -82,7 +85,8 @@ export default definePlugin((nitroApp) => { }) nitroApp.hooks.hook('chronicle:ssr-rendered', (route, status, durationMs) => { - ssrRenderDuration.record(durationMs, { route: toEndpoint(route), status }) + const endpoint = toEndpoint(route) + if (endpoint) ssrRenderDuration.record(durationMs, { route: endpoint, status }) }) nitroApp.hooks.hook('request', (event) => { @@ -103,8 +107,10 @@ export default definePlugin((nitroApp) => { event.req.socket?.remoteAddress ?? 'unknown' - requestCounter.add(1, { method, endpoint, status: res.status }) - requestDuration.record(duration, { method, endpoint, status: res.status }) + if (endpoint) { + requestCounter.add(1, { method, endpoint, status: res.status }) + requestDuration.record(duration, { method, endpoint, status: res.status }) + } logger.emit({ severityNumber: SeverityNumber.INFO, From 85c7df9945ea2bc3c392f6626b9deb98ab968d7f Mon Sep 17 00:00:00 2001 From: Rohil Surana Date: Wed, 10 Jun 2026 14:57:06 +0530 Subject: [PATCH 2/5] fix: match bare doc root paths like /docs and /developer in toEndpoint --- packages/chronicle/src/server/plugins/telemetry.test.ts | 6 ++++++ packages/chronicle/src/server/plugins/telemetry.ts | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/chronicle/src/server/plugins/telemetry.test.ts b/packages/chronicle/src/server/plugins/telemetry.test.ts index c50e016..5ab7310 100644 --- a/packages/chronicle/src/server/plugins/telemetry.test.ts +++ b/packages/chronicle/src/server/plugins/telemetry.test.ts @@ -45,6 +45,12 @@ describe('toEndpoint', () => { expect(toEndpoint('/v2/guides/setup')).toBe('/docs/:slug') }) + test('bare docs root paths map to /docs/:slug', () => { + expect(toEndpoint('/docs')).toBe('/docs/:slug') + expect(toEndpoint('/developer')).toBe('/docs/:slug') + expect(toEndpoint('/v1')).toBe('/docs/:slug') + }) + test('scanner/unmatched routes return null', () => { expect(toEndpoint('/.env')).toBeNull() expect(toEndpoint('/.aws/credentials')).toBeNull() diff --git a/packages/chronicle/src/server/plugins/telemetry.ts b/packages/chronicle/src/server/plugins/telemetry.ts index db43ef2..2505862 100644 --- a/packages/chronicle/src/server/plugins/telemetry.ts +++ b/packages/chronicle/src/server/plugins/telemetry.ts @@ -37,7 +37,7 @@ const ENDPOINT_MAP: [string, string | null][] = [ const STATIC_ROUTES = new Set(['/llms.txt', '/robots.txt', '/sitemap.xml', '/og']) -const DOC_PATH_PREFIX = /^\/(?:docs|developer|v\d+)\// +const DOC_PATH_PREFIX = /^\/(?:docs|developer|v\d+)(?:\/|$)/ export function toEndpoint(pathname: string): string | null { if (pathname === '/') return ROUTES.ROOT; From 4dedcf975f6f9c34745da269918c640b2e1afe96 Mon Sep 17 00:00:00 2001 From: Rohil Surana Date: Wed, 10 Jun 2026 15:00:55 +0530 Subject: [PATCH 3/5] refactor: drop 404 metrics instead of route-matching to prevent cardinality explosion --- .../src/server/plugins/telemetry.test.ts | 17 ++++------------- .../chronicle/src/server/plugins/telemetry.ts | 13 +++++-------- 2 files changed, 9 insertions(+), 21 deletions(-) diff --git a/packages/chronicle/src/server/plugins/telemetry.test.ts b/packages/chronicle/src/server/plugins/telemetry.test.ts index 5ab7310..0293d1b 100644 --- a/packages/chronicle/src/server/plugins/telemetry.test.ts +++ b/packages/chronicle/src/server/plugins/telemetry.test.ts @@ -45,18 +45,9 @@ describe('toEndpoint', () => { expect(toEndpoint('/v2/guides/setup')).toBe('/docs/:slug') }) - test('bare docs root paths map to /docs/:slug', () => { - expect(toEndpoint('/docs')).toBe('/docs/:slug') - expect(toEndpoint('/developer')).toBe('/docs/:slug') - expect(toEndpoint('/v1')).toBe('/docs/:slug') - }) - - test('scanner/unmatched routes return null', () => { - expect(toEndpoint('/.env')).toBeNull() - expect(toEndpoint('/.aws/credentials')).toBeNull() - expect(toEndpoint('/wp-config.bak')).toBeNull() - expect(toEndpoint('/$(pwd)/.git/config')).toBeNull() - expect(toEndpoint('/.circleci/context/secrets.yml')).toBeNull() - expect(toEndpoint('/application.properties')).toBeNull() + test('unmatched paths fall through to /docs/:slug', () => { + expect(toEndpoint('/.env')).toBe('/docs/:slug') + expect(toEndpoint('/wp-config.bak')).toBe('/docs/:slug') + expect(toEndpoint('/unknown/path')).toBe('/docs/:slug') }) }) diff --git a/packages/chronicle/src/server/plugins/telemetry.ts b/packages/chronicle/src/server/plugins/telemetry.ts index 2505862..f4317ff 100644 --- a/packages/chronicle/src/server/plugins/telemetry.ts +++ b/packages/chronicle/src/server/plugins/telemetry.ts @@ -37,16 +37,13 @@ const ENDPOINT_MAP: [string, string | null][] = [ const STATIC_ROUTES = new Set(['/llms.txt', '/robots.txt', '/sitemap.xml', '/og']) -const DOC_PATH_PREFIX = /^\/(?:docs|developer|v\d+)(?:\/|$)/ - -export function toEndpoint(pathname: string): string | null { +export function toEndpoint(pathname: string): string { if (pathname === '/') return ROUTES.ROOT; for (const [prefix, template] of ENDPOINT_MAP) { if (pathname.startsWith(prefix)) return template ?? pathname; } if (STATIC_ROUTES.has(pathname)) return pathname; - if (DOC_PATH_PREFIX.test(pathname)) return ROUTES.DOCS; - return null; + return ROUTES.DOCS; } export default definePlugin((nitroApp) => { @@ -85,8 +82,8 @@ export default definePlugin((nitroApp) => { }) nitroApp.hooks.hook('chronicle:ssr-rendered', (route, status, durationMs) => { - const endpoint = toEndpoint(route) - if (endpoint) ssrRenderDuration.record(durationMs, { route: endpoint, status }) + if (status === 404) return + ssrRenderDuration.record(durationMs, { route: toEndpoint(route), status }) }) nitroApp.hooks.hook('request', (event) => { @@ -107,7 +104,7 @@ export default definePlugin((nitroApp) => { event.req.socket?.remoteAddress ?? 'unknown' - if (endpoint) { + if (res.status !== 404) { requestCounter.add(1, { method, endpoint, status: res.status }) requestDuration.record(duration, { method, endpoint, status: res.status }) } From 7632f0e37daaccd33c7cc435dadb902f5a21da80 Mon Sep 17 00:00:00 2001 From: Rohil Surana Date: Wed, 10 Jun 2026 15:08:16 +0530 Subject: [PATCH 4/5] revert: drop test changes unrelated to 404 metrics skip --- packages/chronicle/src/server/plugins/telemetry.test.ts | 6 ------ 1 file changed, 6 deletions(-) diff --git a/packages/chronicle/src/server/plugins/telemetry.test.ts b/packages/chronicle/src/server/plugins/telemetry.test.ts index 0293d1b..003634d 100644 --- a/packages/chronicle/src/server/plugins/telemetry.test.ts +++ b/packages/chronicle/src/server/plugins/telemetry.test.ts @@ -44,10 +44,4 @@ describe('toEndpoint', () => { expect(toEndpoint('/v1/docs/intro')).toBe('/docs/:slug') expect(toEndpoint('/v2/guides/setup')).toBe('/docs/:slug') }) - - test('unmatched paths fall through to /docs/:slug', () => { - expect(toEndpoint('/.env')).toBe('/docs/:slug') - expect(toEndpoint('/wp-config.bak')).toBe('/docs/:slug') - expect(toEndpoint('/unknown/path')).toBe('/docs/:slug') - }) }) From 93a2981b0a6513e901d98ee5e032c0909acc8310 Mon Sep 17 00:00:00 2001 From: Rohil Surana Date: Wed, 10 Jun 2026 16:11:11 +0530 Subject: [PATCH 5/5] fix: use /api/not-found as endpoint label for 404 responses --- packages/chronicle/src/server/plugins/telemetry.ts | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/packages/chronicle/src/server/plugins/telemetry.ts b/packages/chronicle/src/server/plugins/telemetry.ts index f4317ff..00597c6 100644 --- a/packages/chronicle/src/server/plugins/telemetry.ts +++ b/packages/chronicle/src/server/plugins/telemetry.ts @@ -82,8 +82,8 @@ export default definePlugin((nitroApp) => { }) nitroApp.hooks.hook('chronicle:ssr-rendered', (route, status, durationMs) => { - if (status === 404) return - ssrRenderDuration.record(durationMs, { route: toEndpoint(route), status }) + const endpoint = status === 404 ? '/api/not-found' : toEndpoint(route) + ssrRenderDuration.record(durationMs, { route: endpoint, status }) }) nitroApp.hooks.hook('request', (event) => { @@ -96,7 +96,7 @@ export default definePlugin((nitroApp) => { const duration = performance.now() - start const method = event.req.method const route = new URL(event.req.url).pathname - const endpoint = toEndpoint(route) + const endpoint = res.status === 404 ? '/api/not-found' : toEndpoint(route) const clientIp = event.req.headers['x-forwarded-for']?.toString().split(',')[0].trim() ?? @@ -104,10 +104,8 @@ export default definePlugin((nitroApp) => { event.req.socket?.remoteAddress ?? 'unknown' - if (res.status !== 404) { - requestCounter.add(1, { method, endpoint, status: res.status }) - requestDuration.record(duration, { method, endpoint, status: res.status }) - } + requestCounter.add(1, { method, endpoint, status: res.status }) + requestDuration.record(duration, { method, endpoint, status: res.status }) logger.emit({ severityNumber: SeverityNumber.INFO,