Usamos cookies para mejorar tu experiencia en el sitio
CodeWorlds
Volver a colecciones
Guide29 min read

Sentry

Sentry is an error tracking and performance monitoring platform for applications. Complete guide for developers.

Sentry - Error Tracking & Performance Monitoring

Czym jest Sentry?

Sentry to wiodąca platforma do monitorowania błędów i wydajności aplikacji. Automatycznie przechwytuje wyjątki (exceptions), zbiera stack traces, kontekst błędu i pomaga zespołom szybko debugować problemy w produkcji. Sentry obsługuje ponad 100 języków i frameworków, w tym JavaScript, TypeScript, Python, Java, Go, PHP, Ruby i wiele innych.

Sentry został stworzony w 2012 roku i od tego czasu stał się standardem branżowym w error tracking. Używany jest przez miliony developerów i tysiące firm, od startupów po gigantów jak Disney, Cloudflare i Microsoft.

Dlaczego Sentry?

Kluczowe zalety

  1. Automatyczne przechwytywanie błędów - Integruje się z kodem i łapie wszystkie exceptions
  2. Szczegółowe stack traces - Pełny kontekst z source maps
  3. Session Replay - Nagrywanie sesji użytkowników
  4. Performance Monitoring - Śledzenie wydajności transakcji
  5. Alerting - Powiadomienia o nowych i regresujących błędach
  6. Release Tracking - Powiązanie błędów z wersjami
  7. Integrations - Slack, Jira, GitHub, GitLab i wiele innych

Sentry vs inne rozwiązania

CechaSentryBugsnagRollbarLogRocket
Error TrackingTakTakTakTak
PerformanceTakOgraniczoneNieTak
Session ReplayTakNieNieTak
Free Tier5K events/mo7.5K events/mo5K events/mo1K sessions/mo
Self-hostedTakNieNieNie
Open-sourceTakNieNieNie
Source MapsTakTakTakTak
Mobile SDKsTakTakTakTak

Kiedy wybrać Sentry?

Idealne dla:

  • Zespołów potrzebujących produkcyjnego error tracking
  • Aplikacji webowych (React, Vue, Angular, Next.js)
  • Aplikacji mobilnych (React Native, Flutter, iOS, Android)
  • Backendów (Node.js, Python, Go, Java)
  • Projektów wymagających performance monitoring

Instalacja

Next.js (zalecane)

Code
Bash
# Automatyczna konfiguracja przez wizard
npx @sentry/wizard@latest -i nextjs

# Lub manualnie
npm install @sentry/nextjs

Po uruchomieniu wizarda zostanie utworzonych kilka plików:

  • sentry.client.config.ts - Konfiguracja klienta
  • sentry.server.config.ts - Konfiguracja serwera
  • sentry.edge.config.ts - Konfiguracja edge runtime
  • next.config.js - Zmodyfikowana konfiguracja Next.js

React

Code
Bash
npm install @sentry/react
TSsrc/main.tsx
TypeScript
// src/main.tsx lub index.tsx
import * as Sentry from "@sentry/react";

Sentry.init({
  dsn: "https://examplePublicKey@o0.ingest.sentry.io/0",
  integrations: [
    Sentry.browserTracingIntegration(),
    Sentry.replayIntegration(),
  ],
  tracesSampleRate: 1.0,
  replaysSessionSampleRate: 0.1,
  replaysOnErrorSampleRate: 1.0,
});

// Wrap your app
const App = () => (
  <Sentry.ErrorBoundary fallback={<ErrorFallback />}>
    <YourApp />
  </Sentry.ErrorBoundary>
);

Node.js / Express

Code
Bash
npm install @sentry/node @sentry/profiling-node
TSinstrument.ts
TypeScript
// instrument.ts (musi być importowane PRZED innymi modułami)
import * as Sentry from "@sentry/node";
import { nodeProfilingIntegration } from "@sentry/profiling-node";

Sentry.init({
  dsn: "https://examplePublicKey@o0.ingest.sentry.io/0",
  integrations: [
    nodeProfilingIntegration(),
  ],
  tracesSampleRate: 1.0,
  profilesSampleRate: 1.0,
});
TSapp.ts
TypeScript
// app.ts
import "./instrument"; // Import first!
import * as Sentry from "@sentry/node";
import express from "express";

const app = express();

// Sentry request handler (before routes)
app.use(Sentry.Handlers.requestHandler());

// Sentry tracing handler
app.use(Sentry.Handlers.tracingHandler());

// Your routes
app.get("/", (req, res) => {
  res.send("Hello!");
});

// Sentry error handler (after routes, before other error handlers)
app.use(Sentry.Handlers.errorHandler());

app.listen(3000);

Python

Code
Bash
pip install sentry-sdk
Code
Python
# Django
import sentry_sdk

sentry_sdk.init(
    dsn="https://examplePublicKey@o0.ingest.sentry.io/0",
    traces_sample_rate=1.0,
    profiles_sample_rate=1.0,
)

# FastAPI
from fastapi import FastAPI
import sentry_sdk

sentry_sdk.init(
    dsn="https://examplePublicKey@o0.ingest.sentry.io/0",
    traces_sample_rate=1.0,
)

app = FastAPI()

Konfiguracja

Podstawowa konfiguracja Next.js

TSsentry.client.config.ts
TypeScript
// sentry.client.config.ts
import * as Sentry from "@sentry/nextjs";

Sentry.init({
  dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,

  // Performance Monitoring
  tracesSampleRate: 1.0, // 100% w development, zmniejsz w produkcji

  // Session Replay
  replaysSessionSampleRate: 0.1, // 10% sesji
  replaysOnErrorSampleRate: 1.0, // 100% sesji z błędami

  // Release tracking
  release: process.env.NEXT_PUBLIC_VERCEL_GIT_COMMIT_SHA,

  // Environment
  environment: process.env.NODE_ENV,

  // Filtering
  ignoreErrors: [
    // Ignoruj błędy które nie są problemem
    "ResizeObserver loop limit exceeded",
    "Non-Error exception captured",
    /Loading chunk \d+ failed/,
  ],

  // Before send hook
  beforeSend(event, hint) {
    // Filtruj lub modyfikuj eventy przed wysłaniem
    if (event.exception?.values?.[0]?.value?.includes("ChunkLoadError")) {
      return null; // Nie wysyłaj
    }
    return event;
  },

  // Debug mode
  debug: process.env.NODE_ENV === "development",
});
TSsentry.server.config.ts
TypeScript
// sentry.server.config.ts
import * as Sentry from "@sentry/nextjs";

Sentry.init({
  dsn: process.env.SENTRY_DSN,
  tracesSampleRate: 1.0,
  profilesSampleRate: 1.0,

  // Integrations
  integrations: [
    Sentry.prismaIntegration(), // Dla Prisma
  ],
});

Zmienne środowiskowe

.env.local
Bash
# .env.local
NEXT_PUBLIC_SENTRY_DSN=https://xxx@o0.ingest.sentry.io/0
SENTRY_DSN=https://xxx@o0.ingest.sentry.io/0
SENTRY_AUTH_TOKEN=sntrys_xxx
SENTRY_ORG=your-org
SENTRY_PROJECT=your-project

next.config.js

JSnext.config.js
JavaScript
// next.config.js
const { withSentryConfig } = require("@sentry/nextjs");

/** @type {import('next').NextConfig} */
const nextConfig = {
  // Your Next.js config
};

module.exports = withSentryConfig(nextConfig, {
  // Sentry webpack plugin options
  org: process.env.SENTRY_ORG,
  project: process.env.SENTRY_PROJECT,
  authToken: process.env.SENTRY_AUTH_TOKEN,

  // Upload source maps
  silent: !process.env.CI,
  widenClientFileUpload: true,
  hideSourceMaps: true,
  disableLogger: true,

  // Auto instrument
  automaticVercelMonitors: true,
});

Łapanie błędów

Automatyczne przechwytywanie

Code
TypeScript
// Wszystkie nieobsłużone exceptions są automatycznie łapane
function riskyOperation() {
  throw new Error("Something went wrong!");
}

// Unhandled promise rejections też
async function fetchData() {
  const response = await fetch("/api/data");
  if (!response.ok) {
    throw new Error(`HTTP error! status: ${response.status}`);
  }
  return response.json();
}

Manualne raportowanie

Code
TypeScript
import * as Sentry from "@sentry/nextjs";

// Przechwycenie błędu w try-catch
try {
  riskyOperation();
} catch (error) {
  Sentry.captureException(error);
  // Lub kontynuuj z graceful fallback
}

// Z dodatkowym kontekstem
try {
  await processOrder(orderId);
} catch (error) {
  Sentry.captureException(error, {
    tags: {
      feature: "checkout",
      orderType: "subscription",
    },
    extra: {
      orderId: orderId,
      items: orderItems,
      totalAmount: total,
    },
    user: {
      id: userId,
      email: userEmail,
      username: userName,
    },
    level: "error", // fatal, error, warning, info, debug
  });

  throw error; // Re-throw jeśli potrzeba
}

Raportowanie wiadomości

Code
TypeScript
// Log message bez wyjątku
Sentry.captureMessage("User completed checkout", "info");

// Z kontekstem
Sentry.captureMessage("Payment processing slow", {
  level: "warning",
  tags: {
    paymentProvider: "stripe",
  },
  extra: {
    processingTime: 5000,
    threshold: 3000,
  },
});

Breadcrumbs (ścieżka debugowania)

Code
TypeScript
// Automatyczne breadcrumbs (domyślnie włączone):
// - Console logs
// - DOM events (clicks, inputs)
// - XHR/Fetch requests
// - Navigation

// Manualne breadcrumbs
Sentry.addBreadcrumb({
  category: "auth",
  message: "User logged in",
  level: "info",
  data: {
    userId: user.id,
    method: "oauth",
    provider: "google",
  },
});

Sentry.addBreadcrumb({
  category: "ui.click",
  message: "User clicked Buy Now button",
  level: "info",
});

// Teraz gdy wystąpi błąd, zobaczysz te breadcrumbs
// pokazujące co użytkownik robił przed błędem

Kontekst użytkownika

Identyfikacja użytkownika

Code
TypeScript
// Ustaw użytkownika po zalogowaniu
Sentry.setUser({
  id: user.id,
  email: user.email,
  username: user.username,
  // Custom fields
  subscription: user.plan,
  company: user.company,
});

// Wyczyść po wylogowaniu
Sentry.setUser(null);

Custom Context

Code
TypeScript
// Ustaw globalny kontekst
Sentry.setContext("cart", {
  itemCount: 3,
  totalValue: 99.99,
  currency: "PLN",
});

Sentry.setContext("feature_flags", {
  newCheckout: true,
  darkMode: false,
  betaFeatures: ["ai-assistant", "bulk-export"],
});

// Tags (indeksowane, można filtrować)
Sentry.setTag("page_locale", "pl");
Sentry.setTag("tenant_id", "acme-corp");

// Extra (nieindeksowane, tylko do kontekstu)
Sentry.setExtra("last_api_response", apiResponse);

Performance Monitoring

Automatyczne śledzenie

Code
TypeScript
// Sentry automatycznie śledzi:
// - Page loads (Web Vitals: LCP, FID, CLS)
// - Navigation (route changes)
// - HTTP requests (fetch, XHR)
// - Database queries (z integracjami)

Custom Transactions

Code
TypeScript
import * as Sentry from "@sentry/nextjs";

// Mierz custom operację
async function processOrder(orderId: string) {
  const transaction = Sentry.startTransaction({
    op: "task",
    name: "Process Order",
    data: {
      orderId,
    },
  });

  // Ustaw jako aktualną transakcję
  Sentry.getCurrentHub().configureScope((scope) => {
    scope.setSpan(transaction);
  });

  try {
    // Span dla walidacji
    const validateSpan = transaction.startChild({
      op: "validate",
      description: "Validate order data",
    });
    await validateOrder(orderId);
    validateSpan.finish();

    // Span dla płatności
    const paymentSpan = transaction.startChild({
      op: "payment",
      description: "Process payment",
    });
    await processPayment(orderId);
    paymentSpan.finish();

    // Span dla wysyłki
    const shippingSpan = transaction.startChild({
      op: "shipping",
      description: "Create shipping label",
    });
    await createShippingLabel(orderId);
    shippingSpan.finish();

    transaction.setStatus("ok");
  } catch (error) {
    transaction.setStatus("internal_error");
    Sentry.captureException(error);
    throw error;
  } finally {
    transaction.finish();
  }
}

Spans w funkcjach

Code
TypeScript
import * as Sentry from "@sentry/nextjs";

// Wrapper dla automatycznego span tracking
async function withSpan<T>(
  name: string,
  operation: string,
  fn: () => Promise<T>
): Promise<T> {
  return Sentry.startSpan(
    {
      op: operation,
      name: name,
    },
    async () => {
      return await fn();
    }
  );
}

// Użycie
async function fetchUserData(userId: string) {
  return withSpan("Fetch User Data", "db.query", async () => {
    return await prisma.user.findUnique({
      where: { id: userId },
      include: { posts: true },
    });
  });
}

Web Vitals

Code
TypeScript
// Sentry automatycznie raportuje Web Vitals:
// - LCP (Largest Contentful Paint)
// - FID (First Input Delay)
// - CLS (Cumulative Layout Shift)
// - TTFB (Time to First Byte)
// - FCP (First Contentful Paint)

// Możesz też manualnie reportować custom vitals
Sentry.captureEvent({
  type: "transaction",
  transaction: "custom-metric",
  measurements: {
    custom_metric: { value: 123, unit: "millisecond" },
  },
});

Session Replay

Konfiguracja

Code
TypeScript
import * as Sentry from "@sentry/nextjs";

Sentry.init({
  dsn: "...",
  integrations: [
    Sentry.replayIntegration({
      // Maskowanie wrażliwych danych
      maskAllText: false,
      maskAllInputs: true,
      blockAllMedia: false,

      // Privacy
      mask: [".sensitive-data", '[data-sentry-mask="true"]'],
      block: [".private-content", "iframe"],

      // Networking
      networkDetailAllowUrls: ["/api/"],
      networkDetailDenyUrls: ["/api/auth/"],
      networkCaptureBodies: true,
      networkRequestHeaders: ["X-Request-Id"],
      networkResponseHeaders: ["X-Request-Id"],
    }),
  ],

  // Sample rates
  replaysSessionSampleRate: 0.1, // 10% wszystkich sesji
  replaysOnErrorSampleRate: 1.0, // 100% sesji z błędami
});

Privacy Controls

Code
HTML
<!-- Maskuj wrażliwe elementy -->
<input type="password" data-sentry-mask />
<div class="sensitive-data">Credit Card: 4242-****-****-4242</div>

<!-- Blokuj całkowicie -->
<div data-sentry-block>
  <video src="private-video.mp4" />
</div>

<!-- Ignoruj elementy -->
<button data-sentry-ignore>Click me</button>
Code
TypeScript
// Maskowanie programowe
Sentry.init({
  integrations: [
    Sentry.replayIntegration({
      mask: [
        // CSS selectors
        ".credit-card-number",
        ".social-security",
        '[data-privacy="sensitive"]',
      ],
    }),
  ],
});

Alerting

Konfiguracja alertów (w Sentry Dashboard)

Code
TEXT
# Alert Rules przykłady:

1. New Error Alert
   - When: A new issue is seen
   - Action: Send Slack notification

2. High Volume Alert
   - When: Number of events > 100 in 1 hour
   - Action: Send email to team

3. Critical Error Alert
   - When: Issue level is fatal
   - Action: Send PagerDuty alert

4. Regression Alert
   - When: Previously resolved issue reoccurs
   - Action: Send Slack + create Jira ticket

Programowe triggering alertów

Code
TypeScript
// Ustaw level na fatal dla krytycznych błędów
Sentry.captureException(error, {
  level: "fatal",
  tags: {
    critical: "true",
  },
});

// Lub użyj captureMessage
Sentry.captureMessage("Critical system failure", {
  level: "fatal",
  extra: {
    affectedUsers: 1500,
    downtime: "5 minutes",
  },
});

Release Tracking

Konfiguracja releases

TSsentry.client.config.ts
TypeScript
// sentry.client.config.ts
Sentry.init({
  dsn: "...",
  release: process.env.NEXT_PUBLIC_VERCEL_GIT_COMMIT_SHA,
  // lub
  release: "my-app@1.2.3",
});

Upload source maps

JSnext.config.js
JavaScript
// next.config.js
const { withSentryConfig } = require("@sentry/nextjs");

module.exports = withSentryConfig(nextConfig, {
  org: "your-org",
  project: "your-project",
  authToken: process.env.SENTRY_AUTH_TOKEN,

  // Source map options
  hideSourceMaps: true, // Ukryj mapy przed użytkownikami
  widenClientFileUpload: true, // Upload wszystkich plików JS
});

CLI dla releases

Code
Bash
# Instalacja CLI
npm install -g @sentry/cli

# Utwórz release
sentry-cli releases new my-app@1.2.3

# Upload source maps
sentry-cli releases files my-app@1.2.3 upload-sourcemaps ./dist

# Powiąż commity
sentry-cli releases set-commits my-app@1.2.3 --auto

# Finalizuj release
sentry-cli releases finalize my-app@1.2.3

# Deploy tracking
sentry-cli releases deploys my-app@1.2.3 new -e production

GitHub/GitLab Integration

.github/workflows/release.yml
YAML
# .github/workflows/release.yml
name: Release

on:
  push:
    tags:
      - "v*"

jobs:
  release:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Build
        run: npm run build

      - name: Create Sentry Release
        uses: getsentry/action-release@v1
        env:
          SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
          SENTRY_ORG: your-org
          SENTRY_PROJECT: your-project
        with:
          environment: production
          sourcemaps: "./dist"

Integracje

Slack

Code
TEXT
# W Sentry Dashboard:
# Settings > Integrations > Slack

# Konfiguracja:
1. Connect Slack workspace
2. Select channel for alerts
3. Configure alert rules

Jira

Code
TEXT
# Settings > Integrations > Jira

# Możliwości:
- Tworzenie issues z błędów
- Linkowanie istniejących issues
- Two-way sync statusów

GitHub

Code
TEXT
# Settings > Integrations > GitHub

# Możliwości:
- Suspect commits (który commit wprowadził błąd)
- Stack trace linking do kodu
- Release tracking z tagów

Vercel

Code
TypeScript
// Automatyczna integracja z Vercel:
// 1. Zainstaluj @sentry/nextjs
// 2. Ustaw zmienne środowiskowe w Vercel
// 3. Sentry automatycznie łączy się z deployments

// Automatic environment detection
Sentry.init({
  dsn: "...",
  environment: process.env.VERCEL_ENV || process.env.NODE_ENV,
});

Error Boundary (React)

Podstawowy Error Boundary

Code
TypeScript
import * as Sentry from "@sentry/react";

function ErrorFallback({ error, resetError }) {
  return (
    <div className="error-page">
      <h1>Coś poszło nie tak</h1>
      <p>Przepraszamy, wystąpił błąd. Nasz zespół został powiadomiony.</p>
      <button onClick={resetError}>Spróbuj ponownie</button>
    </div>
  );
}

// Wrap całą aplikację
function App() {
  return (
    <Sentry.ErrorBoundary
      fallback={ErrorFallback}
      onError={(error, componentStack) => {
        console.error("Error caught by boundary:", error);
      }}
      beforeCapture={(scope) => {
        scope.setTag("location", "app-root");
      }}
    >
      <Router>
        <Routes />
      </Router>
    </Sentry.ErrorBoundary>
  );
}

Granularne Error Boundaries

Code
TypeScript
import * as Sentry from "@sentry/react";

// Osobne boundaries dla różnych sekcji
function Dashboard() {
  return (
    <div>
      <Sentry.ErrorBoundary
        fallback={<ChartErrorFallback />}
        beforeCapture={(scope) => {
          scope.setTag("component", "analytics-chart");
        }}
      >
        <AnalyticsChart />
      </Sentry.ErrorBoundary>

      <Sentry.ErrorBoundary
        fallback={<TableErrorFallback />}
        beforeCapture={(scope) => {
          scope.setTag("component", "users-table");
        }}
      >
        <UsersTable />
      </Sentry.ErrorBoundary>
    </div>
  );
}

Filtrowanie i sampling

Filtrowanie błędów

Code
TypeScript
Sentry.init({
  dsn: "...",

  // Ignoruj konkretne błędy
  ignoreErrors: [
    // String matching
    "ResizeObserver loop limit exceeded",
    "Non-Error exception captured",

    // Regex matching
    /Loading chunk \d+ failed/,
    /Network request failed/,
    /AbortError/,
  ],

  // Ignoruj transakcje
  ignoreTransactions: [
    "health-check",
    "/api/health",
  ],

  // Filtruj URLs
  denyUrls: [
    /extensions\//i,
    /^chrome:\/\//i,
    /^moz-extension:\/\//i,
  ],

  allowUrls: [
    /https?:\/\/yourapp\.com/,
    /https?:\/\/.*\.yourapp\.com/,
  ],
});

Before Send Hook

Code
TypeScript
Sentry.init({
  dsn: "...",

  beforeSend(event, hint) {
    // Nie wysyłaj błędów z dev tools
    if (event.exception?.values?.[0]?.stacktrace?.frames?.some(
      (frame) => frame.filename?.includes("devtools")
    )) {
      return null;
    }

    // Nie wysyłaj błędów botów
    const userAgent = event.request?.headers?.["user-agent"];
    if (userAgent && /bot|crawler|spider/i.test(userAgent)) {
      return null;
    }

    // Redact sensitive data
    if (event.request?.data) {
      const data = event.request.data;
      if (typeof data === "string" && data.includes("password")) {
        event.request.data = "[REDACTED]";
      }
    }

    // Modify event
    event.tags = {
      ...event.tags,
      processed: "true",
    };

    return event;
  },

  beforeSendTransaction(event) {
    // Filtruj wolne health checks
    if (event.transaction === "/api/health" && event.measurements?.lcp?.value < 100) {
      return null;
    }
    return event;
  },
});

Sampling

Code
TypeScript
Sentry.init({
  dsn: "...",

  // Error sampling (domyślnie 100%)
  sampleRate: 1.0,

  // Transaction sampling
  tracesSampleRate: 0.2, // 20% transakcji

  // Lub dynamiczny sampling
  tracesSampler: (samplingContext) => {
    // Zawsze zbieraj dla krytycznych operacji
    if (samplingContext.transactionContext.name.includes("checkout")) {
      return 1.0;
    }

    // Mniej dla health checks
    if (samplingContext.transactionContext.name.includes("health")) {
      return 0.01;
    }

    // Domyślnie 20%
    return 0.2;
  },

  // Replay sampling
  replaysSessionSampleRate: 0.1, // 10%
  replaysOnErrorSampleRate: 1.0, // 100% przy błędzie
});

Best practices

Struktura projektu

Code
TEXT
src/
├── lib/
│   ├── sentry.ts           # Sentry helpers
│   └── monitoring.ts       # Custom monitoring
├── components/
│   └── ErrorBoundary.tsx   # Custom error boundary
└── instrumentation.ts      # Next.js instrumentation

# Root files
├── sentry.client.config.ts
├── sentry.server.config.ts
├── sentry.edge.config.ts
└── next.config.js

Helper functions

TSlib/sentry.ts
TypeScript
// lib/sentry.ts
import * as Sentry from "@sentry/nextjs";

// Typed error capture
export function captureError(
  error: Error,
  context?: {
    tags?: Record<string, string>;
    extra?: Record<string, unknown>;
    level?: Sentry.SeverityLevel;
  }
) {
  Sentry.captureException(error, {
    tags: context?.tags,
    extra: context?.extra,
    level: context?.level || "error",
  });
}

// Track feature usage
export function trackFeatureUsage(
  feature: string,
  metadata?: Record<string, unknown>
) {
  Sentry.addBreadcrumb({
    category: "feature",
    message: `Used feature: ${feature}`,
    level: "info",
    data: metadata,
  });
}

// Performance wrapper
export async function withPerformance<T>(
  name: string,
  fn: () => Promise<T>
): Promise<T> {
  return Sentry.startSpan({ op: "function", name }, async () => {
    return await fn();
  });
}

// User identification
export function identifyUser(user: {
  id: string;
  email?: string;
  name?: string;
  plan?: string;
}) {
  Sentry.setUser({
    id: user.id,
    email: user.email,
    username: user.name,
    subscription: user.plan,
  });
}

export function clearUser() {
  Sentry.setUser(null);
}

Środowiska

Code
TypeScript
// Różna konfiguracja per environment
const isDev = process.env.NODE_ENV === "development";
const isProd = process.env.NODE_ENV === "production";

Sentry.init({
  dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,
  enabled: isProd, // Wyłącz w development
  environment: process.env.VERCEL_ENV || process.env.NODE_ENV,

  // Więcej danych w dev
  debug: isDev,
  attachStacktrace: true,

  // Mniej samplingowania w dev
  tracesSampleRate: isDev ? 1.0 : 0.2,
  replaysSessionSampleRate: isDev ? 0 : 0.1,
});

Cennik

Developer (Free)

  • 5,000 errors/month
  • 10,000 performance units/month
  • 1 team member
  • 30-day data retention
  • Email support

Team ($26/month)

  • 50,000 errors/month
  • 100,000 performance units/month
  • Unlimited team members
  • 90-day data retention
  • Session Replay
  • Priority support

Business ($80/month)

  • 100,000 errors/month
  • 250,000 performance units/month
  • Cross-project issues
  • 90-day data retention
  • SSO/SAML
  • Dedicated support

Enterprise (Custom)

  • Custom volume
  • Custom retention
  • On-premise option
  • SLA guarantees
  • Dedicated account manager

FAQ - Najczęściej zadawane pytania

Ile kosztuje Sentry?

Plan Developer jest darmowy z 5K events/month. Plan Team zaczyna się od $26/month. Dla większości małych projektów darmowy plan wystarcza.

Czy Sentry spowalnia aplikację?

Nie znacząco. Sentry jest zaprojektowane do minimalnego wpływu na performance. Możesz też kontrolować sampling rate aby zmniejszyć overhead.

Jak usunąć wrażliwe dane?

Używaj beforeSend hook do filtrowania danych, maskuj elementy w Session Replay, i skonfiguruj scrubAllData dla automatycznego usuwania PII.

Czy mogę self-hostować Sentry?

Tak, Sentry jest open-source. Możesz uruchomić własną instancję używając Docker. Jednak cloud version jest zalecana dla większości użytkowników.

Jak zintegrować z CI/CD?

Użyj @sentry/cli lub GitHub Actions do automatycznego tworzenia releases i uploadowania source maps podczas deploymentu.

Podsumowanie

Sentry to kompleksowe rozwiązanie do monitorowania aplikacji, oferujące:

  • Error Tracking - Automatyczne przechwytywanie i raportowanie błędów
  • Performance Monitoring - Śledzenie wydajności transakcji
  • Session Replay - Nagrywanie sesji dla debugowania
  • Release Tracking - Powiązanie błędów z wersjami
  • Alerting - Powiadomienia o problemach
  • Integrations - Slack, Jira, GitHub i wiele innych

Dla zespołów pracujących nad aplikacjami produkcyjnymi, Sentry jest niezbędnym narzędziem do szybkiego wykrywania i naprawiania problemów.


Sentry - Error Tracking & Performance Monitoring

What is Sentry?

Sentry is the leading platform for monitoring application errors and performance. It automatically captures exceptions, collects stack traces, error context, and helps teams quickly debug production issues. Sentry supports over 100 languages and frameworks, including JavaScript, TypeScript, Python, Java, Go, PHP, Ruby, and many others.

Sentry was created in 2012 and since then has become the industry standard in error tracking. It is used by millions of developers and thousands of companies, from startups to giants like Disney, Cloudflare, and Microsoft.

Why Sentry?

Key advantages

  1. Automatic error capture - Integrates with your code and catches all exceptions
  2. Detailed stack traces - Full context with source maps
  3. Session Replay - Recording user sessions
  4. Performance Monitoring - Tracking transaction performance
  5. Alerting - Notifications for new and regressing errors
  6. Release Tracking - Linking errors to specific versions
  7. Integrations - Slack, Jira, GitHub, GitLab, and many others

Sentry vs other solutions

FeatureSentryBugsnagRollbarLogRocket
Error TrackingYesYesYesYes
PerformanceYesLimitedNoYes
Session ReplayYesNoNoYes
Free Tier5K events/mo7.5K events/mo5K events/mo1K sessions/mo
Self-hostedYesNoNoNo
Open-sourceYesNoNoNo
Source MapsYesYesYesYes
Mobile SDKsYesYesYesYes

When to choose Sentry?

Ideal for:

  • Teams needing production error tracking
  • Web applications (React, Vue, Angular, Next.js)
  • Mobile applications (React Native, Flutter, iOS, Android)
  • Backends (Node.js, Python, Go, Java)
  • Projects requiring performance monitoring

Installation

Next.js (recommended)

Code
Bash
# Automatic configuration via wizard
npx @sentry/wizard@latest -i nextjs

# Or manually
npm install @sentry/nextjs

After running the wizard, several files will be created:

  • sentry.client.config.ts - Client configuration
  • sentry.server.config.ts - Server configuration
  • sentry.edge.config.ts - Edge runtime configuration
  • next.config.js - Modified Next.js configuration

React

Code
Bash
npm install @sentry/react
TSsrc/main.tsx
TypeScript
// src/main.tsx or index.tsx
import * as Sentry from "@sentry/react";

Sentry.init({
  dsn: "https://examplePublicKey@o0.ingest.sentry.io/0",
  integrations: [
    Sentry.browserTracingIntegration(),
    Sentry.replayIntegration(),
  ],
  tracesSampleRate: 1.0,
  replaysSessionSampleRate: 0.1,
  replaysOnErrorSampleRate: 1.0,
});

// Wrap your app
const App = () => (
  <Sentry.ErrorBoundary fallback={<ErrorFallback />}>
    <YourApp />
  </Sentry.ErrorBoundary>
);

Node.js / Express

Code
Bash
npm install @sentry/node @sentry/profiling-node
TSinstrument.ts
TypeScript
// instrument.ts (must be imported BEFORE other modules)
import * as Sentry from "@sentry/node";
import { nodeProfilingIntegration } from "@sentry/profiling-node";

Sentry.init({
  dsn: "https://examplePublicKey@o0.ingest.sentry.io/0",
  integrations: [
    nodeProfilingIntegration(),
  ],
  tracesSampleRate: 1.0,
  profilesSampleRate: 1.0,
});
TSapp.ts
TypeScript
// app.ts
import "./instrument"; // Import first!
import * as Sentry from "@sentry/node";
import express from "express";

const app = express();

// Sentry request handler (before routes)
app.use(Sentry.Handlers.requestHandler());

// Sentry tracing handler
app.use(Sentry.Handlers.tracingHandler());

// Your routes
app.get("/", (req, res) => {
  res.send("Hello!");
});

// Sentry error handler (after routes, before other error handlers)
app.use(Sentry.Handlers.errorHandler());

app.listen(3000);

Python

Code
Bash
pip install sentry-sdk
Code
Python
# Django
import sentry_sdk

sentry_sdk.init(
    dsn="https://examplePublicKey@o0.ingest.sentry.io/0",
    traces_sample_rate=1.0,
    profiles_sample_rate=1.0,
)

# FastAPI
from fastapi import FastAPI
import sentry_sdk

sentry_sdk.init(
    dsn="https://examplePublicKey@o0.ingest.sentry.io/0",
    traces_sample_rate=1.0,
)

app = FastAPI()

Configuration

Basic Next.js configuration

TSsentry.client.config.ts
TypeScript
// sentry.client.config.ts
import * as Sentry from "@sentry/nextjs";

Sentry.init({
  dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,

  // Performance Monitoring
  tracesSampleRate: 1.0, // 100% in development, reduce in production

  // Session Replay
  replaysSessionSampleRate: 0.1, // 10% of sessions
  replaysOnErrorSampleRate: 1.0, // 100% of sessions with errors

  // Release tracking
  release: process.env.NEXT_PUBLIC_VERCEL_GIT_COMMIT_SHA,

  // Environment
  environment: process.env.NODE_ENV,

  // Filtering
  ignoreErrors: [
    // Ignore errors that are not real problems
    "ResizeObserver loop limit exceeded",
    "Non-Error exception captured",
    /Loading chunk \d+ failed/,
  ],

  // Before send hook
  beforeSend(event, hint) {
    // Filter or modify events before sending
    if (event.exception?.values?.[0]?.value?.includes("ChunkLoadError")) {
      return null; // Don't send
    }
    return event;
  },

  // Debug mode
  debug: process.env.NODE_ENV === "development",
});
TSsentry.server.config.ts
TypeScript
// sentry.server.config.ts
import * as Sentry from "@sentry/nextjs";

