Sentry â Error Tracking & Performance Monitoring Guide
In this tutorial, you'll learn about Sentry. We cover key concepts, practical examples, and best practices to help you understand and apply this topic effectively.
Sentry is an open-source error tracking and performance monitoring platform that helps developers see, triage, and resolve errors and performance issues in real time across their entire software stack.
What You'll Learn
Why It Matters
Users experiencing errors rarely report them. They silently leave your application or write a negative review. Sentry captures every error automatically â frontend JavaScript exceptions, backend API crashes, mobile app crashes â with full stack traces, user context, and breadcrumbs leading up to the error. DodaTech reduced unhandled error resolution time by 85% after integrating Sentry across all applications.
Real-World Use
DodaZIP's desktop application uses Sentry's native SDK to capture crashes with full minidump analysis. When a user's file compression crashes, Sentry captures the crash thread, loaded modules, and OS information â enabling the team to fix the issue within hours of the first report.
flowchart TD
A[Application Error] --> B[Sentry SDK]
B --> C[Sentry Server]
C --> D[Issue Grouping]
C --> E[Release Tracking]
C --> F[Source Maps]
C --> G[Performance Traces]
D --> H[Alert Rules]
H --> I[Slack Notification]
H --> I2[PagerDuty]
H --> I3[Email]
D --> J[Issue Dashboard]
J --> K[Assign to Developer]
K --> L[Fix & Deploy]
L --> M[Resolve in Sentry]
style C fill:#362D59,color:#fff
Prerequisites: A Sentry account (sentry.io or self-hosted). Basic knowledge of JavaScript or your target language.
Installation
# Self-hosted Sentry (using getsentry/self-hosted)
git clone https://github.com/getsentry/self-hosted.git
cd self-hosted
sudo ./install.sh
# Expected output:
# Checking minimum requirements...
# Creating volumes...
# Building images...
# Creating services...
# Installation complete.
# Your Sentry server is ready! Visit http://your-ip:9000
# Create DSN for your project
# Settings > Projects > Your Project > DSN
# DSN format: https://publicKey@o123456.ingest.sentry.io/654321
JavaScript/Node.js Setup
// sentry.js â Sentry initialization
const Sentry = require('@sentry/node');
const { nodeProfilingIntegration } = require('@sentry/profiling-node');
Sentry.init({
dsn: 'https://publicKey@o123456.ingest.sentry.io/654321',
environment: 'production',
release: 'dodazip@2.5.0',
dist: '1',
// Performance monitoring
tracesSampleRate: 0.2,
profilesSampleRate: 0.1,
// Send errors from all transactions
errorSampleRate: 1.0,
integrations: [
nodeProfilingIntegration(),
],
// Capture unhandled rejections
captureUnhandledRejections: true,
// Denylist sensitive data
denyUrls: [
/https?:\/\/localhost/,
/https?:\/\/.*\.local/,
],
beforeSend(event) {
if (event.user) {
delete event.user.email;
delete event.user.ip_address;
}
return event;
},
// Sampling for performance
tracesSampler(samplingContext) {
if (samplingContext.request?.url?.includes('/health')) {
return 0;
}
if (samplingContext.parentSampled) {
return 1;
}
return 0.2;
},
});
Capturing Errors
// Automatic error capturing
// Express error handler
const express = require('express');
const app = express();
// RequestHandler creates a separate trace per request
app.use(Sentry.Handlers.requestHandler());
app.use(Sentry.Handlers.tracingHandler());
app.get('/api/users/:id', async (req, res) => {
try {
const user = await db.query('SELECT * FROM users WHERE id = $1', [req.params.id]);
if (!user) {
throw new Error('User not found');
}
res.json(user);
} catch (error) {
// Sentry automatically captures in error handler
Sentry.captureException(error, {
tags: {
endpoint: 'GET /api/users/:id',
user_id: req.params.id,
},
extra: {
query: req.query,
headers: req.headers,
},
user: {
id: req.user?.id,
username: req.user?.username,
},
});
res.status(500).json({ error: 'Internal server error' });
}
});
// The error handler middleware
app.use(Sentry.Handlers.errorHandler());
// Manual error capture
Sentry.captureMessage('Database migration completed', {
level: 'info',
tags: { migration: 'v2.5.0' },
});
// Set user context
Sentry.setUser({
id: 'user-123',
username: 'jdoe',
email: 'jdoe@dodatech.com',
});
// Add breadcrumbs for debugging
Sentry.addBreadcrumb({
category: 'auth',
message: 'User authenticated',
level: 'info',
data: {
auth_method: 'OAuth2',
provider: 'GitHub',
},
});
React Frontend Setup
// frontend/sentry.js
import * as Sentry from '@sentry/react';
import { BrowserTracing } from '@sentry/react';
import { createRoutesFromChildren, matchRoutes, useLocation, useNavigationType } from 'react-router-dom';
Sentry.init({
dsn: 'https://publicKey@o123456.ingest.sentry.io/654321',
environment: 'production',
release: 'dodazip-frontend@3.1.0',
integrations: [
new BrowserTracing({
routingInstrumentation: Sentry.reactRouterV6Instrumentation(
React.useEffect,
useLocation,
useNavigationType,
createRoutesFromChildren,
matchRoutes
),
}),
new Sentry.Replay({
maskAllText: false,
maskAllInputs: false,
blockAllMedia: false,
}),
],
tracesSampleRate: 0.1,
replaysSessionSampleRate: 0.1,
replaysOnErrorSampleRate: 1.0,
});
// Sentry Error Boundary
import { SentryErrorBoundary } from '@sentry/react';
function App() {
return (
<SentryErrorBoundary fallback={({ error, componentStack }) => (
<div>
<h2>Something went wrong</h2>
<p>{error.message}</p>
<button onClick={() => window.location.reload()}>
Reload page
</button>
</div>
)}>
<MainContent />
</SentryErrorBoundary>
);
}
Release Tracking
# .github/workflows/sentry-release.yml
name: Create Sentry Release
on:
push:
branches: [main]
jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Create Sentry release
uses: getsentry/action-release@v1
env:
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
SENTRY_ORG: dodatech
SENTRY_PROJECT: user-service
with:
environment: production
version: dodazip@${{ github.sha }}
sourcemaps: ./dist
url_prefix: ~/static/js
Performance Monitoring
// Custom transaction
const transaction = Sentry.startTransaction({
name: 'User Registration',
op: 'registration',
data: {
method: 'email',
},
});
Sentry.configureScope(scope => scope.setSpan(transaction));
try {
// Child span: validation
const validationSpan = transaction.startChild({
op: 'validation',
description: 'Validate user input',
});
validateInput(userData);
validationSpan.finish();
// Child span: database
const dbSpan = transaction.startChild({
op: 'db',
description: 'Create user in database',
});
await createUser(userData);
dbSpan.finish();
// Child span: email
const emailSpan = transaction.startChild({
op: 'email',
description: 'Send welcome email',
});
await sendEmail(userData.email);
emailSpan.finish();
transaction.setStatus('ok');
} catch (error) {
transaction.setStatus('internal_error');
Sentry.captureException(error);
} finally {
transaction.finish();
}
Common Configuration Mistakes
Not uploading source maps: Without source maps, Sentry shows minified stack traces. Upload source maps in CI with
sentry-cli releases filesor the GitHub Action.Over-sampling performance traces: 100% trace sampling generates excessive events (cost and rate limits). Use 0.1-0.2 for high-traffic services and 1.0 only during debugging.
Ignoring
beforeSendfor PII filtering: Sentry captures request bodies and error details which may contain PII. UsebeforeSendto redact sensitive fields.Not configuring release tracking: Without releases, you cannot track which version introduced an error. Set
releaseinSentry.init()and create releases in CI.Missing environment isolation: Development errors contaminate production error data. Set separate DSNs or use
environmentto distinguish dev, staging, and production errors.
Practice Questions
What is a Sentry DSN? Answer: The Data Source Name (DSN) is a unique URL that identifies your project and tells the Sentry SDK where to send events. It includes the project key and ingestion endpoint.
How does Sentry group similar errors? Answer: Sentry uses fingerprinting â it groups errors with the same stack trace, error type, and message into a single issue. Fingerprints can be customized with
beforeSendorfingerprintcallback.What is the purpose of source maps in Sentry? Answer: Source maps map minified JavaScript back to original source code, allowing Sentry to display readable stack traces with file names and line numbers.
How does Sentry Replay help debug frontend issues? Answer: Session Replay captures a video-like recording of user interactions (clicks, scrolls, navigation) leading up to an error, helping developers reproduce the issue.
Challenge
Integrate Sentry across a full-stack application: initialize the Node.js SDK for backend error and performance tracking, configure error handlers for Express routes, upload source maps for a React frontend with Sentry Error Boundary and Browser Tracing, create and associate Sentry releases with CI pipeline, set up alert rules for critical errors to Slack and PagerDuty, configure custom fingerprinting for known non-actionable errors, and verify that all errors include user context, breadcrumbs, and request data.
Built by the developers of Doda Browser, DodaZIP, and Durga Antivirus Pro.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro