Sentry Error Tracking Samples

Comprehensive Sentry error tracking and performance monitoring setup with SDK integrations for various platforms

Key Facts

Category
Error Monitoring
Items
4
Format Families
json, audio

Sample Overview

Comprehensive Sentry error tracking and performance monitoring setup with SDK integrations for various platforms This sample set belongs to Error Monitoring and can be used to test related workflows inside Elysia Tools.

💻 Sentry JavaScript SDK Setup javascript

🟡 intermediate ⭐⭐⭐

Complete JavaScript SDK configuration for browser and Node.js applications with error tracking and performance monitoring

⏱️ 30 min 🏷️ sentry, javascript, react, node.js, monitoring, error-tracking
Prerequisites: JavaScript/Node.js, npm, Sentry account
// Sentry JavaScript SDK Configuration
// Install: npm install @sentry/browser @sentry/node @sentry/tracing

// Frontend Browser Setup
// sentry-browser.js
import * as Sentry from "@sentry/browser";
import { BrowserTracing } from "@sentry/tracing";

// Initialize Sentry for browser
Sentry.init({
  dsn: "https://[email protected]/project-id",

  // Environment
  environment: process.env.NODE_ENV || "development",

  // Release version
  release: `my-app@${process.env.APP_VERSION || "1.0.0"}`,

  // Performance monitoring
  integrations: [
    new BrowserTracing({
      // Set custom tracing options
      routingInstrumentation: Sentry.reactRouterV6Instrumentation(
        React.useEffect,
        useLocation,
        useNavigationType,
        createRoutesFromChildren,
        matchRoutes
      ),
    }),
  ],

  // Performance settings
  tracesSampleRate: 1.0, // Capture 100% of transactions for testing

  // Error sampling
  sampleRate: 1.0, // Capture 100% of errors

  // Before send callback for error filtering/enhancement
  beforeSend(event, hint) {
    // Add custom context
    event.contexts = {
      ...event.contexts,
      app: {
        name: "My Web App",
        version: process.env.APP_VERSION,
        buildNumber: process.env.BUILD_NUMBER
      },
      browser: {
        cookiesEnabled: navigator.cookieEnabled,
        language: navigator.language,
        online: navigator.onLine,
        platform: navigator.platform,
        userAgent: navigator.userAgent
      }
    };

    // Filter out certain errors
    if (event.exception) {
      const error = hint.originalException;

      // Ignore non-critical errors
      if (error.message && error.message.includes("Non-critical")) {
        return null;
      }

      // Add custom tags
      event.tags = {
        ...event.tags,
        component: "frontend",
        userId: getCurrentUserId()
      };
    }

    return event;
  },

  // Debug mode for development
  debug: process.env.NODE_ENV === "development",

  // Enable user feedback dialog
  beforeSend(event, hint) {
    // Check if it's an exception
    if (event.exception) {
      event.event_id = Sentry.showReportDialog({
        eventId: event.event_id,
        title: "Something went wrong",
        subtitle: "Our team has been notified. If you'd like to help, tell us what happened below.",
        subtitle2: "If you prefer not to share this information, you can just close this dialog.",
        labelName: "Name",
        labelEmail: "Email",
        labelComments: "What happened?",
        labelClose: "Close",
        labelSubmit: "Submit",
        errorGeneric: "An unknown error occurred while submitting your report. Please try again.",
        errorFormEntry: "Some fields were invalid. Please correct the errors and try again.",
        successMessage: "Your feedback has been sent. Thank you!"
      });
    }
    return event;
  },

  // User context (will be updated dynamically)
  initialScope: {
    tags: {
      section: "main"
    },
    user: {
      id: "anonymous"
    }
  }
});

// Set user context dynamically
function setUserContext(user) {
  Sentry.setUser({
    id: user.id,
    email: user.email,
    username: user.username,
    ip_address: "{{auto}}"
  });
}

// Clear user context
function clearUserContext() {
  Sentry.setUser(null);
}

// Add custom tags
function addTags(tags) {
  Sentry.configureScope((scope) => {
    Object.entries(tags).forEach(([key, value]) => {
      scope.setTag(key, value);
    });
  });
}

// Add breadcrumbs for user actions
function trackUserAction(action, data = {}) {
  Sentry.addBreadcrumb({
    category: "user",
    message: action,
    level: "info",
    data: data
  });
}

// Manual error capture with context
function captureError(error, context = {}) {
  Sentry.withScope((scope) => {
    // Add context data
    Object.entries(context).forEach(([key, value]) => {
      scope.setContext(key, value);
    });

    // Add tags
    if (context.tags) {
      Object.entries(context.tags).forEach(([key, value]) => {
        scope.setTag(key, value);
      });
    }

    // Capture the error
    Sentry.captureException(error);
  });
}

// Performance monitoring
function startTransaction(name, operation = "navigation") {
  return Sentry.startTransaction({
    name: name,
    operation: operation,
  });
}

// Custom performance example
function performExpensiveOperation() {
  const transaction = Sentry.startTransaction({
    name: "expensive-operation",
    operation: "task"
  });

  try {
    // Step 1: Data processing
    const dataProcessingSpan = transaction.startChild({
      op: "processing",
      description: "Processing user data"
    });

    // Simulate data processing
    const processedData = processUserData(getUserData());
    dataProcessingSpan.finish();

    // Step 2: API call
    const apiCallSpan = transaction.startChild({
      op: "http.client",
      description: "API call to external service"
    });

    return fetch('/api/process', {
      method: 'POST',
      body: JSON.stringify(processedData)
    }).then(response => {
      apiCallSpan.setData("statusCode", response.status);
      apiCallSpan.finish();

      if (!response.ok) {
        throw new Error(`API call failed: ${response.status}`);
      }

      return response.json();
    });

  } catch (error) {
    Sentry.captureException(error);
    throw error;
  } finally {
    transaction.finish();
  }
}

// React Error Boundary component
import React from "react";

class ErrorBoundary extends React.Component {
  constructor(props) {
    super(props);
    this.state = { hasError: false };
  }

  static getDerivedStateFromError(error) {
    return { hasError: true };
  }

  componentDidCatch(error, errorInfo) {
    Sentry.withScope((scope) => {
      scope.setContext("react", {
        componentStack: errorInfo.componentStack
      });

      scope.setTag("react", "error-boundary");

      Sentry.captureException(error);
    });
  }

  render() {
    if (this.state.hasError) {
      return (
        <div>
          <h1>Something went wrong.</h1>
          <p>We've been notified about this issue.</p>
          <button onClick={() => this.setState({ hasError: false })}>
            Try again
          </button>
        </div>
      );
    }

    return this.props.children;
  }
}

// Backend Node.js Setup
// sentry-server.js
const Sentry = require("@sentry/node");
const { nodeprofilerIntegration } = require("@sentry/profiling-node");

// Initialize Sentry for Node.js
Sentry.init({
  dsn: "https://[email protected]/project-id",

  environment: process.env.NODE_ENV || "development",
  release: `my-api@${process.env.APP_VERSION || "1.0.0"}`,

  // Performance monitoring
  integrations: [
    // Add HTTP request tracking
    new Sentry.Integrations.Http({ tracing: true }),

    // Express.js integration
    new Sentry.Integrations.Express({ app }),

    // Profiling integration
    nodeprofilerIntegration()
  ],

  // Performance settings
  tracesSampleRate: 0.1, // Capture 10% of transactions

  // Profiling
  _experiments: {
    // The sampling rate for profiling is relative to tracesSampleRate
    profilesSampleRate: 0.1,
  },

  // Before send callback for server errors
  beforeSend(event, hint) {
    // Add server context
    event.contexts = {
      ...event.contexts,
      server: {
        name: process.env.HOSTNAME || "unknown",
        pid: process.pid,
        platform: process.platform,
        nodeVersion: process.version
      }
    };

    // Sanitize sensitive data
    if (event.request && event.request.headers) {
      // Remove sensitive headers
      delete event.request.headers.authorization;
      delete event.request.headers.cookie;
      delete event.request.headers["x-api-key"];
    }

    // Add user context if available in the request
    if (hint && hint.request && hint.request.user) {
      event.user = {
        id: hint.request.user.id,
        email: hint.request.user.email
      };
    }

    return event;
  },

  // Custom event processor
  eventProcessor(event) {
    // Filter out health check errors
    if (event.request && event.request.url && event.request.url.includes("/health")) {
      return null;
    }
    return event;
  }
});

// Express.js middleware setup
const express = require("express");
const app = express();

// Request handler
app.use(Sentry.Handlers.requestHandler());

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

// Example route with custom monitoring
app.get("/api/users/:id", async (req, res) => {
  try {
    // Add request context
    Sentry.configureScope((scope) => {
      scope.setTag("route", "/api/users/:id");
      scope.setTag("method", "GET");
      scope.setContext("request_params", {
        userId: req.params.id,
        query: req.query
      });
    });

    // Add breadcrumb
    Sentry.addBreadcrumb({
      category: "http",
      message: `Fetching user ${req.params.id}`,
      level: "info"
    });

    const user = await database.findUserById(req.params.id);

    if (!user) {
      Sentry.captureMessage(`User ${req.params.id} not found`, "warning");
      return res.status(404).json({ error: "User not found" });
    }

    // Set user context
    Sentry.setUser({ id: user.id, email: user.email });

    res.json({ user });

  } catch (error) {
    // Capture error with additional context
    Sentry.withScope((scope) => {
      scope.setContext("database_error", {
        operation: "findUserById",
        userId: req.params.id,
        error_code: error.code
      });

      Sentry.captureException(error);
    });

    res.status(500).json({ error: "Internal server error" });
  }
});

// Error handler
app.use(Sentry.Handlers.errorHandler());

// Fallback error handler
app.use(function onError(err, req, res, next) {
  res.statusCode = 500;
  res.end(res.sentry + "\n");
});

const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
  console.log(`Server running on port ${PORT}`);

  // Record deployment
  Sentry.captureMessage("Application started", "info");
});

💻 Sentry Python SDK Integration python

🟡 intermediate ⭐⭐⭐

Complete Python SDK setup for Django, Flask, and FastAPI applications with error tracking and performance monitoring

⏱️ 35 min 🏷️ sentry, python, django, flask, fastapi, monitoring
Prerequisites: Python, Django/Flask/FastAPI, pip, Sentry account
# Sentry Python SDK Configuration
# Install: pip install sentry-sdk[django,flask,fastapi]

import sentry_sdk
from sentry_sdk.integrations.django import DjangoIntegration
from sentry_sdk.integrations.flask import FlaskIntegration
from sentry_sdk.integrations.fastapi import FastApiIntegration
from sentry_sdk.integrations.sqlalchemy import SqlalchemyIntegration
from sentry_sdk.integrations.celery import CeleryIntegration
from sentry_sdk.integrations.redis import RedisIntegration
import logging

# Common configuration
SENTRY_DSN = "https://[email protected]/project-id"
ENVIRONMENT = "production"
RELEASE = "[email protected]"

# Configure sentry_sdk with common settings
def configure_sentry(integrations=None):
    """Configure Sentry SDK with common settings"""

    # Default integrations
    default_integrations = [
        SqlalchemyIntegration(),
        RedisIntegration(),
    ]

    if integrations:
        default_integrations.extend(integrations)

    sentry_sdk.init(
        dsn=SENTRY_DSN,
        environment=ENVIRONMENT,
        release=RELEASE,

        # Performance monitoring
        traces_sample_rate=0.1,

        # Error monitoring
        sample_rate=1.0,

        # Integrations
        integrations=default_integrations,

        # Before send callback for error filtering
        before_send=before_send_filter,

        # Before breadcrumb callback
        before_breadcrumb=before_breadcrumb_filter,

        # Ignore specific exceptions
        ignore_errors=[
            KeyboardInterrupt,
            SystemExit,
            "django.http.request.DisallowedHost",
        ],

        # Server name
        server_name=get_server_name(),

        # Max breadcrumbs
        max_breadcrumbs=100,

        # Attach stack traces
        attach_stacktrace=True,
    )

def before_send_filter(event, hint):
    """Filter and enhance error events"""

    # Add custom context
    event["contexts"] = {
        **event.get("contexts", {}),
        "app": {
            "version": RELEASE,
            "environment": ENVIRONMENT,
            "process_id": os.getpid(),
        },
        "system": {
            "platform": sys.platform,
            "python_version": sys.version,
        }
    }

    # Add user context if available
    if hasattr(g, 'user') and g.user:
        event["user"] = {
            "id": g.user.id,
            "email": g.user.email,
            "username": g.user.username,
        }

    # Sanitize sensitive data
    if "request" in event:
        sanitize_request_data(event["request"])

    # Filter out health checks
    if event.get("request", {}).get("url", "").endswith("/health/"):
        return None

    return event