Sentry.init({
  dsn: process.env.SENTRY_DSN,
  tracesSampleRate: 1.0,
  profilesSampleRate: 1.0,

  // Integrations
  integrations: [
    Sentry.prismaIntegration(), // For Prisma
  ],
});

Environment variables

.env.local
Bash
# .env.local
NEXT_PUBLIC_SENTRY_DSN=https://xxx@o0.ingest.sentry.io/0
SENTRY_DSN=https://xxx@o0.ingest.sentry.io/0
SENTRY_AUTH_TOKEN=sntrys_xxx
SENTRY_ORG=your-org
SENTRY_PROJECT=your-project

next.config.js

JSnext.config.js
JavaScript
// next.config.js
const { withSentryConfig } = require("@sentry/nextjs");

/** @type {import('next').NextConfig} */
const nextConfig = {
  // Your Next.js config
};

module.exports = withSentryConfig(nextConfig, {
  // Sentry webpack plugin options
  org: process.env.SENTRY_ORG,
  project: process.env.SENTRY_PROJECT,
  authToken: process.env.SENTRY_AUTH_TOKEN,

  // Upload source maps
  silent: !process.env.CI,
  widenClientFileUpload: true,
  hideSourceMaps: true,
  disableLogger: true,

  // Auto instrument
  automaticVercelMonitors: true,
});

Catching errors

Automatic capture

Code
TypeScript
// All unhandled exceptions are automatically captured
function riskyOperation() {
  throw new Error("Something went wrong!");
}

// Unhandled promise rejections too
async function fetchData() {
  const response = await fetch("/api/data");
  if (!response.ok) {
    throw new Error(`HTTP error! status: ${response.status}`);
  }
  return response.json();
}

Manual reporting

Code
TypeScript
import * as Sentry from "@sentry/nextjs";

// Capture error in try-catch
try {
  riskyOperation();
} catch (error) {
  Sentry.captureException(error);
  // Or continue with graceful fallback
}

// With additional context
try {
  await processOrder(orderId);
} catch (error) {
  Sentry.captureException(error, {
    tags: {
      feature: "checkout",
      orderType: "subscription",
    },
    extra: {
      orderId: orderId,
      items: orderItems,
      totalAmount: total,
    },
    user: {
      id: userId,
      email: userEmail,
      username: userName,
    },
    level: "error", // fatal, error, warning, info, debug
  });

  throw error; // Re-throw if needed
}

Message reporting

Code
TypeScript
// Log message without an exception
Sentry.captureMessage("User completed checkout", "info");

// With context
Sentry.captureMessage("Payment processing slow", {
  level: "warning",
  tags: {
    paymentProvider: "stripe",
  },
  extra: {
    processingTime: 5000,
    threshold: 3000,
  },
});

Breadcrumbs (debugging trail)

Code
TypeScript
// Automatic breadcrumbs (enabled by default):
// - Console logs
// - DOM events (clicks, inputs)
// - XHR/Fetch requests
// - Navigation

// Manual breadcrumbs
Sentry.addBreadcrumb({
  category: "auth",
  message: "User logged in",
  level: "info",
  data: {
    userId: user.id,
    method: "oauth",
    provider: "google",
  },
});

Sentry.addBreadcrumb({
  category: "ui.click",
  message: "User clicked Buy Now button",
  level: "info",
});

// Now when an error occurs, you will see these breadcrumbs
// showing what the user was doing before the error

User context

User identification

Code
TypeScript
// Set user after login
Sentry.setUser({
  id: user.id,
  email: user.email,
  username: user.username,
  // Custom fields
  subscription: user.plan,
  company: user.company,
});

// Clear after logout
Sentry.setUser(null);

Custom Context

Code
TypeScript
// Set global context
Sentry.setContext("cart", {
  itemCount: 3,
  totalValue: 99.99,
  currency: "PLN",
});

Sentry.setContext("feature_flags", {
  newCheckout: true,
  darkMode: false,
  betaFeatures: ["ai-assistant", "bulk-export"],
});

// Tags (indexed, can be used for filtering)
Sentry.setTag("page_locale", "pl");
Sentry.setTag("tenant_id", "acme-corp");

// Extra (not indexed, for context only)
Sentry.setExtra("last_api_response", apiResponse);

Performance Monitoring

Automatic tracking

Code
TypeScript
// Sentry automatically tracks:
// - Page loads (Web Vitals: LCP, FID, CLS)
// - Navigation (route changes)
// - HTTP requests (fetch, XHR)
// - Database queries (with integrations)

Custom Transactions

Code
TypeScript
import * as Sentry from "@sentry/nextjs";

// Measure a custom operation
async function processOrder(orderId: string) {
  const transaction = Sentry.startTransaction({
    op: "task",
    name: "Process Order",
    data: {
      orderId,
    },
  });

  // Set as current transaction
  Sentry.getCurrentHub().configureScope((scope) => {
    scope.setSpan(transaction);
  });

  try {
    // Span for validation
    const validateSpan = transaction.startChild({
      op: "validate",
      description: "Validate order data",
    });
    await validateOrder(orderId);
    validateSpan.finish();

    // Span for payment
    const paymentSpan = transaction.startChild({
      op: "payment",
      description: "Process payment",
    });
    await processPayment(orderId);
    paymentSpan.finish();

    // Span for shipping
    const shippingSpan = transaction.startChild({
      op: "shipping",
      description: "Create shipping label",
    });
    await createShippingLabel(orderId);
    shippingSpan.finish();

    transaction.setStatus("ok");
  } catch (error) {
    transaction.setStatus("internal_error");
    Sentry.captureException(error);
    throw error;
  } finally {
    transaction.finish();
  }
}

Spans in functions

Code
TypeScript
import * as Sentry from "@sentry/nextjs";

// Wrapper for automatic span tracking
async function withSpan<T>(
  name: string,
  operation: string,
  fn: () => Promise<T>
): Promise<T> {
  return Sentry.startSpan(
    {
      op: operation,
      name: name,
    },
    async () => {
      return await fn();
    }
  );
}

// Usage
async function fetchUserData(userId: string) {
  return withSpan("Fetch User Data", "db.query", async () => {
    return await prisma.user.findUnique({
      where: { id: userId },
      include: { posts: true },
    });
  });
}

Web Vitals

Code
TypeScript
// Sentry automatically reports Web Vitals:
// - LCP (Largest Contentful Paint)
// - FID (First Input Delay)
// - CLS (Cumulative Layout Shift)
// - TTFB (Time to First Byte)
// - FCP (First Contentful Paint)

