# Configuration Guide

This guide covers all configuration options for Rails Error Dashboard, including advanced features for customization and extensibility.

## Table of Contents

- [Configuration Defaults Reference](#configuration-defaults-reference)
- [Opt-in Feature System](#opt-in-feature-system)
- [Basic Configuration](#basic-configuration)
- [Notification Features](#notification-features)
- [Performance Features](#performance-features)
- [Advanced Analytics Features](#advanced-analytics-features)
- [Source Code Integration](#source-code-integration-new)
- [Local Variable Capture](#local-variable-capture-v040)
- [Instance Variable Capture](#instance-variable-capture-v040)
- [Swallowed Exception Detection](#swallowed-exception-detection-v040)
- [Diagnostic Dump](#diagnostic-dump-v040)
- [Rack Attack Event Tracking](#rack-attack-event-tracking-v040)
- [Process Crash Capture](#process-crash-capture-v040)
- [Custom Severity Classification](#custom-severity-classification)
- [Ignored Exceptions](#ignored-exceptions)
- [Error Sampling](#error-sampling)
- [Notification Callbacks](#notification-callbacks)
- [ActiveSupport Notifications](#activesupport-notifications)
- [Backtrace Configuration](#backtrace-configuration)
- [Complete Configuration Example](#complete-configuration-example)

---

## Configuration Defaults Reference

Complete reference of all 60+ configuration options with defaults, types, and descriptions.

### Authentication & Access

| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `dashboard_username` | String | `"gandalf"` | Username for HTTP Basic Auth (ENV: `ERROR_DASHBOARD_USER`) |
| `dashboard_password` | String | `"youshallnotpass"` | Password for HTTP Basic Auth (ENV: `ERROR_DASHBOARD_PASSWORD`) |
| `authenticate_with` | Lambda/Proc/Callable | `nil` | Custom auth lambda executed in controller context. When set, replaces HTTP Basic Auth. Return truthy to allow, falsy to deny (403). |
| `user_model` | String | `"User"` | Model name for user associations |

### Multi-App Support

| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `application_name` | String | Auto-detected | Application identifier (ENV: `APPLICATION_NAME`) |
| `database` | Symbol/String | `nil` | Database connection name (nil = primary database) |
| `use_separate_database` | Boolean | `false` | Use separate database for errors (ENV: `USE_SEPARATE_ERROR_DB`) |

### Notifications - Slack

| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `enable_slack_notifications` | Boolean | `false` | Enable Slack webhooks |
| `slack_webhook_url` | String | `nil` | Slack webhook URL (ENV: `SLACK_WEBHOOK_URL`) |

### Notifications - Email

| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `enable_email_notifications` | Boolean | `false` | Enable email notifications |
| `notification_email_recipients` | Array | `[]` | Email recipients (ENV: `ERROR_NOTIFICATION_EMAILS`, comma-separated) |
| `notification_email_from` | String | `"errors@example.com"` | From address (ENV: `ERROR_NOTIFICATION_FROM`) |
| `dashboard_base_url` | String | `nil` | Base URL for links in emails (ENV: `DASHBOARD_BASE_URL`) |

### Notifications - Discord

| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `enable_discord_notifications` | Boolean | `false` | Enable Discord webhooks |
| `discord_webhook_url` | String | `nil` | Discord webhook URL (ENV: `DISCORD_WEBHOOK_URL`) |

### Notifications - PagerDuty

| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `enable_pagerduty_notifications` | Boolean | `false` | Enable PagerDuty (critical errors only) |
| `pagerduty_integration_key` | String | `nil` | PagerDuty integration key (ENV: `PAGERDUTY_INTEGRATION_KEY`) |

### Notifications - Webhooks

| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `enable_webhook_notifications` | Boolean | `false` | Enable custom webhooks |
| `webhook_urls` | Array | `[]` | Custom webhook URLs (ENV: `WEBHOOK_URLS`, comma-separated) |

### Core Features

| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `enable_middleware` | Boolean | `true` | Enable error catching middleware |
| `enable_error_subscriber` | Boolean | `true` | Enable Rails.error subscriber |
| `retention_days` | Integer | `90` | Days to keep errors before auto-deletion |

### Error Classification

| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `custom_severity_rules` | Hash | `{}` | Custom error type → severity mappings |
| `ignored_exceptions` | Array | `[]` | Exception classes/patterns to ignore |

### Performance Optimization

| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `async_logging` | Boolean | `false` | Log errors asynchronously in background jobs |
| `async_adapter` | Symbol | `:sidekiq` | Background job adapter (`:sidekiq`, `:solid_queue`, `:async`) |
| `sampling_rate` | Float | `1.0` | Percentage of errors to log (0.0-1.0, critical always logged) |
| `max_backtrace_lines` | Integer | `50` | Maximum backtrace lines to store |

### API & Rate Limiting

| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `enable_rate_limiting` | Boolean | `false` | Enable API rate limiting (opt-in) |
| `rate_limit_per_minute` | Integer | `100` | Max requests per minute per IP |

### Enhanced Metrics

| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `app_version` | String | `nil` | Application version (ENV: `APP_VERSION`) |
| `git_sha` | String | `nil` | Git commit SHA (ENV: `GIT_SHA`) |
| `git_repository_url` | String | `nil` | Git repository URL for commit links (ENV: `GIT_REPOSITORY_URL`) |
| `total_users_for_impact` | Integer | `nil` | Total users for impact % calculation (auto-detected if nil) |

### Advanced Analytics - Error Analysis

| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `enable_similar_errors` | Boolean | `false` | Fuzzy error matching with Jaccard/Levenshtein similarity |
| `enable_co_occurring_errors` | Boolean | `false` | Detect errors happening together |
| `enable_error_cascades` | Boolean | `false` | Detect parent→child error relationships |
| `enable_error_correlation` | Boolean | `false` | Version/user/time correlation analysis |
| `enable_platform_comparison` | Boolean | `false` | iOS vs Android vs Web health comparison |
| `enable_occurrence_patterns` | Boolean | `false` | Cyclical and burst pattern detection |

### Advanced Analytics - Baseline Monitoring

| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `enable_baseline_alerts` | Boolean | `false` | Statistical anomaly detection and alerts |
| `baseline_alert_threshold_std_devs` | Float | `2.0` | Standard deviations to trigger alert (ENV: `BASELINE_ALERT_THRESHOLD`) |
| `baseline_alert_severities` | Array | `[:critical, :high]` | Severities to alert on |
| `baseline_alert_cooldown_minutes` | Integer | `120` | Minutes between alerts for same error (ENV: `BASELINE_ALERT_COOLDOWN`) |

### Source Code Integration (NEW!)

| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `enable_source_code_integration` | Boolean | `false` | View source code directly in error details |
| `source_code_context_lines` | Integer | `5` | Lines of context before/after error line |
| `enable_git_blame` | Boolean | `false` | Show git blame info (author, commit, timestamp) |
| `source_code_cache_ttl` | Integer | `3600` | Cache TTL in seconds (1 hour default) |
| `only_show_app_code_source` | Boolean | `true` | Hide gem/vendor code (security) |
| `git_branch_strategy` | Symbol | `:commit_sha` | Branch strategy (`:commit_sha`, `:current_branch`, `:main`) |

### Breadcrumbs — Request Activity Trail (NEW!)

| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `enable_breadcrumbs` | Boolean | `false` | Capture request activity trail (SQL, controller, cache, etc.) |
| `breadcrumb_buffer_size` | Integer | `40` | Max breadcrumbs per request (ring buffer) |
| `breadcrumb_categories` | Array/nil | `nil` | Categories to capture (`nil` = all; or `[:sql, :controller, :cache, :job, :mailer, :deprecation, :custom]`) |
| `enable_n_plus_one_detection` | Boolean | `true` | Detect N+1 query patterns in SQL breadcrumbs (display-time analysis) |
| `n_plus_one_threshold` | Integer | `3` | Min repetitions to flag as N+1 (min: 2) |

### System Health Snapshot

| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `enable_system_health` | Boolean | `false` | Capture GC, memory, threads, connection pool, RubyVM cache, YJIT stats at error time |

### Local Variable Capture (v0.4.0)

| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `enable_local_variables` | Boolean | `false` | Capture local variables at exception raise point via TracePoint |
| `local_variable_max_count` | Integer | `15` | Maximum number of local variables to capture per exception |
| `local_variable_max_depth` | Integer | `3` | Maximum object nesting depth for serialization |
| `local_variable_max_string_length` | Integer | `200` | Truncate string values beyond this length |
| `local_variable_max_array_items` | Integer | `10` | Maximum array items to serialize |
| `local_variable_max_hash_items` | Integer | `20` | Maximum hash entries to serialize |
| `local_variable_filter_patterns` | Array | `[]` | Additional sensitive variable name patterns to filter (beyond Rails `filter_parameters`) |

### Instance Variable Capture (v0.4.0)

| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `enable_instance_variables` | Boolean | `false` | Capture instance variables from the object that raised the exception |
| `instance_variable_max_count` | Integer | `20` | Maximum instance variables to capture per exception |
| `instance_variable_filter_patterns` | Array | `[]` | Additional sensitive instance variable name patterns to filter |

### Swallowed Exception Detection (v0.4.0)

| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `detect_swallowed_exceptions` | Boolean | `false` | Detect exceptions that are raised but silently rescued. **Requires Ruby 3.3+** |
| `swallowed_exception_max_cache_size` | Integer | `1000` | Maximum entries per thread-local raise/rescue tracking cache |
| `swallowed_exception_flush_interval` | Integer | `60` | Seconds between database flushes of accumulated data |
| `swallowed_exception_threshold` | Float | `0.95` | Rescue ratio (0.0-1.0) to flag a location as "swallowed" |
| `swallowed_exception_ignore_classes` | Array | `[]` | Additional exception classes to skip during tracking |

### Diagnostic Dump (v0.4.0)

| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `enable_diagnostic_dump` | Boolean | `false` | Enable on-demand system state snapshots via dashboard or rake task |

### Rack Attack Event Tracking (v0.4.0)

| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `enable_rack_attack_tracking` | Boolean | `false` | Track Rack::Attack throttle/blocklist events as breadcrumbs. Requires `enable_breadcrumbs = true` |

### Process Crash Capture (v0.4.0)

| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `enable_crash_capture` | Boolean | `false` | Capture unhandled exceptions that crash the Ruby process via at_exit hook |
| `crash_capture_path` | String | `nil` | Directory for crash files. If nil, uses `Dir.tmpdir`. Directory must exist |

### Internal Logging & Debugging

| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `enable_internal_logging` | Boolean | `false` | Enable internal gem logging for debugging |
| `log_level` | Symbol | `:silent` | Log level (`:debug`, `:info`, `:warn`, `:error`, `:silent`) |

### Read-Only Attributes

| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `notification_callbacks` | Hash | See below | Notification callback registry (use helper methods, not direct assignment) |

---

### Environment Variables Quick Reference

All environment variables that can be used instead of or alongside configuration:

```bash
# Authentication
ERROR_DASHBOARD_USER=admin
ERROR_DASHBOARD_PASSWORD=secure_password

# Multi-App
APPLICATION_NAME=my-api

# Database
USE_SEPARATE_ERROR_DB=true  # "true" or "false"

# Notifications
SLACK_WEBHOOK_URL=https://hooks.slack.com/services/...
ERROR_NOTIFICATION_EMAILS=team@example.com,ops@example.com
ERROR_NOTIFICATION_FROM=errors@myapp.com
DASHBOARD_BASE_URL=https://dashboard.example.com
DISCORD_WEBHOOK_URL=https://discord.com/api/webhooks/...
PAGERDUTY_INTEGRATION_KEY=abc123...
WEBHOOK_URLS=https://hook1.example.com,https://hook2.example.com

# Enhanced Metrics
APP_VERSION=1.2.3
GIT_SHA=abc123def456
GIT_REPOSITORY_URL=https://github.com/user/repo

# Baseline Alerts
BASELINE_ALERT_THRESHOLD=2.0  # Standard deviations
BASELINE_ALERT_COOLDOWN=120   # Minutes
```

---

### Practical Defaults Guidance

**For Development:**
```ruby
config.async_logging = false          # Sync for easier debugging
config.sampling_rate = 1.0             # Log all errors
config.enable_internal_logging = true  # See what's happening
config.log_level = :debug             # Verbose logging
```

**For Production (Low Traffic):**
```ruby
config.async_logging = true           # Background jobs
config.async_adapter = :sidekiq       # Battle-tested
config.sampling_rate = 1.0            # Log all errors
config.retention_days = 90            # 3 months
config.max_backtrace_lines = 50       # Full context
```

**For Production (High Traffic >1000 errors/day):**
```ruby
config.async_logging = true           # REQUIRED
config.async_adapter = :sidekiq       # Recommended
config.sampling_rate = 0.1            # 10% (critical always logged)
config.retention_days = 30            # 1 month
config.max_backtrace_lines = 20       # Reduce storage
config.use_separate_database = true   # Isolate errors
```

---

## Opt-in Feature System

Rails Error Dashboard uses an **opt-in architecture**. Core features are always enabled, while everything else is disabled by default.

**Tier 1 Features (Always ON):**
- ✅ Error capture (controllers, jobs, middleware)
- ✅ Dashboard UI with search and filtering
- ✅ Real-time updates via Turbo Streams
- ✅ Analytics and trend charts

**Optional Features (17 total):**
- 📧 **5 Notification Channels** (Slack, Email, Discord, PagerDuty, Webhooks)
- ⚡ **3 Performance Features** (Async Logging, Error Sampling, Separate Database)
- 📊 **7 Advanced Analytics** (Baseline Alerts, Fuzzy Matching, Co-occurring Errors, Error Cascades, Correlation, Platform Comparison, Occurrence Patterns)
- 🔍 **2 Developer Tools** (Source Code Integration, Git Blame)

All features can be enabled during installation via the interactive installer, or toggled on/off at any time in the initializer.

---

## Basic Configuration

Create an initializer at `config/initializers/rails_error_dashboard.rb`:

```ruby
RailsErrorDashboard.configure do |config|
  # Dashboard authentication (always required)
  config.dashboard_username = "admin"
  config.dashboard_password = ENV.fetch("ERROR_DASHBOARD_PASSWORD", "changeme")

  # Data retention (days)
  config.retention_days = 90

  # User model for error association
  config.user_model = "User"

  # Enable/disable middleware and error subscriber
  config.enable_middleware = true
  config.enable_error_subscriber = true
end
```

### Custom Authentication

If you use Devise, Warden, or any other auth system, you can replace HTTP Basic Auth with a lambda that runs in controller context via `instance_exec`:

```ruby
RailsErrorDashboard.configure do |config|
  # Devise/Warden — use warden directly (recommended)
  config.authenticate_with = -> {
    if warden.authenticated?
      true
    else
      redirect_to main_app.new_user_session_path, allow_other_host: true
    end
  }

  # Warden with admin scope
  config.authenticate_with = -> { warden.authenticated?(:admin) }

  # Session-based
  config.authenticate_with = -> { session[:dashboard_admin] == true }
end
```

> **Important: Engine controller context.** The lambda runs inside the engine's controller, which inherits from `ActionController::Base` — not your app's `ApplicationController`. This means Devise helpers like `current_user` and `authenticate_user!` are **not available**. Use `warden` (the underlying Rack middleware) instead:
>
> | Works | Doesn't work |
> |-------|-------------|
> | `warden.authenticated?` | `current_user` |
> | `warden.user` | `authenticate_user!` |
> | `warden.authenticate(:scope => :user)` | `user_signed_in?` |
> | `session`, `cookies`, `request`, `params` | Devise helper methods |

**How it works:**
- The lambda has access to `warden`, `session`, `request`, `params`, `cookies`, `redirect_to`, etc.
- **Truthy return** → access granted
- **Falsy return** (including `nil`) → 403 Forbidden
- **Lambda raises** → rescued, logged, 403 (fail closed)
- **Lambda calls `redirect_to`** → redirect honored (e.g. to your login page)
- **`authenticate_with = nil`** (default) → falls back to HTTP Basic Auth

---

## Notification Features

Rails Error Dashboard supports 5 notification channels, all disabled by default.

### Slack Notifications

Send real-time error notifications to Slack channels.

```ruby
RailsErrorDashboard.configure do |config|
  config.enable_slack_notifications = true
  config.slack_webhook_url = ENV['SLACK_WEBHOOK_URL']
end
```

### Email Notifications

Send error alerts via email to your team.

```ruby
RailsErrorDashboard.configure do |config|
  config.enable_email_notifications = true
  config.notification_email_recipients = ["dev@yourapp.com", "team@yourapp.com"]
  config.notification_email_from = "errors@yourapp.com"
end
```

### Discord Notifications

Push errors to Discord channels via webhooks.

```ruby
RailsErrorDashboard.configure do |config|
  config.enable_discord_notifications = true
  config.discord_webhook_url = ENV['DISCORD_WEBHOOK_URL']
end
```

### PagerDuty Integration

Escalate critical errors to PagerDuty for on-call teams. **Only triggers for critical errors** to avoid alert fatigue.

```ruby
RailsErrorDashboard.configure do |config|
  config.enable_pagerduty_notifications = true
  config.pagerduty_integration_key = ENV['PAGERDUTY_INTEGRATION_KEY']
end
```

### Custom Webhooks

Send errors to custom endpoints (Zapier, IFTTT, custom services).

```ruby
RailsErrorDashboard.configure do |config|
  config.enable_webhook_notifications = true
  config.webhook_urls = [
    'https://yourapp.com/hooks/errors',
    'https://zapier.com/hooks/catch/123456/abcdef'
  ]
end
```

**Dashboard Base URL** (for notification links):
```ruby
config.dashboard_base_url = ENV['DASHBOARD_BASE_URL']  # e.g., "https://yourapp.com"
```

See [Notifications Guide](/rails_error_dashboard/docs/guides/notifications/) for detailed setup instructions.

---

## Performance Features

Optimize performance and reduce database load with these features.

### Async Error Logging

Log errors in background jobs for non-blocking performance.

```ruby
RailsErrorDashboard.configure do |config|
  config.async_logging = true
  config.async_adapter = :sidekiq  # Options: :sidekiq, :solid_queue, :async
end
```

**Supported Adapters:**
- `:sidekiq` - Battle-tested, recommended for production
- `:solid_queue` - Rails 8.1+ built-in job backend
- `:async` - Rails default (in-process, good for development)

### Error Sampling

Reduce database writes by logging only a percentage of non-critical errors. **Critical errors are ALWAYS logged** regardless of sampling rate.

```ruby
RailsErrorDashboard.configure do |config|
  config.sampling_rate = 0.1  # Log 10% of non-critical errors
end
```

See [Error Sampling](#error-sampling) section below for details.

### Separate Database

Isolate error data in a dedicated database for better performance and separation of concerns.

```ruby
RailsErrorDashboard.configure do |config|
  config.use_separate_database = true
end
```

Requires additional database configuration. See [Database Options Guide](/rails_error_dashboard/docs/guides/database-options/) for setup instructions.

---

## Advanced Analytics Features

Powerful analytics features for deep error insights, all disabled by default.

### Baseline Anomaly Alerts

Automatically detect when error rates exceed normal patterns using statistical analysis.

```ruby
RailsErrorDashboard.configure do |config|
  config.enable_baseline_alerts = true
  config.baseline_alert_threshold_std_devs = 2.0  # Alert when >2 std devs above baseline
  config.baseline_alert_severities = [:critical, :high]  # Alert on these severities only
  config.baseline_alert_cooldown_minutes = 120  # 2 hours between alerts for same error
end
```

See [Baseline Monitoring Guide](/rails_error_dashboard/docs/features/baseline-monitoring/) for details.

### Fuzzy Error Matching

Find similar errors even with different error_hashes using backtrace signatures and message similarity.

```ruby
RailsErrorDashboard.configure do |config|
  config.enable_similar_errors = true
end
```

See [Advanced Error Grouping Guide](/rails_error_dashboard/docs/features/advanced-error-grouping/) for details.

### Co-occurring Errors

Detect errors that happen together in time (within 5-minute windows).

```ruby
RailsErrorDashboard.configure do |config|
  config.enable_co_occurring_errors = true
end
```

See [Advanced Error Grouping Guide](/rails_error_dashboard/docs/features/advanced-error-grouping/) for details.

### Error Cascades

Identify parent→child error relationships (error A causes error B).

```ruby
RailsErrorDashboard.configure do |config|
  config.enable_error_cascades = true
end
```

See [Advanced Error Grouping Guide](/rails_error_dashboard/docs/features/advanced-error-grouping/) for details.

### Error Correlation

Correlate errors with app versions, users, and time patterns.

```ruby
RailsErrorDashboard.configure do |config|
  config.enable_error_correlation = true
end
```

See [Error Correlation Guide](/rails_error_dashboard/docs/features/error-correlation/) for details.

### Platform Comparison

Compare iOS vs Android vs Web health metrics and platform-specific error rates.

```ruby
RailsErrorDashboard.configure do |config|
  config.enable_platform_comparison = true
end
```

See [Platform Comparison Guide](/rails_error_dashboard/docs/features/platform-comparison/) for details.

### Occurrence Patterns

Detect cyclical patterns (daily/weekly rhythms) and error bursts.

```ruby
RailsErrorDashboard.configure do |config|
  config.enable_occurrence_patterns = true
end
```

See [Occurrence Patterns Guide](/rails_error_dashboard/docs/features/occurrence-patterns/) for details.

---

## Source Code Integration (NEW!)

View source code directly in the error dashboard with git blame information and repository links.

### Basic Configuration

```ruby
RailsErrorDashboard.configure do |config|
  # Enable source code viewer
  config.enable_source_code_integration = true

  # Optional: Enable git blame integration
  config.enable_git_blame = true
end
```

### Advanced Configuration

```ruby
RailsErrorDashboard.configure do |config|
  # Enable source code viewer
  config.enable_source_code_integration = true

  # Enable git blame
  config.enable_git_blame = true

  # Context lines (±N lines around error)
  config.source_code_context_lines = 5  # Default: 5

  # Cache TTL in seconds
  config.source_code_cache_ttl = 3600  # Default: 1 hour

  # Security: only show app code (hide gems/vendor)
  config.only_show_app_code_source = true  # Default: true

  # Branch strategy for repository links
  config.git_branch_strategy = :commit_sha  # Options: :commit_sha, :current_branch, :main
end
```

### Features

- **Source Code Viewer**: View actual source code lines around the error
- **Git Blame Integration**: See who last modified the code and when
- **Repository Links**: Direct links to GitHub, GitLab, or Bitbucket
- **Automatic Detection**: Detects repository URL from git remote
- **Security**: Only reads files within application root directory

### Requirements

- Application must be a git repository
- Git must be installed (for git blame functionality)
- Dashboard must have read access to application source files

### Use Cases

```ruby
# Development: Full visibility
config.enable_source_code_integration = true
config.enable_git_blame = true

# Production: Source code only (no git blame for performance)
config.enable_source_code_integration = true
config.enable_git_blame = false

# Staging: Enable both for debugging
if Rails.env.staging?
  config.enable_source_code_integration = true
  config.enable_git_blame = true
end
```

### Privacy & Security

- **Self-hosted**: Source code never leaves your infrastructure
- **Read-only**: Dashboard only reads files, never modifies
- **Path validation**: Only files within app root can be accessed
- **No external calls**: All processing happens locally

---

## Breadcrumbs — Request Activity Trail (NEW!)

Breadcrumbs capture a timeline of events (SQL queries, controller actions, cache operations, etc.) during a request, then store them with the error for instant debugging context.

### Basic Configuration

```ruby
RailsErrorDashboard.configure do |config|
  # Enable breadcrumbs
  config.enable_breadcrumbs = true
end
```

### Advanced Configuration

```ruby
RailsErrorDashboard.configure do |config|
  config.enable_breadcrumbs = true

  # Max events per request (default: 40, ring buffer drops oldest when full)
  config.breadcrumb_buffer_size = 40

  # Limit which categories are captured (default: nil = all)
  # Options: :sql, :controller, :cache, :job, :mailer, :deprecation, :custom
  config.breadcrumb_categories = [ :sql, :controller ]  # Only SQL and controller events

  # N+1 query detection (analyzes SQL breadcrumbs at display time)
  config.enable_n_plus_one_detection = true  # Default: true
  config.n_plus_one_threshold = 3            # Min repetitions to flag (default: 3, min: 2)
end
```

### Manual Breadcrumbs

Add custom breadcrumbs from anywhere in your application code:

```ruby
RailsErrorDashboard.add_breadcrumb("checkout started", { cart_id: 123 })
RailsErrorDashboard.add_breadcrumb("payment processed", { provider: "stripe", amount: 99.99 })
```

### Captured Events

| Event | Category | What's Captured |
|-------|----------|----------------|
| `sql.active_record` | `sql` | SQL query (first 200 chars) + duration. Skips SCHEMA queries and internal gem queries |
| `process_action.action_controller` | `controller` | `ControllerName#action` + duration |
| `cache_read.active_support` | `cache` | `cache read: key` |
| `cache_write.active_support` | `cache` | `cache write: key` |
| `perform.active_job` | `job` | Job class name + duration |
| `deliver.action_mailer` | `mailer` | `MailerClass to: [recipients]` |
| `deprecation.rails` | `deprecation` | Deprecation warning message + caller location |

### N+1 Query Detection

When breadcrumbs and N+1 detection are both enabled, the error detail page automatically analyzes SQL breadcrumbs for repeated query patterns. A yellow warning card appears when the same normalized query shape is repeated above the threshold:

```ruby
config.enable_n_plus_one_detection = true  # ON by default
config.n_plus_one_threshold = 3            # Flag when same pattern appears 3+ times
```

The detector normalizes SQL by replacing literal values (`WHERE id = 42` → `WHERE id = ?`) and IN lists (`IN (1, 2, 3)` → `IN (?)`) while preserving PostgreSQL double-quoted identifiers. Analysis runs at display time only — zero overhead on requests.

### Use Cases

```ruby
# Development: Full breadcrumb visibility
config.enable_breadcrumbs = true

# Production: Enable with conservative buffer
config.enable_breadcrumbs = true
config.breadcrumb_buffer_size = 25

# High-traffic: Only capture SQL and controller events
config.enable_breadcrumbs = true
config.breadcrumb_categories = [ :sql, :controller ]
```

### Safety

- **Default OFF** — opt-in only
- **Fixed-size ring buffer** — no unbounded memory growth
- **Thread-local** — no mutex/lock, each request isolated
- **Cleanup in ensure** — buffer cleared even on exceptions (Puma thread reuse safe)
- **Every subscriber wrapped in rescue** — never raises, never blocks
- **Sensitive data filtered** — passwords, tokens, secrets scrubbed before storage
- **< 0.1ms/request overhead** — events already fired by Rails

---

## System Health Snapshot (NEW!)

Capture runtime health metrics (GC stats, memory, threads, connection pool, Puma) at the moment of every error. Displayed in the error detail sidebar.

### Quick Start

```ruby
RailsErrorDashboard.configure do |config|
  config.enable_system_health = true
end
```

### What Gets Captured

| Metric | Source | Notes |
|--------|--------|-------|
| GC stats | `GC.stat` | heap_live_slots, heap_free_slots, major_gc_count, total_allocated_objects |
| Process memory | `/proc/self/status` | RSS in MB, Linux only (nil on macOS) |
| Thread count | `Thread.list.count` | O(1), safe |
| Connection pool | `ActiveRecord::Base.connection_pool.stat` | size, busy, idle, dead, waiting |
| Puma stats | `Puma.stats` | running, max_threads, pool_capacity, backlog (when available) |
| RubyVM cache | `RubyVM.stat` | constant_cache invalidations, class serial, global state (when available) |
| YJIT stats | `RubyVM::YJIT.runtime_stats` | compiled ISEQs, code region size, inline/outlined bytes (when YJIT enabled) |

### Safety

- **Default OFF** — opt-in only
- **Sub-millisecond** — total snapshot < 1ms
- **Every metric individually wrapped** in `rescue => nil`
- **Top-level rescue** — returns `{ captured_at: ... }` if everything fails (never raises)
- **No ObjectSpace scanning** — never calls `each_object` or `count_objects`
- **No Thread backtraces** — only `.count`, never `.map(&:backtrace)`
- **No subprocess** — memory via procfs only, no `ps`, no fork, no backtick
- **No global state** — no Thread.current, no mutex, no memoization

---

## Local Variable Capture (v0.4.0)

Capture local variables at the exact moment an exception is raised via `TracePoint(:raise)`. The most valuable debugging context possible.

```ruby
RailsErrorDashboard.configure do |config|
  config.enable_local_variables = true

  # Serialization limits (all have sensible defaults)
  config.local_variable_max_count = 15          # Max variables per exception
  config.local_variable_max_depth = 3           # Max object nesting depth
  config.local_variable_max_string_length = 200 # Truncate strings beyond this
  config.local_variable_max_array_items = 10    # Max array items
  config.local_variable_max_hash_items = 20     # Max hash entries

  # Additional sensitive patterns (beyond Rails filter_parameters)
  config.local_variable_filter_patterns = [ /secret/, /token/ ]
end
```

### Safety

- **Never stores Binding objects** — values extracted immediately, Binding is GC'd
- **Sensitive data auto-filtered** — Rails `filter_parameters` applied automatically
- **Configurable limits** — all size limits enforced during serialization
- **Opt-in only** — disabled by default

---

## Instance Variable Capture (v0.4.0)

Capture instance variables from the object that raised the exception (`tp.self` on the TracePoint).

```ruby
RailsErrorDashboard.configure do |config|
  config.enable_instance_variables = true
  config.instance_variable_max_count = 20          # Max variables (default: 20)
  config.instance_variable_filter_patterns = []    # Additional sensitive patterns
end
```

Shares the same TracePoint handler as local variable capture — minimal overhead when both are enabled. Includes `_self_class` metadata showing the receiver's class name.

---

## Swallowed Exception Detection (v0.4.0)

Detect exceptions that are raised but silently rescued — the hardest bugs to find. **Requires Ruby 3.3+** (TracePoint `:rescue` event, Feature #19572).

```ruby
RailsErrorDashboard.configure do |config|
  config.detect_swallowed_exceptions = true

  config.swallowed_exception_max_cache_size = 1000  # Thread-local cache size
  config.swallowed_exception_flush_interval = 60    # Seconds between DB flushes
  config.swallowed_exception_threshold = 0.95       # 95% rescue ratio = "swallowed"
  config.swallowed_exception_ignore_classes = []    # Exception classes to skip
end
```

Dashboard page at `/errors/swallowed_exceptions`. Auto-disabled on Ruby < 3.3 with a warning (no crash).

---

## Diagnostic Dump (v0.4.0)

On-demand system state snapshots — environment, GC stats, threads, connection pool, memory, job queue health.

```ruby
RailsErrorDashboard.configure do |config|
  config.enable_diagnostic_dump = true
end
```

Trigger via dashboard button or `rails error_dashboard:diagnostic_dump NOTE="deploy check"`. Dashboard page at `/errors/diagnostic_dumps`.

---

## Rack Attack Event Tracking (v0.4.0)

Track Rack::Attack throttle, blocklist, and track events as breadcrumbs. Requires breadcrumbs to be enabled.

```ruby
RailsErrorDashboard.configure do |config|
  config.enable_breadcrumbs = true              # Required dependency
  config.enable_rack_attack_tracking = true
end
```

Auto-disabled with warning if breadcrumbs are not enabled. Dashboard page at `/errors/rack_attack_summary`.

---

## Process Crash Capture (v0.4.0)

Capture unhandled exceptions that crash the Ruby process via an `at_exit` hook.

```ruby
RailsErrorDashboard.configure do |config|
  config.enable_crash_capture = true
  config.crash_capture_path = nil    # nil = Dir.tmpdir; custom path must exist
end
```

Writes crash data to JSON on disk (database may be unavailable during shutdown). Imported automatically on next boot. A self-hosted only feature — impossible for SaaS tools.

---

## Custom Severity Classification

Override default severity levels for specific error types. This is useful when you want to treat certain errors differently than the defaults.

### Default Severity Levels

- **Critical**: `SecurityError`, `NoMemoryError`, `SystemStackError`, `ActiveRecord::StatementInvalid`
- **High**: `ActiveRecord::RecordNotFound`, `ArgumentError`, `TypeError`, `NoMethodError`, `NameError`
- **Medium**: `ActiveRecord::RecordInvalid`, `Timeout::Error`, `Net::ReadTimeout`, `Net::OpenTimeout`
- **Low**: All other errors

### Configuration

```ruby
RailsErrorDashboard.configure do |config|
  config.custom_severity_rules = {
    # Treat payment errors as critical
    "Stripe::CardError" => :critical,
    "PaymentProcessingError" => :critical,

    # Downgrade validation errors to low
    "ActiveRecord::RecordInvalid" => :low,

    # Custom application errors
    "MyApp::BusinessLogicError" => :medium
  }
end
```

### Use Cases

- **Payment Errors**: Treat as critical to ensure immediate attention
- **Validation Errors**: Downgrade to low if they're expected user input errors
- **Third-party API Errors**: Classify based on business impact
- **Custom Application Errors**: Set appropriate severity for domain-specific errors

---

## Ignored Exceptions

Prevent certain exceptions from being logged. Useful for reducing noise from expected errors or third-party gems.

### Configuration

```ruby
RailsErrorDashboard.configure do |config|
  config.ignored_exceptions = [
    # Exact class names
    "ActionController::RoutingError",
    "ActiveRecord::RecordNotFound",

    # Regex patterns for flexible matching
    /Rack::Timeout/,
    /ActionController::InvalidAuthenticityToken/,

    # All errors from a specific namespace
    /ThirdPartyGem::.*/
  ]
end
```

### Features

- **Exact Matching**: Specify exception class names as strings
- **Regex Patterns**: Use regular expressions for flexible matching
- **Inheritance Support**: Ignoring a parent class ignores all subclasses
- **Early Exit**: Ignored exceptions skip all processing, saving resources

### Use Cases

```ruby
# Production: Ignore bot-related errors
config.ignored_exceptions = [
  "ActionController::RoutingError",  # Bots scanning for vulnerabilities
  /ActionController::InvalidAuthenticityToken/  # CSRF from legitimate crawlers
]

# Development: Ignore known third-party issues
config.ignored_exceptions = [
  /Geocoder::.*/,  # Geocoding API rate limits
  "Redis::CannotConnectError"  # Redis disconnects during development
]
```

---

## Error Sampling

Reduce database load by logging only a percentage of non-critical errors. **Critical errors are ALWAYS logged** regardless of sampling rate.

### Configuration

```ruby
RailsErrorDashboard.configure do |config|
  # Log 100% of errors (default)
  config.sampling_rate = 1.0

  # Log only 10% of non-critical errors (critical errors always logged)
  config.sampling_rate = 0.1

  # Disable logging of non-critical errors entirely
  config.sampling_rate = 0.0
end
```

### Behavior

- **1.0 (100%)**: Log all errors - default behavior
- **0.1 (10%)**: Log 10% of non-critical errors, 100% of critical errors
- **0.0 (0%)**: Skip all non-critical errors, log only critical errors
- **> 1.0**: Treated as 100%
- **< 0.0**: Treated as 0%

### Critical Errors (Always Logged)

These errors bypass sampling because they indicate serious system issues:
- `SecurityError`
- `NoMemoryError`
- `SystemStackError`
- `ActiveRecord::StatementInvalid`

### Use Cases

```ruby
# High-traffic production: Reduce database writes
config.sampling_rate = 0.1  # 10% sampling

# Load testing: Only log critical issues
config.sampling_rate = 0.0  # Skip non-critical

# Monitoring phase: Full visibility
config.sampling_rate = 1.0  # Log everything
```

---

## Notification Callbacks

Register custom Ruby blocks that execute when errors are logged or resolved. Perfect for integrating with external services.

### Available Callbacks

#### 1. `on_error_logged` - Any Error Logged

```ruby
RailsErrorDashboard.on_error_logged do |error_log|
  # Called for every NEW error (not recurrences)

  # Send to custom logging service
  CustomLogger.log(
    level: error_log.severity,
    message: error_log.message,
    metadata: {
      error_type: error_log.error_type,
      platform: error_log.platform,
      environment: error_log.environment
    }
  )
end
```

#### 2. `on_critical_error` - Critical Errors Only

```ruby
RailsErrorDashboard.on_critical_error do |error_log|
  # Called ONLY for critical errors (in addition to on_error_logged)

  # Trigger PagerDuty incident
  PagerDuty.trigger(
    summary: "Critical: #{error_log.error_type}",
    severity: "critical",
    source: error_log.platform,
    custom_details: {
      message: error_log.message,
      backtrace: error_log.backtrace&.lines&.first(5)
    }
  )
end
```

#### 3. `on_error_resolved` - Error Resolved

```ruby
RailsErrorDashboard.on_error_resolved do |error_log|
  # Called when error is marked as resolved

  # Notify team
  Slack.post_message(
    channel: "#engineering",
    text: "✅ Error resolved: #{error_log.error_type}",
    attachments: [{
      fields: [
        { title: "Resolved By", value: error_log.resolved_by_name },
        { title: "Occurrences", value: error_log.occurrence_count },
        { title: "Resolution", value: error_log.resolution_comment }
      ]
    }]
  )
end
```

### Multiple Callbacks

You can register multiple callbacks for the same event:

```ruby
# Callback 1: Log to external service
RailsErrorDashboard.on_error_logged do |error_log|
  Datadog.increment("errors.logged", tags: ["type:#{error_log.error_type}"])
end

# Callback 2: Send to analytics
RailsErrorDashboard.on_error_logged do |error_log|
  Analytics.track_error(error_log)
end

# Both callbacks will execute
```

### Error Handling

Callbacks are fail-safe - if one callback raises an error, it won't break error logging or prevent other callbacks from running:

```ruby
RailsErrorDashboard.on_error_logged do |error_log|
  raise "Callback error"  # Logged as warning, other callbacks still run
end

RailsErrorDashboard.on_error_logged do |error_log|
  puts "This still executes"  # ✓ Runs even if previous callback failed
end
```

### Integration Examples

#### Datadog

```ruby
RailsErrorDashboard.on_error_logged do |error_log|
  Datadog::Statsd.increment("errors.logged",
    tags: [
      "severity:#{error_log.severity}",
      "platform:#{error_log.platform}",
      "environment:#{error_log.environment}"
    ]
  )
end
```

#### Sentry (alongside Error Dashboard)

```ruby
RailsErrorDashboard.on_critical_error do |error_log|
  Sentry.capture_message(
    "Critical Error: #{error_log.error_type}",
    level: :fatal,
    extra: {
      error_id: error_log.id,
      message: error_log.message,
      platform: error_log.platform
    }
  )
end
```

#### Custom Metrics

```ruby
RailsErrorDashboard.on_error_logged do |error_log|
  Prometheus.error_counter.increment(
    labels: {
      type: error_log.error_type,
      severity: error_log.severity,
      platform: error_log.platform
    }
  )
end
```

---

## ActiveSupport Notifications

Rails Error Dashboard emits standard Rails instrumentation events that can be subscribed to using `ActiveSupport::Notifications`.

### Available Events

#### 1. `error_logged.rails_error_dashboard`

Emitted when any error is logged (new errors only, not recurrences).

```ruby
ActiveSupport::Notifications.subscribe("error_logged.rails_error_dashboard") do |name, start, finish, id, payload|
  # Payload contains:
  # - error_log: Full ErrorLog record
  # - error_id: Error ID
  # - error_type: Exception class name
  # - message: Error message
  # - severity: Error severity (:critical, :high, :medium, :low)
  # - platform: Platform (iOS, Android, API)
  # - environment: Rails environment
  # - occurred_at: Timestamp

  duration = finish - start
  StatsD.timing("error_logging.duration", duration)
  StatsD.increment("errors.logged", tags: ["type:#{payload[:error_type]}"])
end
```

#### 2. `critical_error.rails_error_dashboard`

Emitted when a critical error is logged (in addition to `error_logged`).

```ruby
ActiveSupport::Notifications.subscribe("critical_error.rails_error_dashboard") do |name, start, finish, id, payload|
  # Same payload as error_logged

  # Trigger immediate alert
  PagerDuty.trigger_incident(
    title: "Critical Error: #{payload[:error_type]}",
    severity: "critical",
    details: payload[:message]
  )
end
```

#### 3. `error_resolved.rails_error_dashboard`

Emitted when an error is marked as resolved.

```ruby
ActiveSupport::Notifications.subscribe("error_resolved.rails_error_dashboard") do |name, start, finish, id, payload|
  # Payload contains:
  # - error_log: Full ErrorLog record
  # - error_id: Error ID
  # - error_type: Exception class name
  # - resolved_by: Name of person who resolved it
  # - resolved_at: Timestamp

  Analytics.track_resolution(
    error_id: payload[:error_id],
    resolved_by: payload[:resolved_by],
    resolution_time: payload[:resolved_at] - payload[:error_log].occurred_at
  )
end
```

### Using Event Objects

```ruby
ActiveSupport::Notifications.subscribe("error_logged.rails_error_dashboard") do |*args|
  event = ActiveSupport::Notifications::Event.new(*args)

  puts "Event: #{event.name}"
  puts "Duration: #{event.duration}ms"
  puts "Error Type: #{event.payload[:error_type]}"
  puts "Severity: #{event.payload[:severity]}"
end
```

### Wildcard Subscriptions

```ruby
# Subscribe to all Rails Error Dashboard events
ActiveSupport::Notifications.subscribe(/rails_error_dashboard/) do |event|
  Rails.logger.info "Error Dashboard Event: #{event.name}"
end
```

### Integration Examples

#### NewRelic

```ruby
ActiveSupport::Notifications.subscribe("critical_error.rails_error_dashboard") do |*args|
  event = ActiveSupport::Notifications::Event.new(*args)
  NewRelic::Agent.notice_error(
    StandardError.new(event.payload[:message]),
    custom_params: {
      error_id: event.payload[:error_id],
      platform: event.payload[:platform]
    }
  )
end
```

#### Prometheus

```ruby
error_counter = Prometheus::Client::Counter.new(
  :rails_errors_total,
  docstring: "Total number of Rails errors",
  labels: [:type, :severity, :platform]
)

ActiveSupport::Notifications.subscribe("error_logged.rails_error_dashboard") do |*args|
  event = ActiveSupport::Notifications::Event.new(*args)
  error_counter.increment(
    labels: {
      type: event.payload[:error_type],
      severity: event.payload[:severity],
      platform: event.payload[:platform]
    }
  )
end
```

#### Elasticsearch

```ruby
ActiveSupport::Notifications.subscribe("error_logged.rails_error_dashboard") do |*args|
  event = ActiveSupport::Notifications::Event.new(*args)

  Elasticsearch::Client.new.index(
    index: "rails-errors",
    body: {
      timestamp: event.payload[:occurred_at],
      error_type: event.payload[:error_type],
      message: event.payload[:message],
      severity: event.payload[:severity],
      platform: event.payload[:platform],
      environment: event.payload[:environment]
    }
  )
end
```

---

## Async Error Logging (Revisited)

Async logging is available and fully functional. See the [Async Error Logging](#async-error-logging) section above for complete configuration details.

For quick reference:

```ruby
RailsErrorDashboard.configure do |config|
  # Enable async logging
  config.async_logging = true

  # Choose adapter: :sidekiq (default), :solid_queue, or :async
  config.async_adapter = :sidekiq
end
```

---

## Backtrace Configuration

Control how many lines of backtrace are stored:

```ruby
RailsErrorDashboard.configure do |config|
  # Limit backtrace to 50 lines (default)
  config.max_backtrace_lines = 50

  # Store more for detailed debugging
  config.max_backtrace_lines = 100

  # Minimal storage (just the first line)
  config.max_backtrace_lines = 1
end
```

**Benefits:**
- Reduced database storage
- Faster error logging
- Still captures the most relevant stack frames

---

## Complete Configuration Example

Here's a production-ready configuration combining multiple features:

```ruby
# config/initializers/rails_error_dashboard.rb

RailsErrorDashboard.configure do |config|
  # ============================================================================
  # AUTHENTICATION (Always Required)
  # ============================================================================
  # Authentication is always required in all environments
  config.dashboard_username = ENV.fetch("ERROR_DASHBOARD_USER", "gandalf")
  config.dashboard_password = ENV.fetch("ERROR_DASHBOARD_PASSWORD", "youshallnotpass")

  # ============================================================================
  # CORE FEATURES (Always Enabled)
  # ============================================================================
  config.enable_middleware = true
  config.enable_error_subscriber = true
  config.user_model = "User"
  config.retention_days = 90

  # ============================================================================
  # NOTIFICATION SETTINGS
  # ============================================================================

  # Slack Notifications
  config.enable_slack_notifications = true
  config.slack_webhook_url = ENV["SLACK_WEBHOOK_URL"]

  # Email Notifications
  config.enable_email_notifications = true
  config.notification_email_recipients = ENV.fetch("ERROR_NOTIFICATION_EMAILS", "").split(",").map(&:strip)
  config.notification_email_from = ENV.fetch("ERROR_NOTIFICATION_FROM", "errors@example.com")

  # Discord Notifications
  config.enable_discord_notifications = true
  config.discord_webhook_url = ENV["DISCORD_WEBHOOK_URL"]

  # PagerDuty Integration (critical errors only)
  config.enable_pagerduty_notifications = true
  config.pagerduty_integration_key = ENV["PAGERDUTY_INTEGRATION_KEY"]

  # Generic Webhook Notifications
  config.enable_webhook_notifications = true
  config.webhook_urls = ENV.fetch("WEBHOOK_URLS", "").split(",").map(&:strip).reject(&:empty?)

  # Dashboard base URL (used in notification links)
  config.dashboard_base_url = ENV["DASHBOARD_BASE_URL"]

  # ============================================================================
  # PERFORMANCE & SCALABILITY
  # ============================================================================

  # Async Error Logging
  config.async_logging = true
  config.async_adapter = :sidekiq  # Options: :sidekiq, :solid_queue, :async

  # Backtrace size limiting
  config.max_backtrace_lines = 50

  # Error Sampling (10% - critical errors ALWAYS logged)
  config.sampling_rate = 0.1

  # Ignored exceptions
  config.ignored_exceptions = [
    "ActionController::RoutingError",
    "ActionController::InvalidAuthenticityToken",
    /^ActiveRecord::RecordNotFound/
  ]

  # ============================================================================
  # DATABASE CONFIGURATION
  # ============================================================================
  config.use_separate_database = false

  # ============================================================================
  # ADVANCED ANALYTICS
  # ============================================================================

  # Baseline Anomaly Alerts
  config.enable_baseline_alerts = true
  config.baseline_alert_threshold_std_devs = 2.0
  config.baseline_alert_severities = [:critical, :high]
  config.baseline_alert_cooldown_minutes = 120

  # Fuzzy Error Matching
  config.enable_similar_errors = true

  # Co-occurring Errors
  config.enable_co_occurring_errors = true

  # Error Cascade Detection
  config.enable_error_cascades = true

  # Error Correlation Analysis
  config.enable_error_correlation = true

  # Platform Comparison
  config.enable_platform_comparison = true

  # Occurrence Pattern Detection
  config.enable_occurrence_patterns = true

  # ============================================================================
  # SOURCE CODE INTEGRATION (NEW!)
  # ============================================================================

  # Enable source code viewer
  config.enable_source_code_integration = true

  # Context lines around error (default: 5)
  config.source_code_context_lines = 5

  # Enable git blame integration
  config.enable_git_blame = true

  # Cache TTL in seconds (default: 3600 = 1 hour)
  config.source_code_cache_ttl = 3600

  # Security: only show app code (default: true)
  config.only_show_app_code_source = true

  # Branch strategy for repository links (default: :commit_sha)
  config.git_branch_strategy = :commit_sha

  # ============================================================================
  # BREADCRUMBS (NEW!)
  # ============================================================================

  # Enable breadcrumbs (request activity trail)
  config.enable_breadcrumbs = true

  # Max events per request (default: 40)
  config.breadcrumb_buffer_size = 40

  # Capture all categories (default: nil = all)
  # config.breadcrumb_categories = [:sql, :controller, :cache, :job, :mailer, :custom]

  # ============================================================================
  # SYSTEM HEALTH SNAPSHOT (NEW!)
  # ============================================================================

  # Capture GC, memory, threads, connection pool, RubyVM, YJIT at error time
  config.enable_system_health = true

  # ============================================================================
  # DEEP DEBUGGING (v0.4.0)
  # ============================================================================

  # Local variable capture via TracePoint(:raise)
  config.enable_local_variables = true
  config.local_variable_max_count = 15
  config.local_variable_max_depth = 3
  config.local_variable_max_string_length = 200

  # Instance variable capture from raising object
  config.enable_instance_variables = true
  config.instance_variable_max_count = 20

  # Swallowed exception detection (Ruby 3.3+ required)
  config.detect_swallowed_exceptions = true
  config.swallowed_exception_threshold = 0.95

  # On-demand diagnostic dump
  config.enable_diagnostic_dump = true

  # Rack Attack event tracking (requires breadcrumbs)
  config.enable_rack_attack_tracking = true

  # Process crash capture via at_exit hook
  config.enable_crash_capture = true
  # config.crash_capture_path = "/var/log/myapp/crashes"  # default: Dir.tmpdir

  # ============================================================================
  # ADDITIONAL CONFIGURATION
  # ============================================================================

  # Custom severity rules
  config.custom_severity_rules = {
    "PaymentError" => :critical,
    "ValidationError" => :low
  }

  # Enhanced metrics
  config.app_version = ENV["APP_VERSION"]
  config.git_sha = ENV["GIT_SHA"]
  # config.total_users_for_impact = 10000  # For user impact % calculation
end

# ============================================================================
# NOTIFICATION CALLBACKS
# ============================================================================

# Alert on critical errors
RailsErrorDashboard.on_critical_error do |error_log|
  PagerDuty.trigger(
    summary: "Critical: #{error_log.error_type}",
    severity: "critical",
    source: error_log.platform
  )
end

# Track metrics
RailsErrorDashboard.on_error_logged do |error_log|
  StatsD.increment("errors.logged",
    tags: [
      "type:#{error_log.error_type}",
      "severity:#{error_log.severity}",
      "platform:#{error_log.platform}"
    ]
  )
end

# Notify on resolution
RailsErrorDashboard.on_error_resolved do |error_log|
  Slack.post_message(
    channel: "#engineering",
    text: "✅ #{error_log.error_type} resolved by #{error_log.resolved_by_name}"
  )
end

# ============================================================================
# ACTIVESUPPORT NOTIFICATIONS
# ============================================================================

# Send to external logging service
ActiveSupport::Notifications.subscribe("error_logged.rails_error_dashboard") do |*args|
  event = ActiveSupport::Notifications::Event.new(*args)

  Elasticsearch::Client.new.index(
    index: "rails-errors",
    body: {
      timestamp: event.payload[:occurred_at],
      error_type: event.payload[:error_type],
      message: event.payload[:message],
      severity: event.payload[:severity],
      platform: event.payload[:platform]
    }
  )
end
```

---

## Environment-Specific Configuration

Configure differently per environment:

```ruby
RailsErrorDashboard.configure do |config|
  # Common configuration
  config.user_model = "User"
  config.max_backtrace_lines = 50

  if Rails.env.production?
    # Production: Aggressive sampling, strict filtering
    config.sampling_rate = 0.1
    config.ignored_exceptions = [
      "ActionController::RoutingError",
      /ActionController::InvalidAuthenticityToken/
    ]

  elsif Rails.env.staging?
    # Staging: Moderate sampling
    config.sampling_rate = 0.5

  else
    # Development/Test: Log everything
    config.sampling_rate = 1.0
    config.ignored_exceptions = []
  end
end
```

---

## Troubleshooting

### Configuration Not Taking Effect

**Problem**: Changes to `config/initializers/rails_error_dashboard.rb` don't seem to work.

**Solutions**:
1. **Restart server** - Configuration is loaded at startup
   ```bash
   rails server
   ```

2. **Check file location** - Must be in `config/initializers/`
   ```bash
   ls -la config/initializers/rails_error_dashboard.rb
   ```

3. **Check for syntax errors**
   ```bash
   ruby -c config/initializers/rails_error_dashboard.rb
   ```

4. **Verify configuration is loaded**
   ```ruby
   # In rails console
   RailsErrorDashboard.configuration.inspect
   ```

### Environment Variables Not Working

**Problem**: `ENV['VARIABLE']` returns `nil` in configuration.

**Solutions**:
1. **Load environment variables before Rails**
   - Use `dotenv-rails` gem for development
   - Use system environment variables in production

2. **Check variable is set**
   ```bash
   echo $SLACK_WEBHOOK_URL
   ```

3. **Provide defaults**
   ```ruby
   config.slack_webhook_url = ENV.fetch('SLACK_WEBHOOK_URL', nil)
   ```

### Notifications Not Sending

**Problem**: Slack/Discord notifications aren't working.

**Solutions**:
1. **Check notifications are enabled**
   ```ruby
   # In rails console
   RailsErrorDashboard.configuration.enable_slack_notifications
   # Should return true
   ```

2. **Verify webhook URL is set**
   ```ruby
   RailsErrorDashboard.configuration.slack_webhook_url
   # Should return your webhook URL
   ```

3. **Test webhook manually**
   ```bash
   curl -X POST YOUR_WEBHOOK_URL \
     -H 'Content-Type: application/json' \
     -d '{"text": "Test message"}'
   ```

4. **Check background jobs are running**
   ```bash
   # With Sidekiq
   bundle exec sidekiq

   # With Solid Queue
   bin/jobs
   ```

5. **Check notification thresholds**
   ```ruby
   # Critical errors only go to PagerDuty
   config.severity_thresholds[:pagerduty] = :critical
   ```

### Custom Severity Rules Not Working

**Problem**: Custom severity rules aren't being applied.

**Solutions**:
1. **Check rule format** - Use regex or symbol
   ```ruby
   # Correct
   config.custom_severity_rules = {
     /ActiveRecord::RecordNotFound/ => :low,
     :timeout_error => :high
   }

   # Incorrect (string won't match)
   config.custom_severity_rules = {
     "ActiveRecord::RecordNotFound" => :low
   }
   ```

2. **Test regex patterns**
   ```ruby
   # In rails console
   error_class = "ActiveRecord::RecordNotFound"
   /ActiveRecord::RecordNotFound/.match?(error_class)
   # Should return true
   ```

3. **Check rule order** - First match wins
   ```ruby
   # More specific rules should come first
   config.custom_severity_rules = {
     /ActiveRecord::RecordNotFound.*User/ => :high,  # Specific
     /ActiveRecord::RecordNotFound/ => :low          # General
   }
   ```

### Background Jobs Not Processing

**Problem**: Async logging enabled but errors not appearing.

**Solutions**:
1. **Check job adapter configuration**
   ```ruby
   # In rails console
   RailsErrorDashboard.configuration.async_adapter
   # Should return :sidekiq, :solid_queue, or :async
   ```

2. **Verify job processor is running**
   ```bash
   # Sidekiq
   ps aux | grep sidekiq

   # Solid Queue
   ps aux | grep solid_queue
   ```

3. **Check failed jobs**
   ```ruby
   # Sidekiq
   require 'sidekiq/api'
   Sidekiq::RetrySet.new.size
   Sidekiq::DeadSet.new.size

   # Solid Queue
   SolidQueue::Job.failed.count
   ```

4. **Test with sync logging temporarily**
   ```ruby
   config.async_logging = false  # For debugging
   ```

### Sampling Too Aggressive

**Problem**: Too many errors being filtered out.

**Solutions**:
1. **Check sampling rate**
   ```ruby
   RailsErrorDashboard.configuration.sampling_rate
   # 0.1 = 10% of errors logged
   ```

2. **Critical errors always logged** - Check severity
   ```ruby
   # Critical errors bypass sampling
   config.severity_thresholds[:critical]
   ```

3. **Adjust rate** - Start higher, tune down
   ```ruby
   config.sampling_rate = 0.5  # Start with 50%
   ```

4. **Use conditional sampling**
   ```ruby
   config.before_log_callback = lambda do |exception, context|
     # Always log payment errors
     return true if exception.message.include?("Stripe")

     # Sample others based on environment
     Rails.env.production? ? rand < 0.1 : true
   end
   ```

### Database Performance Issues

**Problem**: Error logging is slow or causing database issues.

**Solutions**:
1. **Enable async logging**
   ```ruby
   config.async_logging = true
   ```

2. **Use separate database**
   ```ruby
   config.database = :errors
   ```

3. **Add database indexes** - Already included in migrations

4. **Increase backtrace limit**
   ```ruby
   config.max_backtrace_lines = 20  # Default is 50
   ```

5. **Configure retention policy**
   ```ruby
   config.retention_days = 30  # Auto-cleanup old errors
   ```

See [Database Optimization Guide](/rails_error_dashboard/docs/guides/database-optimization/) for more.

### Authentication Not Working

**Problem**: Can't access dashboard even with correct credentials.

**Solutions**:
1. **Check username and password are set**
   ```ruby
   # In rails console
   RailsErrorDashboard.configuration.dashboard_username
   RailsErrorDashboard.configuration.dashboard_password
   ```

2. **Verify HTTP Basic Auth is configured**
   ```ruby
   config.dashboard_username = "admin"
   config.dashboard_password = "secure_password"
   ```

3. **Test credentials**
   ```bash
   curl -u admin:password http://localhost:3000/red
   ```

4. **Check for proxy/load balancer issues**
   - Some proxies strip Authorization headers
   - May need to configure pass-through

5. **Clear browser cache** - Old credentials may be cached

### Multi-App Configuration Issues

**Problem**: Errors from multiple apps not showing correctly.

**Solutions**:
1. **Set APP_NAME environment variable**
   ```bash
   APP_NAME=my-api rails server
   ```

2. **Or configure manually**
   ```ruby
   config.application_name = "my-api"
   ```

3. **Verify application is created**
   ```ruby
   # In rails console
   RailsErrorDashboard::Application.all.pluck(:name)
   ```

4. **Check errors are tagged correctly**
   ```ruby
   RailsErrorDashboard::ErrorLog.last.application.name
   ```

See [Multi-App Support Guide](/rails_error_dashboard/docs/features/multi-app-performance/) for more.

---

## Resetting Configuration

For testing or dynamic reconfiguration:

```ruby
# Reset to defaults
RailsErrorDashboard.reset_configuration!

# Reconfigure
RailsErrorDashboard.configure do |config|
  config.sampling_rate = 1.0
end
```

---

## Next Steps

- **Testing**: Write tests for your custom callbacks and severity rules
- **Monitoring**: Set up ActiveSupport::Notifications subscribers for your metrics service
- **Optimization**: Review database optimization and performance tuning guides

For questions or issues, visit: https://github.com/AnjanJ/rails_error_dashboard