def before_breadcrumb_filter(breadcrumb, hint):
    """Filter breadcrumb data"""

    # Sanitize breadcrumb data
    if breadcrumb.get("category") == "http":
        data = breadcrumb.get("data", {})
        if "url" in data:
            # Remove query parameters from URLs
            data["url"] = data["url"].split("?")[0]

    return breadcrumb

def sanitize_request_data(request):
    """Remove sensitive data from request"""
    sensitive_headers = ["authorization", "cookie", "x-api-key"]
    sensitive_params = ["password", "token", "secret", "key"]

    # Remove sensitive headers
    if "headers" in request:
        for header in sensitive_headers:
            request["headers"].pop(header, None)

    # Remove sensitive query parameters
    if "query_string" in request:
        query_string = request["query_string"]
        for param in sensitive_params:
            query_string = re.sub(f"{param}=[^&]*", f"{param}=[FILTERED]", query_string, flags=re.IGNORECASE)
        request["query_string"] = query_string

# Django Integration
# sentry_django.py
from django.conf import settings

# Configure Sentry for Django
configure_sentry([
    DjangoIntegration(
        transaction_style="url",
        middleware_spans=True,
        signals_spans=True,
    ),
    CeleryIntegration(
        monitor_beat_tasks=True,
        propagate_traces=True,
    ),
])

# Custom middleware for additional context
class SentryContextMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        # Add request context
        with sentry_sdk.configure_scope() as scope:
            scope.set_tag("request_id", get_request_id(request))
            scope.set_context("request", {
                "method": request.method,
                "path": request.path,
                "user_agent": request.META.get("HTTP_USER_AGENT"),
                "remote_addr": request.META.get("REMOTE_ADDR"),
            })

            # Add user context if authenticated
            if hasattr(request, 'user') and request.user.is_authenticated:
                scope.set_user({
                    "id": request.user.id,
                    "email": request.user.email,
                    "username": request.user.username,
                })

            # Add additional business context
            if hasattr(request, 'organization'):
                scope.set_tag("organization", request.organization.id)
                scope.set_context("organization", {
                    "id": request.organization.id,
                    "name": request.organization.name,
                })

        response = self.get_response(request)
        return response

# Add to Django MIDDLEWARE
MIDDLEWARE = [
    "path.to.SentryContextMiddleware",
    # ... other middleware
]

# Django views with custom Sentry usage
from django.http import JsonResponse
from django.views.decorators.http import require_http_methods
import sentry_sdk

@require_http_methods(["GET"])
def user_profile(request, user_id):
    """User profile view with Sentry instrumentation"""

    # Add custom breadcrumb
    sentry_sdk.add_breadcrumb(
        category="auth",
        message=f"Accessing user profile: {user_id}",
        level="info",
        data={"user_id": user_id}
    )

    try:
        # Custom transaction for profile loading
        with sentry_sdk.start_transaction(
            name="user_profile_load",
            op="view",
            data={"user_id": user_id}
        ):

            # Database operation
            with sentry_sdk.start_span(op="db", description="Fetch user from database"):
                user = User.objects.get(id=user_id)

            # Additional data fetching
            with sentry_sdk.start_span(op="db", description="Fetch user profile data"):
                profile = UserProfile.objects.get(user=user)

            # Add context
            with sentry_sdk.configure_scope() as scope:
                scope.set_context("user_profile", {
                    "user_id": user.id,
                    "profile_complete": profile.is_complete,
                    "last_login": user.last_login,
                })
                scope.set_tag("user_type", user.user_type)

            return JsonResponse({
                "user": {
                    "id": user.id,
                    "name": user.get_full_name(),
                    "email": user.email,
                    "profile": profile.to_dict()
                }
            })

    except User.DoesNotExist:
        # Capture warning for missing user
        sentry_sdk.capture_message(
            f"User {user_id} not found",
            level="warning",
            tags={"endpoint": "user_profile", "action": "not_found"}
        )
        return JsonResponse({"error": "User not found"}, status=404)

    except Exception as e:
        # Capture exception with context
        sentry_sdk.capture_exception(e)
        with sentry_sdk.configure_scope() as scope:
            scope.set_context("error_details", {
                "user_id": user_id,
                "endpoint": "user_profile",
                "error_type": type(e).__name__,
            })
        return JsonResponse({"error": "Internal server error"}, status=500)

# Flask Integration
# sentry_flask.py
from flask import Flask, request, g
import sentry_sdk

# Configure Sentry for Flask
configure_sentry([
    FlaskIntegration(
        transaction_style="url",
    ),
])

app = Flask(__name__)

@app.before_request
def add_request_context():
    """Add request context to Sentry"""
    with sentry_sdk.configure_scope() as scope:
        scope.set_tag("request_id", generate_request_id())
        scope.set_context("request", {
            "method": request.method,
            "path": request.path,
            "user_agent": request.headers.get("User-Agent"),
            "remote_addr": request.remote_addr,
        })

@app.route("/api/orders", methods=["GET", "POST"])
def handle_orders():
    """Order handling with Sentry instrumentation"""

    if request.method == "GET":
        return get_orders()
    else:
        return create_order()

def get_orders():
    """Get orders with custom monitoring"""

    # Add breadcrumb
    sentry_sdk.add_breadcrumb(
        category="orders",
        message="Fetching orders",
        level="info"
    )

    try:
        # Custom transaction
        with sentry_sdk.start_transaction(name="order_retrieval", op="http.server"):

            # Database operation
            with sentry_sdk.start_span(op="db.query", description="Fetch orders"):
                orders = Order.query.filter_by(user_id=g.user.id).all()

            # Add metrics
            with sentry_sdk.configure_scope() as scope:
                scope.set_tag("order_count", len(orders))
                scope.set_metric("orders_retrieved", len(orders))

            return jsonify({
                "orders": [order.to_dict() for order in orders]
            })

    except DatabaseError as e:
        # Capture with specific context
        sentry_sdk.capture_exception(e)
        with sentry_sdk.configure_scope() as scope:
            scope.set_context("database_error", {
                "query_type": "SELECT",
                "table": "orders",
                "user_id": getattr(g, 'user', {}).get('id'),
            })
        raise