// You can also manually report custom vitals
Sentry.captureEvent({
  type: "transaction",
  transaction: "custom-metric",
  measurements: {
    custom_metric: { value: 123, unit: "millisecond" },
  },
});

Session Replay

Configuration

Code
TypeScript
import * as Sentry from "@sentry/nextjs";

Sentry.init({
  dsn: "...",
  integrations: [
    Sentry.replayIntegration({
      // Masking sensitive data
      maskAllText: false,
      maskAllInputs: true,
      blockAllMedia: false,

      // Privacy
      mask: [".sensitive-data", '[data-sentry-mask="true"]'],
      block: [".private-content", "iframe"],

      // Networking
      networkDetailAllowUrls: ["/api/"],
      networkDetailDenyUrls: ["/api/auth/"],
      networkCaptureBodies: true,
      networkRequestHeaders: ["X-Request-Id"],
      networkResponseHeaders: ["X-Request-Id"],
    }),
  ],

  // Sample rates
  replaysSessionSampleRate: 0.1, // 10% of all sessions
  replaysOnErrorSampleRate: 1.0, // 100% of sessions with errors
});

Privacy Controls

Code
HTML
<!-- Mask sensitive elements -->
<input type="password" data-sentry-mask />
<div class="sensitive-data">Credit Card: 4242-****-****-4242</div>

<!-- Block entirely -->
<div data-sentry-block>
  <video src="private-video.mp4" />
</div>

<!-- Ignore elements -->
<button data-sentry-ignore>Click me</button>
Code
TypeScript
// Programmatic masking
Sentry.init({
  integrations: [
    Sentry.replayIntegration({
      mask: [
        // CSS selectors
        ".credit-card-number",
        ".social-security",
        '[data-privacy="sensitive"]',
      ],
    }),
  ],
});

Alerting

Alert configuration (in Sentry Dashboard)

Code
TEXT
# Alert Rules examples:

1. New Error Alert
   - When: A new issue is seen
   - Action: Send Slack notification

2. High Volume Alert
   - When: Number of events > 100 in 1 hour
   - Action: Send email to team

3. Critical Error Alert
   - When: Issue level is fatal
   - Action: Send PagerDuty alert

4. Regression Alert
   - When: Previously resolved issue reoccurs
   - Action: Send Slack + create Jira ticket

Programmatic alert triggering

Code
TypeScript
// Set level to fatal for critical errors
Sentry.captureException(error, {
  level: "fatal",
  tags: {
    critical: "true",
  },
});

// Or use captureMessage
Sentry.captureMessage("Critical system failure", {
  level: "fatal",
  extra: {
    affectedUsers: 1500,
    downtime: "5 minutes",
  },
});

Release Tracking

Release configuration

TSsentry.client.config.ts
TypeScript
// sentry.client.config.ts
Sentry.init({
  dsn: "...",
  release: process.env.NEXT_PUBLIC_VERCEL_GIT_COMMIT_SHA,
  // or
  release: "my-app@1.2.3",
});

Upload source maps

JSnext.config.js
JavaScript
// next.config.js
const { withSentryConfig } = require("@sentry/nextjs");

module.exports = withSentryConfig(nextConfig, {
  org: "your-org",
  project: "your-project",
  authToken: process.env.SENTRY_AUTH_TOKEN,

  // Source map options
  hideSourceMaps: true, // Hide maps from users
  widenClientFileUpload: true, // Upload all JS files
});

CLI for releases

Code
Bash
# Install CLI
npm install -g @sentry/cli

# Create release
sentry-cli releases new my-app@1.2.3

# Upload source maps
sentry-cli releases files my-app@1.2.3 upload-sourcemaps ./dist

# Associate commits
sentry-cli releases set-commits my-app@1.2.3 --auto

# Finalize release
sentry-cli releases finalize my-app@1.2.3

# Deploy tracking
sentry-cli releases deploys my-app@1.2.3 new -e production

GitHub/GitLab Integration

.github/workflows/release.yml
YAML
# .github/workflows/release.yml
name: Release

on:
  push:
    tags:
      - "v*"

jobs:
  release:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Build
        run: npm run build

      - name: Create Sentry Release
        uses: getsentry/action-release@v1
        env:
          SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
          SENTRY_ORG: your-org
          SENTRY_PROJECT: your-project
        with:
          environment: production
          sourcemaps: "./dist"

Integrations

Slack

Code
TEXT
# In Sentry Dashboard:
# Settings > Integrations > Slack

# Configuration:
1. Connect Slack workspace
2. Select channel for alerts
3. Configure alert rules

Jira

Code
TEXT
# Settings > Integrations > Jira

# Capabilities:
- Creating issues from errors
- Linking existing issues
- Two-way status sync

GitHub

Code
TEXT
# Settings > Integrations > GitHub

# Capabilities:
- Suspect commits (which commit introduced the error)
- Stack trace linking to code
- Release tracking from tags

Vercel

Code
TypeScript
// Automatic integration with Vercel:
// 1. Install @sentry/nextjs
// 2. Set environment variables in Vercel
// 3. Sentry automatically connects with deployments

// Automatic environment detection
Sentry.init({
  dsn: "...",
  environment: process.env.VERCEL_ENV || process.env.NODE_ENV,
});

Error Boundary (React)

Basic Error Boundary

Code
TypeScript
import * as Sentry from "@sentry/react";

function ErrorFallback({ error, resetError }) {
  return (
    <div className="error-page">
      <h1>Something went wrong</h1>
      <p>We're sorry, an error occurred. Our team has been notified.</p>
      <button onClick={resetError}>Try again</button>
    </div>
  );
}

// Wrap the entire application
function App() {
  return (
    <Sentry.ErrorBoundary
      fallback={ErrorFallback}
      onError={(error, componentStack) => {
        console.error("Error caught by boundary:", error);
      }}
      beforeCapture={(scope) => {
        scope.setTag("location", "app-root");
      }}
    >
      <Router>
        <Routes />
      </Router>
    </Sentry.ErrorBoundary>
  );
}

Granular Error Boundaries

Code
TypeScript
import * as Sentry from "@sentry/react";

// Separate boundaries for different sections
function Dashboard() {
  return (
    <div>
      <Sentry.ErrorBoundary
        fallback={<ChartErrorFallback />}
        beforeCapture={(scope) => {
          scope.setTag("component", "analytics-chart");
        }}
      >
        <AnalyticsChart />
      </Sentry.ErrorBoundary>

      <Sentry.ErrorBoundary
        fallback={<TableErrorFallback />}
        beforeCapture={(scope) => {
          scope.setTag("component", "users-table");
        }}
      >
        <UsersTable />
      </Sentry.ErrorBoundary>
    </div>
  );
}

