Skip to main content Inicio Creadores jeremylongshore tons-of-skills-marketplace sentry-reference-architecture
sentry-reference-architecture Design production-grade Sentry architecture for multi-service organizations.
Use when planning Sentry rollout, structuring projects across teams,
building shared config modules, or setting up distributed tracing.
Trigger: "sentry architecture", "sentry project structure",
"sentry reference design", "sentry distributed tracing".
Ir a la instalación Skills Marketplace Descubre y explora habilidades de IA creadas por la comunidad.
Instalar con Codex o Claude Copia este prompt, pégalo en Codex, Claude u otro asistente, y deja que revise la página de la skill y la instale por ti.
Copiar promptMostrar detalles del prompt Un comando directo omite el prompt de revisión. Revisa el origen antes de ejecutarlo.
npx skills add https://github.com/jeremylongshore/tons-of-skills-marketplace --skill sentry-reference-architectureEl comando permanece en una sola línea. Desplázate horizontalmente para revisarlo antes de copiarlo.
¿Prefieres una copia local? Descarga los archivos que SkillsMP tiene disponibles ahora.
Descargar Zip Descargando...
langchain-deploy-integration Deploy a LangChain 1.0 / LangGraph 1.0 app to Cloud Run, Vercel, or LangServe correctly — with timeouts sized for chain length, cold-start mitigation, SSE anti-buffering headers, and Secret Manager over .env. Use when prepping a first production deploy, debugging a stream that hangs behind a proxy, or diagnosing p99 latency spikes. Trigger with "langchain deploy", "langchain cloud run", "langchain vercel python", "langchain langserve", or "langchain docker".
Explorador de archivos
7 archivos name sentry-reference-architecture description Design production-grade Sentry architecture for multi-service organizations.
Use when planning Sentry rollout, structuring projects across teams,
building shared config modules, or setting up distributed tracing.
Trigger: "sentry architecture", "sentry project structure",
"sentry reference design", "sentry distributed tracing".
allowed-tools Read, Write, Edit, Bash(npm:*), Bash(npx:*), Glob, Grep version 1.51.0 license MIT author Jeremy Longshore <jeremy@intentsolutions.io> tags ["saas","sentry","architecture","enterprise","distributed-tracing","microservices"] compatibility Designed for Claude Code
Sentry Reference Architecture
Overview
Enterprise Sentry architecture patterns for multi-service organizations. Covers centralized configuration, project topology, team-based alert routing, distributed tracing, error middleware, source map management, and a production-ready SentryService wrapper.
Prerequisites
Sentry organization at sentry.io (Business plan+ for team features)
@sentry/node v8+ installed (npm install @sentry/node @sentry/profiling-node)
Service inventory and team ownership documented
Node.js 18+ (ESM and native fetch instrumentation)
Instructions
Step 1 — Project Structure Strategy
Pattern A: One Project Per Service (3+ services, recommended)
Organization: acme-corp
├── Team: platform-eng
│ ├── Project: api-gateway (Node/Express)
│ ├── Project: auth-service (Node/Fastify)
│ └── Project: user-service (Node/Express)
├── Team: payments
│ ├── Project: payment-api (Node/Express)
│ └── Project: billing-worker (Node worker)
└── Team: frontend
├── Project: web-app (React/Next.js)
└── Project: mobile-app (React Native)
Benefits: independent quotas, team-scoped alerts, per-service rate limits, isolated release tracking.
Pattern B: Shared Project (< 3 services, single team) — one project with Environment tags (production/staging/dev). Simpler setup; outgrow when alert noise exceeds one team.
Step 2 — Centralized Config Module
Create lib/sentry.ts imported by every service to enforce org-wide defaults:
import * as Sentry from '@sentry/node' ;
import { nodeProfilingIntegration } from '@sentry/profiling-node' ;
export interface SentryServiceConfig {
serviceName : string ;
dsn : string ;
environment ?: string ;
?: ;
?: ;
?: [];
}
( ): {
env = config. || process. . || ;
. ({
: config. ,
: env,
: ,
: config. ,
: config. ?? (env === ? : ),
: ,
: ,
: [ ()],
: [
,
,
,
],
: {
(parentSampled !== ) parentSampled;
ignored = config. || [
, , , ,
];
(ignored. ( name. (p))) ;
config. ?? (env === ? : );
},
( ) {
(event. ?. ) {
event. . [ ];
event. . [ ];
event. . [ ];
}
event;
},
: {
: { : config. , : process. . || },
},
});
}
{ };
version
string
tracesSampleRate
number
ignoredTransactions
string
export
function
initSentry
config : SentryServiceConfig
void
const
environment
env
NODE_ENV
'development'
Sentry
init
dsn
dsn
environment
release
`${config.serviceName} @${config.version || 'unknown' } `
serverName
serviceName
tracesSampleRate
tracesSampleRate
'production'
0.1
1.0
sendDefaultPii
false
maxBreadcrumbs
50
integrations
nodeProfilingIntegration
ignoreErrors
'ResizeObserver loop completed with undelivered notifications'
/Loading chunk \d+ failed/
'AbortError'
tracesSampler
({ name, parentSampled } ) =>
if
undefined
return
const
ignoredTransactions
'GET /health'
'GET /healthz'
'GET /ready'
'GET /metrics'
if
some
p =>
includes
return
0
return
tracesSampleRate
'production'
0.1
1.0
beforeSend
event
if
request
headers
delete
request
headers
'authorization'
delete
request
headers
'cookie'
delete
request
headers
'x-api-key'
return
initialScope
tags
service
serviceName
team
env
TEAM_NAME
'unassigned'
export
Sentry
Bootstrap in each service:
import { initSentry } from '@acme/sentry-config' ;
initSentry ({ serviceName : 'api-gateway' , dsn : process.env .SENTRY_DSN ! });
Step 3 — Error Handling Middleware
import * as Sentry from '@sentry/node' ;
import type { Request , Response , NextFunction , ErrorRequestHandler } from 'express' ;
export function sentryRequestHandler ( ) {
return (req : Request , _res : Response , next : NextFunction ): void => {
Sentry .setTag ('http.route' , req.route ?.path || req.path );
if (req.user ) Sentry .setUser ({ id : req.user .id });
next ();
};
}
export const sentryErrorHandler : ErrorRequestHandler = (err, req, res, _next ) => {
const status = (err as any ).statusCode || 500 ;
Sentry .withScope ((scope ) => {
scope.setLevel (status >= 500 ? 'error' : 'warning' );
scope.setTag ('http.status_code' , String (status));
scope.setContext ('request' , { method : req.method , url : req.originalUrl });
status >= 500 ? Sentry .captureException (err) : Sentry .captureMessage (err.message , 'warning' );
});
res.status (status).json ({ error : status >= 500 ? 'Internal server error' : err.message });
};
import sentry_sdk, os
from sentry_sdk.integrations.fastapi import FastApiIntegration
def init_sentry (service_name: str ) -> None :
sentry_sdk.init(
dsn=os.environ["SENTRY_DSN" ],
environment=os.getenv("ENV" , "development" ),
release=f"{service_name} @{os.getenv('SERVICE_VERSION' , 'unknown' )} " ,
traces_sample_rate=0.1 ,
send_default_pii=False ,
integrations=[FastApiIntegration(transaction_style="endpoint" )],
before_send=lambda event, hint: _scrub(event),
)
def _scrub (event ):
headers = event.get("request" , {}).get("headers" , {})
for k in ["authorization" , "cookie" , "x-api-key" ]:
headers.pop(k, None )
return event
Step 4 — Distributed Tracing HTTP (automatic): SDK v8 auto-propagates sentry-trace + baggage headers on fetch/http. All services in the same org link automatically.
Message queues (manual propagation):
import * as Sentry from '@sentry/node' ;
export function publishWithTrace<T>(queue : string , payload : T, publish : Function ) {
return Sentry .startSpan ({ name : `queue.publish.${queue} ` , op : 'queue.publish' }, async () => {
const headers : Record <string , string > = {};
const span = Sentry .getActiveSpan ();
if (span) {
headers['sentry-trace' ] = Sentry .spanToTraceHeader (span);
headers['baggage' ] = Sentry .spanToBaggageHeader (span) || '' ;
}
await publish (queue, { payload, headers });
});
}
export function consumeWithTrace<T>(queue : string , msg : { payload : T; headers : Record <string , string > }, handler : (p : T ) => Promise <void >) {
return Sentry .continueTrace (
{ sentryTrace : msg.headers ['sentry-trace' ], baggage : msg.headers ['baggage' ] },
() => Sentry .startSpan ({ name : `queue.process.${queue} ` , op : 'queue.process' }, () => handler (msg.payload ))
);
}
Step 5 — Team-Based Alert Routing Configure in Project Settings > Ownership Rules :
path:src/payments/**
path:src/auth/**
url:*/api/v1/payments/*
tags.service:payment-api
*
P0 Critical: error rate > 50/min OR crash-free < 95% — PagerDuty on-call, 15 min SLA
P1 Warning: new production issue or regression — Slack #alerts-prod, same-day SLA
P2 Performance: P95 > 2s or Apdex < 0.7 — Slack #alerts-perf, next sprint
P3 Info: new staging issue — Slack #alerts-staging, backlog triage
Step 6 — Source Map Uploads (Monorepo) #!/usr/bin/env bash
set -euo pipefail
SERVICE="${1:?Usage: upload-sourcemaps.sh <service>} "
RELEASE="${SERVICE} @$(git rev-parse --short HEAD) "
npx @sentry/cli releases new "$RELEASE " --org "$SENTRY_ORG " --project "$SERVICE "
npx @sentry/cli sourcemaps upload --org "$SENTRY_ORG " --project "$SERVICE " \
--release "$RELEASE " --url-prefix "~/" --validate "./services/${SERVICE} /dist/"
npx @sentry/cli releases set-commits "$RELEASE " --org "$SENTRY_ORG " --auto
npx @sentry/cli releases finalize "$RELEASE " --org "$SENTRY_ORG "
Webpack plugin alternative (auto-uploads on build):
import { sentryWebpackPlugin } from '@sentry/webpack-plugin' ;
export default {
devtool : 'source-map' ,
plugins : [sentryWebpackPlugin ({
org : process.env .SENTRY_ORG ,
project : 'web-app' ,
authToken : process.env .SENTRY_AUTH_TOKEN ,
sourcemaps : { filesToDeleteAfterUpload : ['./dist/**/*.map' ] },
})],
};
Step 7 — Custom Integrations Wrap internal SDK calls with spans for tracing visibility:
import * as Sentry from '@sentry/node' ;
export function withSpan<T>(op : string , desc : string , fn : () => Promise <T>, attrs ?: Record <string , string | number >): Promise <T> {
return Sentry .startSpan ({ name : desc, op, attributes : attrs }, async (span) => {
try { const r = await fn (); span.setStatus ({ code : 1 , message : 'ok' }); return r; }
catch (e) { span.setStatus ({ code : 2 , message : String (e) }); throw e; }
});
}
Step 8 — SentryService Wrapper Production wrapper with singleton, metrics, and graceful shutdown:
import * as Sentry from '@sentry/node' ;
export class SentryService {
private static instance : SentryService | null = null ;
private initialized = false ;
private constructor (private config : { serviceName: string ; dsn: string ; version?: string } ) {}
static getInstance (config ?: { serviceName : string ; dsn : string ; version ?: string }): SentryService {
if (!SentryService .instance ) {
if (!config) throw new Error ('Config required on first call' );
SentryService .instance = new SentryService (config);
}
return SentryService .instance ;
}
init (): void {
if (this .initialized ) return ;
const { initSentry } = require ('./sentry' );
initSentry (this .config );
this .initialized = true ;
}
captureError (error : Error , ctx ?: { tags ?: Record <string , string >; extra ?: Record <string , unknown >; level ?: Sentry .SeverityLevel }): string {
return Sentry .withScope ((scope ) => {
if (ctx?.tags ) Object .entries (ctx.tags ).forEach (([k, v] ) => scope.setTag (k, v));
if (ctx?.extra ) Object .entries (ctx.extra ).forEach (([k, v] ) => scope.setExtra (k, v));
if (ctx?.level ) scope.setLevel (ctx.level );
return Sentry .captureException (error);
});
}
async trackOperation<T>(name : string , op : string , fn : () => Promise <T>): Promise <T> {
return Sentry .startSpan ({ name, op }, async (span) => {
try { const r = await fn (); span.setStatus ({ code : 1 , message : 'ok' }); return r; }
catch (e) { span.setStatus ({ code : 2 , message : String (e) }); Sentry .captureException (e); throw e; }
});
}
async shutdown (timeoutMs = 5000 ): Promise <void > {
await Sentry .close (timeoutMs);
SentryService .instance = null ;
this .initialized = false ;
}
}
Step 9 — Health Check Exclusion Define health routes BEFORE Sentry middleware so they never create transactions:
app.get ('/health' , (_req, res ) => res.status (200 ).json ({ status : 'ok' }));
app.get ('/readiness' , async (_req, res) => {
const dbOk = await checkDatabase ();
res.status (dbOk ? 200 : 503 ).json ({ db : dbOk });
});
Output
Centralized lib/sentry.ts enforcing PII scrubbing, sample rates, and noise filters across all services
Project-per-service topology with team ownership, independent quotas, and per-service releases
Error middleware for Express and FastAPI with severity-based capture
Distributed tracing across HTTP (automatic) and message queues (manual propagation helpers)
Team-based alert routing with 4-tier escalation (P0-P3)
Source map pipeline with CLI and Webpack plugin for monorepo builds
SentryService singleton with custom metrics and graceful shutdown
Error Handling Error Cause Solution Traces not linking cross-service Missing trace headers in non-HTTP transport Use publishWithTrace/consumeWithTrace for queues init() called multiple timesMultiple imports Use SentryService singleton (idempotent init) Source maps not resolving Wrong url-prefix Use --url-prefix "~/" and --validate flag Alerts routing to wrong team Ownership rules mismatch Verify path: rules match source tree; add tags.service: fallback Health checks consuming quota Probes hitting instrumented routes Define health routes before middleware; use tracesSampler PII leaking Missing beforeSend scrubbing Enforce sendDefaultPii: false + header deletion in shared config
Examples Bootstrap a service (3 lines):
import { SentryService } from '@acme/sentry-config' ;
const sentry = SentryService .getInstance ({ serviceName : 'user-service' , dsn : process.env .SENTRY_DSN ! });
sentry.init ();
Capture with business context:
sentry.captureError (err, {
tags : { 'payment.provider' : 'stripe' },
extra : { orderId : order.id , amount : order.total },
level : 'error' ,
});
const result = await sentry.trackOperation ('order.fulfillment' , 'business.process' , () => fulfillOrder (id));
Resources
Next Steps
Roll out incrementally — start with one high-traffic service, validate traces and alerts, then onboard remaining services
Set up Sentry Crons for scheduled job monitoring (ETL, billing workers)
Enable Session Replay (@sentry/browser) for frontend error-to-session correlation
Define per-project quota budgets to prevent one noisy service from exhausting org quota
Build Discover dashboards for cross-service error trends (count() by service, level)