def create_order():
    """Create order with monitoring"""

    order_data = request.get_json()

    # Validate input
    if not order_data or "items" not in order_data:
        sentry_sdk.capture_message(
            "Invalid order data received",
            level="warning",
            extra={"data": order_data}
        )
        return jsonify({"error": "Invalid order data"}), 400

    try:
        with sentry_sdk.start_transaction(name="order_creation", op="business") as transaction:

            # Add order context
            transaction.set_data("order_value", calculate_order_value(order_data))
            transaction.set_tag("payment_method", order_data.get("payment_method"))

            # Create order
            with sentry_sdk.start_span(op="db.insert", description="Create order"):
                order = Order.create(order_data)

            # Process payment
            with sentry_sdk.start_span(op="external", description="Process payment"):
                payment_result = process_payment(order)

            # Record custom event
            sentry_sdk.capture_message(
                f"Order created successfully: {order.id}",
                level="info",
                tags={
                    "order_id": order.id,
                    "user_id": order.user_id,
                    "payment_method": order_data.get("payment_method")
                }
            )

            return jsonify({
                "order_id": order.id,
                "status": "created"
            }), 201

    except PaymentError as e:
        # Capture payment error
        sentry_sdk.capture_exception(e)
        with sentry_sdk.configure_scope() as scope:
            scope.set_context("payment_error", {
                "order_data": sanitize_order_data(order_data),
                "error_code": e.code,
                "gateway": e.gateway,
            })
        return jsonify({"error": "Payment failed"}), 400

# FastAPI Integration
# sentry_fastapi.py
from fastapi import FastAPI, Request, Depends
import sentry_sdk

# Configure Sentry for FastAPI
configure_sentry([
    FastApiIntegration(
        transaction_style="url",
    ),
])

app = FastAPI()

@app.middleware("http")
async def add_sentry_context(request: Request, call_next):
    """Add request context to Sentry"""
    with sentry_sdk.configure_scope() as scope:
        scope.set_tag("request_id", generate_request_id())
        scope.set_context("request", {
            "method": request.method,
            "path": request.url.path,
            "user_agent": request.headers.get("user-agent"),
            "client_ip": request.client.host if request.client else None,
        })

    response = await call_next(request)
    return response

# Celery Integration
# sentry_celery.py
from celery import Celery
import sentry_sdk

celery_app = Celery('tasks')

@celery_app.task
def send_email_notification(user_id, message_data):
    """Send email notification with Sentry monitoring"""

    with sentry_sdk.start_transaction(name="send_email_notification", op="task"):

        try:
            # Add context
            with sentry_sdk.configure_scope() as scope:
                scope.set_tag("task", "email_notification")
                scope.set_tag("user_id", user_id)
                scope.set_tag("message_type", message_data.get("type"))

            # Fetch user data
            with sentry_sdk.start_span(op="db.query", description="Fetch user"):
                user = User.objects.get(id=user_id)

            # Send email
            with sentry_sdk.start_span(op="external", description="Send email"):
                result = email_service.send(user.email, message_data)

            # Record success
            sentry_sdk.add_breadcrumb(
                category="celery",
                message=f"Email sent successfully to {user.email}",
                level="info"
            )

            return {"status": "success", "email": user.email}

        except Exception as e:
            # Capture error with task context
            sentry_sdk.capture_exception(e)
            with sentry_sdk.configure_scope() as scope:
                scope.set_context("celery_task", {
                    "task_name": "send_email_notification",
                    "user_id": user_id,
                    "message_type": message_data.get("type"),
                    "retry_count": send_email_notification.request.retries,
                })
            raise

# Custom performance monitoring
def monitor_slow_operation(operation_name, func, *args, **kwargs):
    """Monitor slow operations with Sentry"""

    with sentry_sdk.start_transaction(name=operation_name, op="custom") as transaction:
        try:
            result = func(*args, **kwargs)

            # Record operation metrics
            duration = transaction.finish_timestamp - transaction.start_timestamp
            with sentry_sdk.configure_scope() as scope:
                scope.set_metric(f"{operation_name}_duration", duration)

            return result

        except Exception as e:
            # Capture with operation context
            sentry_sdk.capture_exception(e)
            with sentry_sdk.configure_scope() as scope:
                scope.set_context("operation", {
                    "name": operation_name,
                    "args_count": len(args),
                    "kwargs": list(kwargs.keys()),
                })
            raise

# Usage example
def process_large_dataset(dataset):
    """Example function with custom monitoring"""

    def _process_data(data):
        # Actual processing logic
        return [item.upper() for item in data]

    return monitor_slow_operation("data_processing", _process_data, dataset)

💻 Sentry Performance Monitoring javascript

🔴 complex ⭐⭐⭐⭐

Advanced performance monitoring with custom transactions, spans, and metrics for deep application insights

⏱️ 50 min 🏷️ sentry, performance, tracing, monitoring, profiling
Prerequisites: JavaScript, Sentry SDK, Performance concepts
// Sentry Performance Monitoring Advanced Setup
// Install: npm install @sentry/tracing @sentry/browser

import * as Sentry from "@sentry/browser";
import { BrowserTracing } from "@sentry/tracing";

// Enhanced performance configuration
Sentry.init({
  dsn: "https://[email protected]/project-id",

  // Environment and release
  environment: process.env.NODE_ENV,
  release: `my-app@${process.env.APP_VERSION}`,

  // Performance integrations
  integrations: [
    new BrowserTracing({
      // Custom routing instrumentation
      routingInstrumentation: (customRoutingInstrumentation) => ({
        // Custom implementation
        registerNavigationInstrumentation: () => {
          // Track route changes
          history.listen(({ location }) => {
            const name = location.pathname + location.search;
            Sentry.startTransaction({
              name: name,
              op: "navigation"
            }).finish();
          });
        }
      }),

      // Enable user interaction tracing
      userInteractionTracing: {
        enabled: true,
        eventTargets: [document.body],
        keypressThresholdMs: 1000,
        scrollTimeoutMs: 100
      },

      // Enable long task tracking
      enableLongTask: true,

      // Enable first paint/first contentful paint
      enableFirstPaint: true
    })
  ],

  // Performance sampling
  tracesSampleRate: calculateSampleRate(),

  // Custom transaction context
  initialScope: {
    tags: {
      section: "main",
      platform: "web"
    }
  }
});

// Dynamic sampling rate based on user
function calculateSampleRate() {
  const user = getCurrentUser();
  if (!user) return 0.1; // 10% for anonymous users

  // Higher sampling for paid users
  if (user.subscription === "premium") return 0.5; // 50%
  if (user.subscription === "pro") return 0.2; // 20%

  return 0.05; // 5% for free users
}