Filtering and sampling

Error filtering

Code
TypeScript
Sentry.init({
  dsn: "...",

  // Ignore specific errors
  ignoreErrors: [
    // String matching
    "ResizeObserver loop limit exceeded",
    "Non-Error exception captured",

    // Regex matching
    /Loading chunk \d+ failed/,
    /Network request failed/,
    /AbortError/,
  ],

  // Ignore transactions
  ignoreTransactions: [
    "health-check",
    "/api/health",
  ],

  // Filter URLs
  denyUrls: [
    /extensions\//i,
    /^chrome:\/\//i,
    /^moz-extension:\/\//i,
  ],

  allowUrls: [
    /https?:\/\/yourapp\.com/,
    /https?:\/\/.*\.yourapp\.com/,
  ],
});

Before Send Hook

Code
TypeScript
Sentry.init({
  dsn: "...",

  beforeSend(event, hint) {
    // Don't send errors from dev tools
    if (event.exception?.values?.[0]?.stacktrace?.frames?.some(
      (frame) => frame.filename?.includes("devtools")
    )) {
      return null;
    }

    // Don't send bot errors
    const userAgent = event.request?.headers?.["user-agent"];
    if (userAgent && /bot|crawler|spider/i.test(userAgent)) {
      return null;
    }

    // Redact sensitive data
    if (event.request?.data) {
      const data = event.request.data;
      if (typeof data === "string" && data.includes("password")) {
        event.request.data = "[REDACTED]";
      }
    }

    // Modify event
    event.tags = {
      ...event.tags,
      processed: "true",
    };

    return event;
  },

  beforeSendTransaction(event) {
    // Filter slow health checks
    if (event.transaction === "/api/health" && event.measurements?.lcp?.value < 100) {
      return null;
    }
    return event;
  },
});

Sampling

Code
TypeScript
Sentry.init({
  dsn: "...",

  // Error sampling (100% by default)
  sampleRate: 1.0,

  // Transaction sampling
  tracesSampleRate: 0.2, // 20% of transactions

  // Or dynamic sampling
  tracesSampler: (samplingContext) => {
    // Always collect for critical operations
    if (samplingContext.transactionContext.name.includes("checkout")) {
      return 1.0;
    }

    // Less for health checks
    if (samplingContext.transactionContext.name.includes("health")) {
      return 0.01;
    }

    // Default 20%
    return 0.2;
  },

  // Replay sampling
  replaysSessionSampleRate: 0.1, // 10%
  replaysOnErrorSampleRate: 1.0, // 100% on error
});

Best practices

Project structure

Code
TEXT
src/
├── lib/
│   ├── sentry.ts           # Sentry helpers
│   └── monitoring.ts       # Custom monitoring
├── components/
│   └── ErrorBoundary.tsx   # Custom error boundary
└── instrumentation.ts      # Next.js instrumentation

# Root files
├── sentry.client.config.ts
├── sentry.server.config.ts
├── sentry.edge.config.ts
└── next.config.js

Helper functions

TSlib/sentry.ts
TypeScript
// lib/sentry.ts
import * as Sentry from "@sentry/nextjs";

// Typed error capture
export function captureError(
  error: Error,
  context?: {
    tags?: Record<string, string>;
    extra?: Record<string, unknown>;
    level?: Sentry.SeverityLevel;
  }
) {
  Sentry.captureException(error, {
    tags: context?.tags,
    extra: context?.extra,
    level: context?.level || "error",
  });
}

// Track feature usage
export function trackFeatureUsage(
  feature: string,
  metadata?: Record<string, unknown>
) {
  Sentry.addBreadcrumb({
    category: "feature",
    message: `Used feature: ${feature}`,
    level: "info",
    data: metadata,
  });
}

// Performance wrapper
export async function withPerformance<T>(
  name: string,
  fn: () => Promise<T>
): Promise<T> {
  return Sentry.startSpan({ op: "function", name }, async () => {
    return await fn();
  });
}

// User identification
export function identifyUser(user: {
  id: string;
  email?: string;
  name?: string;
  plan?: string;
}) {
  Sentry.setUser({
    id: user.id,
    email: user.email,
    username: user.name,
    subscription: user.plan,
  });
}

export function clearUser() {
  Sentry.setUser(null);
}

Environments

Code
TypeScript
// Different configuration per environment
const isDev = process.env.NODE_ENV === "development";
const isProd = process.env.NODE_ENV === "production";

Sentry.init({
  dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,
  enabled: isProd, // Disable in development
  environment: process.env.VERCEL_ENV || process.env.NODE_ENV,

  // More data in dev
  debug: isDev,
  attachStacktrace: true,

  // Less sampling in dev
  tracesSampleRate: isDev ? 1.0 : 0.2,
  replaysSessionSampleRate: isDev ? 0 : 0.1,
});

Pricing

Developer (Free)

  • 5,000 errors/month
  • 10,000 performance units/month
  • 1 team member
  • 30-day data retention
  • Email support

Team ($26/month)

  • 50,000 errors/month
  • 100,000 performance units/month
  • Unlimited team members
  • 90-day data retention
  • Session Replay
  • Priority support

Business ($80/month)

  • 100,000 errors/month
  • 250,000 performance units/month
  • Cross-project issues
  • 90-day data retention
  • SSO/SAML
  • Dedicated support

Enterprise (Custom)

  • Custom volume
  • Custom retention
  • On-premise option
  • SLA guarantees
  • Dedicated account manager

FAQ - Frequently asked questions

How much does Sentry cost?

The Developer plan is free with 5K events/month. The Team plan starts at $26/month. For most small projects, the free plan is sufficient.

Does Sentry slow down the application?

Not significantly. Sentry is designed for minimal performance impact. You can also control the sampling rate to reduce overhead.

How to remove sensitive data?

Use the beforeSend hook to filter data, mask elements in Session Replay, and configure scrubAllData for automatic PII removal.

Can I self-host Sentry?

Yes, Sentry is open-source. You can run your own instance using Docker. However, the cloud version is recommended for most users.

How to integrate with CI/CD?

Use @sentry/cli or GitHub Actions for automatic release creation and source map uploading during deployment.

Summary

Sentry is a comprehensive application monitoring solution, offering:

  • Error Tracking - Automatic error capture and reporting
  • Performance Monitoring - Transaction performance tracking
  • Session Replay - Session recording for debugging
  • Release Tracking - Linking errors to specific versions
  • Alerting - Notifications about issues
  • Integrations - Slack, Jira, GitHub, and many others

For teams working on production applications, Sentry is an essential tool for quickly detecting and fixing problems.