NIST AU-2 requires that audit-relevant events — including performance events — be captured at sufficient resolution to support analysis. Aggregate server-level response time hides where latency is actually coming from. If your P95 is 800ms but it originates entirely from one /api/reports/export endpoint, aggregate metrics tell you nothing actionable. Per-route latency data is what enables you to write a latency-based SLO ("checkout route P99 < 500ms"), catch regressions in a specific endpoint after a deploy, and prioritize which routes to optimize. This check goes beyond performance-monitoring (any timing data) to require route-level attribution — the difference between knowing "something is slow" and knowing "which endpoint is slow."
Medium because without per-route timing, latency regressions in specific endpoints are invisible in aggregate metrics, delaying optimization and SLO definition.
Enable Sentry transaction tracing with a non-zero sample rate — Sentry automatically records per-route transaction durations for Next.js.
// sentry.server.config.ts
Sentry.init({
dsn: process.env.SENTRY_DSN,
tracesSampleRate: 0.1 // 10% of requests — adjust for traffic volume
})
Alternatively, add a custom timing middleware that emits Server-Timing headers:
// middleware.ts
export function middleware(req: NextRequest) {
const start = performance.now()
const res = NextResponse.next()
res.headers.set(
'Server-Timing',
`handler;dur=${(performance.now() - start).toFixed(1)}`
)
return res
}
The Server-Timing header is consumed by Chrome DevTools in the Network panel and by log platforms that parse response headers, giving you per-route timing with zero external dependencies.
ID: saas-logging.observability.api-response-times-tracked
Severity: medium
What to look for: Enumerate all relevant files and Look for per-route API response time tracking. Check: Sentry Performance with tracesSampleRate > 0 (which automatically tracks transaction durations), Datadog APM with route-level spans, OpenTelemetry instrumentation with HTTP instrumentation library, custom middleware that measures and logs response duration per route with the route path (not just per-request in aggregate), or Vercel Analytics which tracks TTFB per route. The key distinction from performance-monitoring (which checks for any performance data) is whether individual routes/endpoints have their response times tracked separately, enabling you to identify which specific endpoint is slow.
Pass criteria: Per-route response time data is collected through an APM tool, platform analytics, or custom middleware that tags timing by route. "Route" means the endpoint path pattern, not just the server as a whole.
Fail criteria: No per-route timing tracked — either no performance monitoring at all, or only aggregate server-level metrics without route attribution.
Skip (N/A) when: Project has no API routes (static site). Also skip if performance-monitoring is skipped for the same reason.
Detail on fail: "No per-route response time tracking found — Sentry is configured but tracesSampleRate is 0, disabling transaction tracing" or "No APM or route-level timing middleware found"
Remediation: Aggregate response time hides the signal. If your P95 latency is 800ms but it's coming from one specific /api/reports/export endpoint, you need per-route data to find it.
Enable Sentry transaction tracing:
// sentry.server.config.ts
Sentry.init({
dsn: process.env.SENTRY_DSN,
tracesSampleRate: 0.1 // 10% sampling — adjust based on traffic volume
})
Or add a timing middleware for Next.js:
// middleware.ts
export function middleware(req: NextRequest) {
const start = performance.now()
const res = NextResponse.next()
res.headers.set('Server-Timing', `handler;dur=${performance.now() - start}`)
return res
}
The Server-Timing header is also consumed by browsers and available in Chrome DevTools network panel.