// Custom transaction wrapper
class PerformanceTracker {
  constructor(name, operation = "custom") {
    this.transaction = Sentry.startTransaction({
      name: name,
      operation: operation,
      data: {
        page_url: window.location.href,
        user_agent: navigator.userAgent,
        timestamp: Date.now()
      }
    });

    this.spans = new Map();
  }

  // Start a new span
  startSpan(name, operation = "custom", data = {}) {
    const span = this.transaction.startChild({
      op: operation,
      description: name,
      data: data
    });

    this.spans.set(name, span);
    return span;
  }

  // Finish a specific span
  finishSpan(name) {
    const span = this.spans.get(name);
    if (span) {
      span.finish();
      this.spans.delete(name);
      return true;
    }
    return false;
  }

  // Add data to transaction
  setData(key, value) {
    this.transaction.setData(key, value);
  }

  // Add tag to transaction
  setTag(key, value) {
    this.transaction.setTag(key, value);
  }

  // Finish the transaction
  finish() {
    // Finish any remaining spans
    this.spans.forEach(span => span.finish());

    // Add final metrics
    this.transaction.setData("total_duration",
      Date.now() - this.transaction.startTimestamp);

    this.transaction.finish();
  }
}

// Example usage: API request monitoring
class APIMonitor {
  constructor(baseURL) {
    this.baseURL = baseURL;
  }

  async request(method, endpoint, options = {}) {
    const tracker = new PerformanceTracker(
      `api-${method.toLowerCase()}-${endpoint}`,
      "http.client"
    );

    try {
      // Add request details
      tracker.setData("request_method", method);
      tracker.setData("request_endpoint", endpoint);
      tracker.setTag("api_endpoint", endpoint);
      tracker.setTag("http_method", method);

      // Network span
      const networkSpan = tracker.startSpan("network-request", "http.client", {
        url: `${this.baseURL}${endpoint}`,
        method: method
      });

      const response = await fetch(`${this.baseURL}${endpoint}`, {
        method: method,
        ...options
      });

      networkSpan.finish();

      // Response processing span
      const processingSpan = tracker.startSpan("response-processing", "http.client");

      let data;
      if (response.ok) {
        data = await response.json();
      } else {
        throw new Error(`HTTP ${response.status}: ${response.statusText}`);
      }

      processingSpan.finish();

      // Add response details
      tracker.setData("response_status", response.status);
      tracker.setData("response_size", JSON.stringify(data).length);
      tracker.setTag("http_status_code", response.status.toString());

      // Track specific business metrics
      if (endpoint.includes("/orders")) {
        tracker.setData("order_count", Array.isArray(data) ? data.length : 1);
        tracker.setTag("has_orders", true);
      }

      tracker.finish();

      return data;

    } catch (error) {
      // Add error context
      tracker.setData("error_type", error.name);
      tracker.setData("error_message", error.message);
      tracker.setTag("error", true);

      // Capture error in Sentry
      Sentry.withScope((scope) => {
        scope.setContext("api_error", {
          method: method,
          endpoint: endpoint,
          error: error.message
        });
        Sentry.captureException(error);
      });

      tracker.finish();
      throw error;
    }
  }
}

// Component performance monitoring
class ComponentMonitor {
  static wrap(componentName, renderFunction) {
    return function(...args) {
      const tracker = new PerformanceTracker(
        `component-${componentName}`,
        "react.render"
      );

      try {
        // Add component context
        tracker.setTag("component_name", componentName);
        tracker.setData("props_count", args[0] ? Object.keys(args[0]).length : 0);

        // Render span
        const renderSpan = tracker.startSpan("component-render", "react.render");
        const result = renderFunction.apply(this, args);
        renderSpan.finish();

        // Post-render span (effects, etc.)
        const postRenderSpan = tracker.startSpan("component-post-render", "react.effect");

        // Use requestAnimationFrame to capture post-render work
        requestAnimationFrame(() => {
          postRenderSpan.finish();
          tracker.finish();
        });

        return result;

      } catch (error) {
        tracker.setData("render_error", error.message);
        tracker.setTag("render_error", true);
        tracker.finish();
        throw error;
      }
    };
  }
}

// User interaction monitoring
class InteractionMonitor {
  static init() {
    // Click monitoring
    document.addEventListener("click", (event) => {
      const element = event.target.closest("[data-track]");
      if (element) {
        this.trackClick(element, event);
      }
    });

    // Form submission monitoring
    document.addEventListener("submit", (event) => {
      if (event.target.tagName === "FORM") {
        this.trackFormSubmission(event.target);
      }
    });

    // Scroll monitoring (debounced)
    let scrollTimeout;
    window.addEventListener("scroll", () => {
      clearTimeout(scrollTimeout);
      scrollTimeout = setTimeout(() => {
        this.trackScrollDepth();
      }, 100);
    });
  }

  static trackClick(element, event) {
    const tracker = new PerformanceTracker("user-click", "ui.click");

    tracker.setTag("click_target", element.tagName.toLowerCase());
    tracker.setTag("click_id", element.id || "");
    tracker.setTag("click_class", element.className || "");
    tracker.setData("click_x", event.clientX);
    tracker.setData("click_y", event.clientY);

    // Track specific interactions
    if (element.matches("[data-track-cta]")) {
      tracker.setTag("cta_click", true);
      tracker.setData("cta_text", element.textContent.trim());
    }

    if (element.matches("[data-track-feature]")) {
      const feature = element.dataset.trackFeature;
      tracker.setTag("feature_interaction", true);
      tracker.setData("feature_name", feature);

      // Record custom event
      Sentry.addBreadcrumb({
        category: "ui.interaction",
        message: `Feature used: ${feature}`,
        level: "info",
        data: {
          feature: feature,
          element: element.tagName.toLowerCase()
        }
      });
    }

    tracker.finish();
  }

  static trackFormSubmission(form) {
    const tracker = new PerformanceTracker("form-submission", "ui.submit");

    tracker.setTag("form_id", form.id || "");
    tracker.setTag("form_class", form.className || "");
    tracker.setData("field_count", form.elements.length);

    // Track form type
    if (form.matches(".login-form")) {
      tracker.setTag("form_type", "login");
    } else if (form.matches(".signup-form")) {
      tracker.setTag("form_type", "signup");
    } else if (form.matches(".contact-form")) {
      tracker.setTag("form_type", "contact");
    }

    // Add breadcrumb
    Sentry.addBreadcrumb({
      category: "ui.interaction",
      message: `Form submitted: ${tracker.getTransaction().tags.form_type || 'unknown'}`,
      level: "info"
    });

    tracker.finish();
  }

