feat(observability): gate Sentry tracing spans behind SENTRY_TRACING

Spans are now created and exported to Sentry only when SENTRY_TRACING is enabled (default off), keeping 24/7 operation within the free-tier span quota. Error monitoring stays always-on. Includes OpenSpec change gate-sentry-spans (proposal, design, specs, tasks).

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Mauricio Barragan
2026-07-16 12:54:15 -06:00
parent f6e8381c20
commit a5c83ee026
11 changed files with 169 additions and 5 deletions
+6 -3
View File
@@ -2,17 +2,20 @@ import * as Sentry from "@sentry/node";
import { trace, type Span, type Tracer } from "@opentelemetry/api";
import { NodeTracerProvider } from "@opentelemetry/sdk-trace-node";
import { SentrySpanProcessor, SentryPropagator } from "@sentry/opentelemetry";
import { isTracingEnabled } from "./tracing.js";
let tracer: Tracer | null = null;
/**
* OpenTelemetry spans export to Sentry via @sentry/opentelemetry when SENTRY_DSN is set.
* Without a DSN, spans are no-ops (safe for local dev and tests).
* OpenTelemetry spans export to Sentry via @sentry/opentelemetry only when
* SENTRY_DSN is set AND SENTRY_TRACING is enabled. Otherwise spans are no-ops
* (default; safe for 24/7 operation, local dev, and tests). Error capture in
* `withSpan` is preserved regardless.
*/
export function initOpenTelemetry(): Tracer {
if (tracer) return tracer;
if (!process.env.SENTRY_DSN?.trim()) {
if (!process.env.SENTRY_DSN?.trim() || !isTracingEnabled()) {
tracer = trace.getTracer("arbpulse");
return tracer;
}
+7 -1
View File
@@ -1,4 +1,5 @@
import * as Sentry from "@sentry/node";
import { isTracingEnabled } from "./tracing.js";
const dsn = process.env.SENTRY_DSN?.trim();
@@ -8,8 +9,13 @@ export function initSentry(): void {
Sentry.init({
dsn,
environment: process.env.NODE_ENV ?? "development",
tracesSampleRate: process.env.NODE_ENV === "production" ? 0.1 : 1,
integrations: [Sentry.httpIntegration(), Sentry.expressIntegration()],
// Tracing/spans are gated by SENTRY_TRACING (default off) to stay within
// the Sentry free-tier span quota during 24/7 operation. Error monitoring
// is always on.
...(isTracingEnabled()
? { tracesSampleRate: process.env.NODE_ENV === "production" ? 0.1 : 1 }
: {}),
});
process.on("unhandledRejection", (reason) => {
+11
View File
@@ -0,0 +1,11 @@
/**
* Single source of truth for the tracing gate. OpenTelemetry spans are only
* created and exported to Sentry when `SENTRY_TRACING` is truthy (and a
* `SENTRY_DSN` is set). Defaults to disabled so 24/7 operation stays off the
* Sentry free-tier span quota. Error monitoring is unaffected by this flag.
*/
export function isTracingEnabled(): boolean {
const raw = process.env.SENTRY_TRACING;
if (raw === undefined) return false;
return raw === "1" || raw.toLowerCase() === "true";
}