| name | error-tracking |
| description | Add Sentry v8 error tracking and performance monitoring to your services. Use this skill when adding error handling, creating new controllers, instrumenting cron jobs, or tracking database performance. ALL ERRORS MUST BE CAPTURED TO SENTRY - no exceptions. |
Sentry Integration Skill
Purpose
This skill enforces comprehensive Sentry error tracking and performance monitoring across all services following Sentry v8 patterns.
When to Use This Skill
- Adding error handling to any code
- Creating new controllers or routes
- Instrumenting cron jobs
- Tracking database performance
- Adding performance spans
- Handling workflow errors
🚨 CRITICAL RULE
ALL ERRORS MUST BE CAPTURED TO SENTRY - No exceptions. Never use console.error alone.
Current Status
Example: API Service ✅ Complete
- Sentry v8 fully integrated
- All workflow errors tracked
- Background job processors instrumented
- Test endpoints available
Sentry Integration Patterns
1. Controller Error Handling
import { BaseController } from '../controllers/BaseController';
export class MyController extends BaseController {
async myMethod() {
try {
} catch (error) {
this.handleError(error, 'myMethod');
}
}
}
2. Route Error Handling (Without BaseController)
import * as Sentry from '@sentry/node';
router.get('/route', async (req, res) => {
try {
} catch (error) {
Sentry.captureException(error, {
tags: { route: '/route', method: 'GET' },
extra: { userId: req.user?.id }
});
res.status(500).json({ error: 'Internal server error' });
}
});
3. Workflow Error Handling
Example of a domain-specific Sentry helper from the original production project. If you build a helper like this for your domain, the call site looks like:
import { WorkflowSentryHelper } from '../workflow/utils/sentryHelper';
WorkflowSentryHelper.captureWorkflowError(error, {
workflowCode: 'INVOICE_APPROVAL',
instanceId: 123,
stepId: 456,
userId: 'user-123',
operation: 'stepCompletion',
metadata: { additionalInfo: 'value' }
});
Without a helper, plain Sentry works everywhere:
Sentry.captureException(error, {
tags: { operation: 'stepCompletion' },
extra: { workflowCode: 'INVOICE_APPROVAL', instanceId: 123, userId: 'user-123' }
});
4. Cron Jobs (MANDATORY Pattern)
#!/usr/bin/env node
import '../instrument';
import * as Sentry from '@sentry/node';
async function main() {
return await Sentry.startSpan({
name: 'cron.job-name',
op: 'cron',
attributes: {
'cron.job': 'job-name',
'cron.startTime': new Date().toISOString(),
}
}, async () => {
try {
} catch (error) {
Sentry.captureException(error, {
tags: {
'cron.job': 'job-name',
'error.type': 'execution_error'
}
});
console.error('[Job] Error:', error);
process.exit(1);
}
});
}
main()
.then(() => {
console.();
process.();
})
.( {
.(, error);
process.();
});
5. Database Performance Monitoring
Example from the original production project - a small helper that wraps DB calls in Sentry spans. Adapt to your codebase:
import { DatabasePerformanceMonitor } from '../utils/databasePerformance';
const result = await DatabasePerformanceMonitor.withPerformanceTracking(
'findMany',
'UserProfile',
async () => {
return await PrismaService.main.userProfile.findMany({
take: 5,
});
}
);
The universally-available equivalent is a direct Sentry span:
const result = await Sentry.startSpan({
name: 'db.userProfile.findMany',
op: 'db.query',
attributes: { 'db.model': 'UserProfile', 'db.operation': 'findMany' }
}, async () => {
return await prisma.userProfile.findMany({ take: 5 });
});
6. Async Operations with Spans
import * as Sentry from '@sentry/node';
const result = await Sentry.startSpan({
name: 'operation.name',
op: 'operation.type',
attributes: {
'custom.attribute': 'value'
}
}, async () => {
return await someAsyncOperation();
});
Error Levels
Use appropriate severity levels:
- fatal: System is unusable (database down, critical service failure)
- error: Operation failed, needs immediate attention
- warning: Recoverable issues, degraded performance
- info: Informational messages, successful operations
- debug: Detailed debugging information (dev only)
Required Context
import * as Sentry from '@sentry/node';
Sentry.withScope((scope) => {
scope.setUser({ id: userId });
scope.setTag('service', 'api');
scope.setTag('environment', process.env.NODE_ENV);
scope.setContext('operation', {
type: 'workflow.start',
workflowCode: 'INVOICE_APPROVAL',
entityId: 123
});
Sentry.captureException(error);
});
Service Integration Examples
API Service (Example)
Location: ./api/src/instrument.ts
import * as Sentry from '@sentry/node';
import { nodeProfilingIntegration } from '@sentry/profiling-node';
Sentry.init({
dsn: process.env.SENTRY_DSN,
environment: process.env.NODE_ENV || 'development',
integrations: [
nodeProfilingIntegration(),
],
tracesSampleRate: 0.1,
profilesSampleRate: 0.1,
});
Key Helpers:
- Custom Sentry helpers for domain-specific errors
DatabasePerformanceMonitor - DB query tracking
BaseController - Controller error handling
Notifications Service (Example)
Location: ./notifications/src/instrument.ts
import * as Sentry from '@sentry/node';
import { nodeProfilingIntegration } from '@sentry/profiling-node';
Sentry.init({
dsn: process.env.SENTRY_DSN,
environment: process.env.NODE_ENV || 'development',
integrations: [
nodeProfilingIntegration(),
],
tracesSampleRate: 0.1,
profilesSampleRate: 0.1,
});
Key Helpers:
- Service-specific Sentry helpers for domain errors
BaseController - Controller error handling
Configuration (config.ini)
[sentry]
dsn = your-sentry-dsn
environment = development
tracesSampleRate = 0.1
profilesSampleRate = 0.1
[databaseMonitoring]
enableDbTracing = true
slowQueryThreshold = 100
logDbQueries = false
dbErrorCapture = true
enableN1Detection = true
Testing Sentry Integration
Example Test Endpoints
curl http://localhost:3000/api/sentry/test-error
curl http://localhost:3000/api/sentry/test-performance
curl http://localhost:3000/api/sentry/test-database-performance
Create test endpoints in your services to verify Sentry integration works end-to-end.
Performance Monitoring
Requirements
- All API endpoints must have transaction tracking
- Database queries > 100ms are automatically flagged
- N+1 queries are detected and reported
- Cron jobs must track execution time
Transaction Tracking
import * as Sentry from '@sentry/node';
app.use(Sentry.Handlers.requestHandler());
app.use(Sentry.Handlers.tracingHandler());
const transaction = Sentry.startTransaction({
op: 'operation.type',
name: 'Operation Name',
});
try {
} finally {
transaction.finish();
}
Common Mistakes to Avoid
❌ NEVER use console.error without Sentry
❌ NEVER swallow errors silently
❌ NEVER expose sensitive data in error context
❌ NEVER use generic error messages without context
❌ NEVER skip error handling in async operations
❌ NEVER forget to import instrument.ts as first line in cron jobs
Implementation Checklist
When adding Sentry to new code:
Key Files (Typical Structure)
Per Service
src/instrument.ts - Sentry initialization (imported first)
src/utils/sentryHelper.ts - Domain-specific error helpers
src/utils/databasePerformance.ts - DB monitoring
src/controllers/BaseController.ts - Controller base with Sentry
Configuration
config.ini or .env - Sentry DSN and settings
sentry.ini - Shared Sentry config (optional)