  static trackScrollDepth() {
    const scrollPercentage = Math.round(
      (window.scrollY / (document.body.scrollHeight - window.innerHeight)) * 100
    );

    // Record significant scroll milestones
    const milestones = [25, 50, 75, 90];

    milestones.forEach(milestone => {
      if (scrollPercentage >= milestone && !this.scrollMilestones?.[milestone]) {
        this.scrollMilestones = this.scrollMilestones || {};
        this.scrollMilestones[milestone] = true;

        Sentry.addBreadcrumb({
          category: "ui.interaction",
          message: `Scroll depth reached: ${milestone}%`,
          level: "info"
        });

        // Record custom metric
        Sentry.metrics.increment(
          "ui.scroll_depth_reached",
          1,
          { tags: { milestone: milestone.toString() } }
        );
      }
    });
  }
}

// Resource loading monitoring
class ResourceMonitor {
  static init() {
    // Monitor critical resources
    this.observeCriticalResources();

    // Monitor API endpoints
    this.monitorAPIPerformance();
  }

  static observeCriticalResources() {
    const observer = new PerformanceObserver((list) => {
      const entries = list.getEntries();

      entries.forEach(entry => {
        if (entry.entryType === "resource") {
          this.trackResourceLoading(entry);
        }
      });
    });

    observer.observe({ entryTypes: ["resource"] });
  }

  static trackResourceLoading(entry) {
    // Only track certain resource types
    const trackableTypes = ["script", "link", "img", "fetch", "xmlhttprequest"];
    if (!trackableTypes.includes(entry.initiatorType)) return;

    const tracker = new PerformanceTracker(
      `resource-${entry.initiatorType}`,
      "resource"
    );

    tracker.setTag("resource_type", entry.initiatorType);
    tracker.setTag("resource_name", this.getResourceName(entry.name));
    tracker.setData("resource_size", entry.transferSize || 0);
    tracker.setData("load_time", entry.duration);

    // Flag slow resources
    if (entry.duration > 1000) { // 1 second threshold
      tracker.setTag("slow_resource", true);

      Sentry.captureMessage(
        `Slow resource detected: ${entry.name} (${entry.duration}ms)`,
        "warning"
      );
    }

    // Flag failed resources
    if (entry.transferSize === 0 && entry.duration > 0) {
      tracker.setTag("resource_failed", true);
      Sentry.captureMessage(
        `Resource failed to load: ${entry.name}`,
        "error"
      );
    }

    tracker.finish();
  }

  static getResourceName(url) {
    try {
      const urlObj = new URL(url);
      return urlObj.pathname.split('/').pop() || urlObj.pathname;
    } catch {
      return url;
    }
  }

  static monitorAPIPerformance() {
    // Track API performance metrics
    setInterval(() => {
      const apiCalls = Sentry.metrics.distribution(
        "api.request_duration",
        this.getRecentAPICallDurations(),
        { unit: "millisecond" }
      );

      const apiErrors = Sentry.metrics.increment(
        "api.error_count",
        this.getRecentAPIErrorCount(),
        { tags: { status: "error" } }
      );
    }, 30000); // Every 30 seconds
  }

  static getRecentAPICallDurations() {
    // Implementation to collect recent API call durations
    return this.apiCallDurations || [];
  }

  static getRecentAPIErrorCount() {
    // Implementation to count recent API errors
    return this.apiErrorCount || 0;
  }
}

// Initialize all monitoring
function initPerformanceMonitoring() {
  // Start interaction monitoring
  InteractionMonitor.init();

  // Start resource monitoring
  ResourceMonitor.init();

  // Record page load metrics
  window.addEventListener("load", () => {
    setTimeout(() => {
      const perfData = performance.getEntriesByType("navigation")[0];

      Sentry.addBreadcrumb({
        category: "performance",
        message: "Page load completed",
        level: "info",
        data: {
          dom_content_loaded: perfData.domContentLoadedEventEnd - perfData.domContentLoadedEventStart,
          load_complete: perfData.loadEventEnd - perfData.loadEventStart,
          first_paint: getFirstPaintTime(),
          first_contentful_paint: getFirstContentfulPaintTime()
        }
      });
    }, 0);
  });
}

// Utility functions
function getFirstPaintTime() {
  const paintEntries = performance.getEntriesByType("paint");
  const firstPaint = paintEntries.find(entry => entry.name === "first-paint");
  return firstPaint ? Math.round(firstPaint.startTime) : 0;
}

function getFirstContentfulPaintTime() {
  const paintEntries = performance.getEntriesByType("paint");
  const fcp = paintEntries.find(entry => entry.name === "first-contentful-paint");
  return fcp ? Math.round(fcp.startTime) : 0;
}

// Export monitoring classes
export {
  PerformanceTracker,
  APIMonitor,
  ComponentMonitor,
  InteractionMonitor,
  ResourceMonitor,
  initPerformanceMonitoring
};

💻 Sentry Custom Alerts and Rules json

🔴 complex ⭐⭐⭐⭐⭐

Configure advanced alerting rules, notification integrations, and automated workflows for proactive error management

⏱️ 60 min 🏷️ sentry, alerts, monitoring, notifications, automation
Prerequisites: Sentry account, Alerting concepts, Webhook knowledge
{
  "alert_rules": [
    {
      "name": "Critical Error Spike",
      "description": "Alert when critical errors increase significantly",
      "conditions": [
        {
          "id": "error_rate_spike",
          "interval": "5m",
          "aggregation": "count()",
          "field": "level",
          "operator": "gt",
          "value": 10,
          "filters": [
            {
              "field": "level",
              "value": "error",
              "match": "exact"
            },
            {
              "field": "environment",
              "value": "production",
              "match": "exact"
            }
          ]
        }
      ],
      "actions": [
        {
          "type": "email",
          "recipients": ["[email protected]", "[email protected]"],
          "template": "critical_error_spike"
        },
        {
          "type": "slack",
          "channel": "#alerts-critical",
          "template": "error_notification",
          "mention_users": ["@devops", "@tech-lead"]
        },
        {
          "type": "pagerduty",
          "service_key": "your-pagerduty-key",
          "severity": "critical"
        },
        {
          "type": "jira",
          "project": "BUG",
          "issue_type": "Bug",
          "priority": "Highest",
          "assignee": "devops-team"
        }
      ],
      "thresholds": {
        "critical": 50,
        "warning": 20
      },
      "cooldown": "30m",
      "enabled": true,
      "tags": ["production", "critical", "error-spike"]
    },
    {
      "name": "Performance Degradation",
      "description": "Alert when application performance drops below threshold",
      "conditions": [
        {
          "id": "slow_transactions",
          "interval": "10m",
          "aggregation": "p95(transaction.duration)",
          "operator": "gt",
          "value": 2000,
          "filters": [
            {
              "field": "transaction.op",
              "value": "http.server",
              "match": "exact"
            },
            {
              "field": "environment",
              "value": "production",
              "match": "exact"
            }
          ]
        }
      ],
      "actions": [
        {
          "type": "slack",
          "channel": "#performance-alerts",
          "template": "performance_degradation"
        },
        {
          "type": "email",
          "recipients": ["[email protected]"],
          "template": "performance_alert"
        }
      ],
      "thresholds": {
        "critical": 3000,
        "warning": 2000
      },
      "cooldown": "15m",
      "enabled": true,
      "tags": ["performance", "production"]
    },
    {
      "name": "New Error Introduction",
      "description": "Alert when new error types are detected",
      "conditions": [
        {
          "id": "new_error_type",
          "interval": "1h",
          "aggregation": "count_distinct(exception.type)",
          "operator": "gt",
          "value": 1,
          "filters": [
            {
              "field": "first_seen",
              "value": ">= 1h",
              "match": "age"
            },
            {
              "field": "environment",
              "value": "production",
              "match": "exact"
            }
          ]
        }
      ],
      "actions": [
        {
          "type": "slack",
          "channel": "#development",
          "template": "new_error_alert"
        },
        {
          "type": "github",
          "repository": "company/app",
          "issue_title": "New Error Detected: {{error.type}}",
          "issue_body": "New error type detected in production:\n\n{{error.message}}\n\nStack trace:\n{{error.stacktrace}}",
          "assignees": ["development-team"]
        }
      ],
      "cooldown": "1h",
      "enabled": true,
      "tags": ["new-error", "production"]
    },
    {
      "name": "Database Connection Issues",
      "description": "Alert on database-related errors",
      "conditions": [
        {
          "id": "database_errors",
          "interval": "5m",
          "aggregation": "count()",
          "operator": "gt",
          "value": 5,
          "filters": [
            {
              "field": "exception.type",
              "value": ["DatabaseError", "ConnectionError", "TimeoutError"],
              "match": "contains"
            }
          ]
        }
      ],
      "actions": [
        {
          "type": "pagerduty",
          "service_key": "database-pagerduty-key",
          "severity": "high"
        },
        {
          "type": "email",
          "recipients": ["[email protected]", "[email protected]"],
          "template": "database_alert"
        }
      ],
      "thresholds": {
        "critical": 20,
        "warning": 5
      },
      "cooldown": "10m",
      "enabled": true,
      "tags": ["database", "infrastructure"]
    },
    {
      "name": "User Experience Issues",
      "description": "Alert on user-facing problems",
      "conditions": [
        {
          "id": "ux_errors",
          "interval": "10m",
          "aggregation": "count()",
          "operator": "gt",
          "value": 10,
          "filters": [
            {
              "field": "tags.ux_issue",
              "value": "true",
              "match": "exact"
            },
            {
              "field": "user.id",
              "value": "null",
              "match": "not"
            }
          ]
        }
      ],
      "actions": [
        {
          "type": "slack",
          "channel": "#product-alerts",
          "template": "ux_issue"
        },
        {
          "type": "linear",
          "team_id": "product-team-id",
          "priority": "medium"
        }
      ],
      "cooldown": "20m",
      "enabled": true,
      "tags": ["user-experience", "customer-facing"]
    },
    {
      "name": "Third-party Service Failures",
      "description": "Alert on external service failures",
      "conditions": [
        {
          "id": "external_service_errors",
          "interval": "5m",
          "aggregation": "count()",
          "operator": "gt",
          "value": 3,
          "filters": [
            {
              "field": "transaction.op",
              "value": "http.client",
              "match": "exact"
            },
            {
              "field": "http.response_code",
              "value": ">= 500",
              "match": "range"
            }
          ]
        }
      ],
      "actions": [
        {
          "type": "email",
          "recipients": ["[email protected]"],
          "template": "external_service_failure"
        },
        {
          "type": "statuspage",
          "component_id": "external-api",
          "status": "degraded_performance"
        }
      ],
      "cooldown": "15m",
      "enabled": true,
      "tags": ["external-services", "integrations"]
    }
  ],
  "notification_templates": {
    "critical_error_spike": {
      "subject": "🚨 Critical Error Spike Detected - {{error_count}} errors in last {{interval}}",
      "body": `<h2>Critical Error Spike Alert</h2>
        <p><strong>{{error_count}}</strong> critical errors detected in the last {{interval}}</p>

        <h3>Error Details:</h3>
        <ul>
          <li><strong>Environment:</strong> {{environment}}</li>
          <li><strong>Time Period:</strong> {{interval}}</li>
          <li><strong>Error Rate:</strong> {{error_rate}} errors/minute</li>
          <li><strong>Top Error:</strong> {{top_error.type}} - {{top_error.message}}</li>
        </ul>

        <h3>Recent Errors:</h3>
        <table border="1" style="border-collapse: collapse;">
          <tr>
            <th>Time</th>
            <th>Error Type</th>
            <th>Message</th>
            <th>User Impact</th>
          </tr>
          {{#each recent_errors}}
          <tr>
            <td>{{timestamp}}</td>
            <td>{{exception.type}}</td>
            <td>{{exception.message}}</td>
            <td>{{user_impact}}</td>
          </tr>
          {{/each}}
        </table>

        <h3>Actions Required:</h3>
        <ol>
          <li>Check Sentry dashboard: {{sentry_url}}</li>
          <li>Review recent deployments</li>
          <li>Check infrastructure health</li>
          <li>Communicate status to stakeholders</li>
        </ol>

        <p><a href="{{sentry_url}}">View in Sentry</a></p>`
    },
    "performance_degradation": {
      "subject": "⚠️ Performance Degradation Detected - P95: {{p95_duration}}ms",
      "body": `<h2>Performance Degradation Alert</h2>

        <h3>Performance Metrics:</h3>
        <ul>
          <li><strong>P95 Response Time:</strong> {{p95_duration}}ms (threshold: {{threshold}}ms)</li>
          <li><strong>P50 Response Time:</strong> {{p50_duration}}ms</li>
          <li><strong>Slowest Transaction:</strong> {{slowest_transaction.name}} ({{slowest_transaction.duration}}ms)</li>
        </ul>

        <h3>Affected Endpoints:</h3>
        <table>
          <tr><th>Endpoint</th><th>P95 Time</th><th>Error Rate</th></tr>
          {{#each slow_endpoints}}
          <tr>
            <td>{{transaction.name}}</td>
            <td>{{duration}}ms</td>
            <td>{{error_rate}}%</td>
          </tr>
          {{/each}}
        </table>

        <h3>Next Steps:</h3>
        <ol>
          <li>Review database query performance</li>
          <li>Check external service response times</li>
          <li>Analyze recent code changes</li>
          <li>Consider scaling resources if needed</li>
        </ol>`
    },
    "new_error_alert": {
      "subject": "🆕 New Error Type Detected: {{error.type}}",
      "body": `<h2>New Error Type Alert</h2>

        <p>A new error type has been detected in production:</p>

        <ul>
          <li><strong>Error Type:</strong> {{exception.type}}</li>
          <li><strong>Message:</strong> {{exception.message}}</li>
          <li><strong>First Seen:</strong> {{first_seen}}</li>
          <li><strong>Affected Users:</strong> {{affected_users}}</li>
          <li><strong>Environment:</strong> {{environment}}</li>
        </ul>

        <h3>Stack Trace Preview:</h3>
        <pre>{{exception.stacktrace | truncate: 500}}</pre>

        <h3>Investigation Steps:</h3>
        <ol>
          <li>Review recent deployments that might have introduced this error</li>
          <li>Check if this error affects critical user flows</li>
          <li>Determine if immediate action is required</li>
          <li>Create bug ticket if needed</li>
        </ol>

        <p><a href="{{sentry_url}}">View Error Details</a></p>`
    },
    "ux_issue": {
      "subject": "😟 User Experience Issue - {{issue_count}} reports",
      "body": `<h2>User Experience Issue Alert</h2>

        <p><strong>{{issue_count}}</strong> user experience issues have been reported in the last {{interval}}.</p>

        <h3>Issue Summary:</h3>
        <ul>
          <li><strong>Total Affected Users:</strong> {{affected_users}}</li>
          <li><strong>Most Common Issue:</strong> {{common_issue}}</li>
          <li><strong>User Feedback Score:</strong> {{ux_score}}/10</li>
        </ul>

        <h3>Recent User Reports:</h3>
        {{#each user_reports}}
        <div style="margin-bottom: 20px; padding: 10px; border: 1px solid #ccc;">
          <p><strong>User:</strong> {{user.email}} (ID: {{user.id}})</p>
          <p><strong>Issue:</strong> {{message}}</p>
          <p><strong>Context:</strong> {{context}}</p>
          <p><strong>Time:</strong> {{timestamp}}</p>
        </div>
        {{/each}}

        <h3>Recommended Actions:</h3>
        <ol>
          <li>Prioritize issues affecting critical user flows</li>
          <li>Reach out to affected users if needed</li>
          <li>Update product team on potential feature impact</li>
          <li>Consider temporary workarounds if issues are severe</li>
        </ol>`
    }
  },
  "integration_configs": {
    "slack": {
      "webhook_url": "https://hooks.slack.com/services/YOUR/SLACK/WEBHOOK",
      "default_channel": "#alerts",
      "mention_users": ["@devops", "@oncall"],
      "notification_threshold": "warning",
      "resolve_notifications": true
    },
    "pagerduty": {
      "service_key": "your-pagerduty-service-key",
      "severity_mapping": {
        "critical": "critical",
        "warning": "high",
        "info": "low"
      },
      "auto_resolve": true,
      "grouping": true
    },
    "email": {
      "smtp_server": "smtp.company.com",
      "smtp_port": 587,
      "default_recipients": ["[email protected]"],
      "use_tls": true,
      "from_address": "[email protected]"
    },
    "jira": {
      "url": "https://company.atlassian.net",
      "username": "sentry-bot",
      "project_key": "BUG",
      "default_issue_type": "Bug",
      "auto_assign": true,
      "default_priority": "Medium"
    },
    "github": {
      "token": "your-github-token",
      "repository": "company/app",
      "auto_assign": true,
      "default_labels": ["bug", "auto-generated"],
      "default_milestone": "current-sprint"
    },
    "statuspage": {
      "api_key": "your-statuspage-api-key",
      "page_id": "your-statuspage-id",
      "auto_update": true,
      "notify_subscribers": true
    },
    "linear": {
      "team_id": "your-linear-team-id",
      "api_key": "your-linear-api-key",
      "auto_create_issue": true,
      "default_state": "Backlog",
      "default_priority": "Medium"
    }
  },
  "escalation_policies": [
    {
      "name": "Critical Production Issues",
      "triggers": [
        {
          "rule_type": "error_count",
          "threshold": 50,
          "time_window": "5m",
          "environment": "production"
        },
        {
          "rule_type": "performance_degradation",
          "threshold": "5000",
          "metric": "p95_duration"
        }
      ],
      "steps": [
        {
          "wait_time": "0m",
          "actions": ["slack_critical", "pagerduty_critical"]
        },
        {
          "wait_time": "15m",
          "actions": ["phone_call", "executive_notification"]
        },
        {
          "wait_time": "30m",
          "actions": ["war_room", "all_hands_notification"]
        }
      ]
    },
    {
      "name": "Non-Critical Issues",
      "triggers": [
        {
          "rule_type": "error_count",
          "threshold": 10,
          "time_window": "30m"
        }
      ],
      "steps": [
        {
          "wait_time": "0m",
          "actions": ["slack_warning", "email_team"]
        },
        {
          "wait_time": "2h",
          "actions": ["create_ticket"]
        }
      ]
    }
  ],
  "maintenance_windows": [
    {
      "name": "Weekend Deployments",
      "description": "Silence non-critical alerts during planned maintenance",
      "schedule": {
        "type": "weekly",
        "days": ["Saturday", "Sunday"],
        "start_time": "02:00",
        "end_time": "06:00",
        "timezone": "UTC"
      },
      "affected_rules": [
        "performance_degradation",
        "database_errors"
      ],
      "critical_rules_enabled": true
    },
    {
      "name": "Major Release Window",
      "description": "Silence certain alerts during major releases",
      "schedule": {
        "type": "specific_dates",
        "dates": ["2024-01-15", "2024-02-01"],
        "start_time": "00:00",
        "end_time": "23:59"
      },
      "affected_rules": [
        "new_error_type",
        "ux_issues"
      ]
    }
  ]
}