Files
flyer-crawler.projectium.com/docs/tools/BUGSINK-SETUP.md
Torben Sorensen 4f06698dfd
Some checks failed
Deploy to Test Environment / deploy-to-test (push) Failing after 2m50s
test fixes and doc work
2026-01-28 15:33:48 -08:00

1036 lines
32 KiB
Markdown

# Bugsink Error Tracking Setup and Usage Guide
This document covers the complete setup and usage of Bugsink for error tracking in the Flyer Crawler application.
## Table of Contents
- [What is Bugsink](#what-is-bugsink)
- [Environments](#environments)
- [Token Creation](#token-creation)
- [MCP Integration](#mcp-integration)
- [Application Integration](#application-integration)
- [Logstash Integration](#logstash-integration)
- [Using Bugsink](#using-bugsink)
- [Common Workflows](#common-workflows)
- [Troubleshooting](#troubleshooting)
---
## What is Bugsink
Bugsink is a lightweight, self-hosted error tracking platform that is fully compatible with the Sentry SDK ecosystem. We use Bugsink instead of Sentry SaaS or self-hosted Sentry for several reasons:
| Aspect | Bugsink | Self-Hosted Sentry |
| ----------------- | -------------------------- | -------------------------------- |
| Resource Usage | Single process, ~256MB RAM | 16GB+ RAM, Kafka, ClickHouse |
| Deployment | Simple pip/binary install | Docker Compose with 20+ services |
| SDK Compatibility | Full Sentry SDK support | Full Sentry SDK support |
| Database | PostgreSQL or SQLite | PostgreSQL + ClickHouse |
| Cost | Free, self-hosted | Free, self-hosted |
| Maintenance | Minimal | Significant |
**Key Benefits:**
1. **Sentry SDK Compatibility**: Uses the same `@sentry/node` and `@sentry/react` SDKs as Sentry
2. **Self-Hosted**: All error data stays on our infrastructure
3. **Lightweight**: Runs alongside the application without significant overhead
4. **MCP Integration**: AI tools (Claude Code) can query errors via the bugsink-mcp server
**Architecture Decision**: See [ADR-015: Application Performance Monitoring and Error Tracking](../adr/0015-application-performance-monitoring-and-error-tracking.md) for the full rationale.
---
## Environments
### Dev Container (Local Development)
| Item | Value |
| ---------------- | ----------------------------------------------------------------- |
| Web UI | `https://localhost:8443` (nginx proxy) |
| Internal URL | `http://localhost:8000` (direct) |
| Credentials | `admin@localhost` / `admin` |
| Backend Project | Project ID 1 - `Backend API (Dev)` |
| Frontend Project | Project ID 2 - `Frontend (Dev)` |
| Infra Project | Project ID 4 - `Infrastructure (Dev)` |
| Backend DSN | `http://<key>@localhost:8000/1` |
| Frontend DSN | `https://<key>@localhost/bugsink-api/2` (via nginx proxy) |
| Infra DSN | `http://<key>@localhost:8000/4` (Logstash only) |
| Database | `postgresql://bugsink:bugsink_dev_password@postgres:5432/bugsink` |
**Important:** The Frontend DSN uses an nginx proxy (`/bugsink-api/`) because the browser cannot reach `localhost:8000` directly (container-internal port). See [Frontend Nginx Proxy](#frontend-nginx-proxy) for details.
**Configuration Files:**
| File | Purpose |
| ------------------------------ | ------------------------------------------------------- |
| `compose.dev.yml` | Initial DSNs using `127.0.0.1:8000` (container startup) |
| `.env.local` | **OVERRIDES** compose.dev.yml (app runtime) |
| `docker/nginx/dev.conf` | Nginx proxy for Bugsink API (frontend error reporting) |
| `docker/logstash/bugsink.conf` | Log routing to Backend/Infrastructure projects |
**Note:** `.env.local` takes precedence over `compose.dev.yml` environment variables.
### Production
| Item | Value |
| ---------------- | --------------------------------------- |
| Web UI | `https://bugsink.projectium.com` |
| Credentials | Managed separately (not shared in docs) |
| Backend Project | `flyer-crawler-backend` |
| Frontend Project | `flyer-crawler-frontend` |
| Infra Project | `flyer-crawler-infrastructure` |
**Bugsink Projects:**
| Project Slug | Type | Environment |
| --------------------------------- | -------- | ----------- |
| flyer-crawler-backend | Backend | Production |
| flyer-crawler-backend-test | Backend | Test |
| flyer-crawler-frontend | Frontend | Production |
| flyer-crawler-frontend-test | Frontend | Test |
| flyer-crawler-infrastructure | Infra | Production |
| flyer-crawler-test-infrastructure | Infra | Test |
---
## Token Creation
Bugsink 2.0.11 does **NOT** have a "Settings > API Keys" menu in the UI. API tokens must be created via Django management command.
### Dev Container Token
Run this command from the Windows host (Git Bash or PowerShell):
```bash
MSYS_NO_PATHCONV=1 podman exec -e DATABASE_URL=postgresql://bugsink:bugsink_dev_password@postgres:5432/bugsink -e SECRET_KEY=dev-bugsink-secret-key-minimum-50-characters-for-security flyer-crawler-dev sh -c 'cd /opt/bugsink/conf && DJANGO_SETTINGS_MODULE=bugsink_conf PYTHONPATH=/opt/bugsink/conf:/opt/bugsink/lib/python3.10/site-packages /opt/bugsink/bin/python -m django create_auth_token'
```
**Output:** A 40-character lowercase hex token (e.g., `a609c2886daa4e1e05f1517074d7779a5fb49056`)
### Production Token
User executes this command on the production server:
```bash
cd /opt/bugsink && bugsink-manage create_auth_token
```
**Output:** Same format - 40-character hex token.
### Token Storage
| Environment | Storage Location | Notes |
| ----------- | ----------------------------- | ---------------------- |
| Dev | `.mcp.json` (project-level) | Not committed to git |
| Production | Gitea secrets + settings.json | `BUGSINK_TOKEN` secret |
---
## MCP Integration
The bugsink-mcp server allows Claude Code and other AI tools to query Bugsink for error information.
### Installation
```bash
# Clone the MCP server
cd d:\gitea
git clone https://github.com/j-shelfwood/bugsink-mcp.git
cd bugsink-mcp
npm install
npm run build
```
### Configuration
**IMPORTANT:** Localhost MCP servers must use project-level `.mcp.json` due to a known Claude Code loader issue. See [BUGSINK-MCP-TROUBLESHOOTING.md](../BUGSINK-MCP-TROUBLESHOOTING.md) for details.
#### Production (Global settings.json)
Location: `~/.claude/settings.json` (or `C:\Users\<username>\.claude\settings.json`)
```json
{
"mcpServers": {
"bugsink": {
"command": "node",
"args": ["d:\\gitea\\bugsink-mcp\\dist\\index.js"],
"env": {
"BUGSINK_URL": "https://bugsink.projectium.com",
"BUGSINK_TOKEN": "<40-char-hex-token>"
}
}
}
}
```
#### Dev Container (Project-level .mcp.json)
Location: Project root `.mcp.json`
```json
{
"mcpServers": {
"localerrors": {
"command": "node",
"args": ["d:\\gitea\\bugsink-mcp\\dist\\index.js"],
"env": {
"BUGSINK_URL": "http://127.0.0.1:8000",
"BUGSINK_TOKEN": "<40-char-hex-token>"
}
}
}
}
```
### Environment Variables
The bugsink-mcp package requires exactly TWO environment variables:
| Variable | Description | Required |
| --------------- | ----------------------- | -------- |
| `BUGSINK_URL` | Bugsink instance URL | Yes |
| `BUGSINK_TOKEN` | API token (40-char hex) | Yes |
**Common Mistakes:**
- Using `BUGSINK_API_TOKEN` (wrong - use `BUGSINK_TOKEN`)
- Including `BUGSINK_ORG_SLUG` (not used by the package)
### Available MCP Tools
| Tool | Purpose |
| ----------------- | ------------------------------------ |
| `test_connection` | Verify MCP server can reach Bugsink |
| `list_projects` | List all projects in the instance |
| `get_project` | Get project details including DSN |
| `list_issues` | List issues for a project |
| `get_issue` | Get detailed issue information |
| `list_events` | List individual error occurrences |
| `get_event` | Get full event details with context |
| `get_stacktrace` | Get pre-rendered Markdown stacktrace |
| `list_releases` | List releases for a project |
| `create_release` | Create a new release |
**Tool Prefixes:**
- Production: `mcp__bugsink__*`
- Dev Container: `mcp__localerrors__*`
### Verifying MCP Connection
After configuration, restart Claude Code and test:
```typescript
// Production
mcp__bugsink__test_connection();
// Expected: "Connection successful: Connected successfully. Found N project(s)."
// Dev Container
mcp__localerrors__test_connection();
// Expected: "Connection successful: Connected successfully. Found N project(s)."
```
---
## Application Integration
### Backend (Express/Node.js)
**File:** `src/services/sentry.server.ts`
The backend uses `@sentry/node` SDK v8+ to capture errors:
```typescript
import * as Sentry from '@sentry/node';
import { config, isSentryConfigured, isProduction, isTest } from '../config/env';
export function initSentry(): void {
if (!isSentryConfigured || isTest) return;
Sentry.init({
dsn: config.sentry.dsn,
environment: config.sentry.environment || config.server.nodeEnv,
debug: config.sentry.debug,
tracesSampleRate: 0, // Performance monitoring disabled
beforeSend(event, hint) {
// Custom filtering logic
return event;
},
});
}
```
**Key Functions:**
| Function | Purpose |
| ----------------------- | -------------------------------------------- |
| `initSentry()` | Initialize SDK at application startup |
| `captureException()` | Manually capture caught errors |
| `captureMessage()` | Log non-exception events |
| `setUser()` | Set user context after authentication |
| `addBreadcrumb()` | Add navigation/action breadcrumbs |
| `getSentryMiddleware()` | Get Express middleware for automatic capture |
**Integration in server.ts:**
```typescript
// At the very top of server.ts, before other imports
import { initSentry, getSentryMiddleware } from './services/sentry.server';
initSentry();
// After Express app creation
const { requestHandler, errorHandler } = getSentryMiddleware();
app.use(requestHandler);
// ... routes ...
// Before final error handler
app.use(errorHandler);
```
### Frontend (React)
**File:** `src/services/sentry.client.ts`
The frontend uses `@sentry/react` SDK:
```typescript
import * as Sentry from '@sentry/react';
import config from '../config';
export function initSentry(): void {
if (!config.sentry.dsn || !config.sentry.enabled) return;
Sentry.init({
dsn: config.sentry.dsn,
environment: config.sentry.environment,
debug: config.sentry.debug,
tracesSampleRate: 0,
integrations: [
Sentry.breadcrumbsIntegration({
console: true,
dom: true,
fetch: true,
history: true,
xhr: true,
}),
],
beforeSend(event) {
// Filter browser extension errors
if (
event.exception?.values?.[0]?.stacktrace?.frames?.some((frame) =>
frame.filename?.includes('extension://'),
)
) {
return null;
}
return event;
},
});
}
```
**Client Configuration (src/config.ts):**
```typescript
const config = {
sentry: {
dsn: import.meta.env.VITE_SENTRY_DSN,
environment: import.meta.env.VITE_SENTRY_ENVIRONMENT || import.meta.env.MODE,
debug: import.meta.env.VITE_SENTRY_DEBUG === 'true',
enabled: import.meta.env.VITE_SENTRY_ENABLED !== 'false',
},
};
```
### Environment Variables
**Backend (src/config/env.ts):**
| Variable | Description | Default |
| -------------------- | ------------------------------ | ---------- |
| `SENTRY_DSN` | Sentry-compatible DSN | (optional) |
| `SENTRY_ENABLED` | Enable/disable error reporting | `true` |
| `SENTRY_ENVIRONMENT` | Environment tag | NODE_ENV |
| `SENTRY_DEBUG` | Enable SDK debug logging | `false` |
**Frontend (Vite):**
| Variable | Description |
| ------------------------- | ------------------------------- |
| `VITE_SENTRY_DSN` | Frontend DSN (separate project) |
| `VITE_SENTRY_ENVIRONMENT` | Environment tag |
| `VITE_SENTRY_DEBUG` | Enable SDK debug logging |
| `VITE_SENTRY_ENABLED` | Enable/disable error reporting |
---
## Frontend Nginx Proxy
The frontend Sentry SDK runs in the browser, which cannot directly reach `localhost:8000` (the Bugsink container-internal port). To solve this, we use an nginx proxy.
### How It Works
```text
Browser --HTTPS--> https://localhost/bugsink-api/2/store/
|
v (nginx proxy)
http://localhost:8000/api/2/store/
|
v
Bugsink (internal)
```
### Nginx Configuration
Location: `docker/nginx/dev.conf`
```nginx
# Proxy Bugsink Sentry API for frontend error reporting
location /bugsink-api/ {
proxy_pass http://localhost:8000/api/;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# Allow large error payloads with stack traces
client_max_body_size 10M;
# Timeouts for error reporting
proxy_connect_timeout 10s;
proxy_send_timeout 30s;
proxy_read_timeout 30s;
}
```
### Frontend DSN Format
```bash
# .env.local
# Uses nginx proxy path instead of direct port
VITE_SENTRY_DSN=https://<key>@localhost/bugsink-api/2
```
### Testing Frontend Error Reporting
1. Open browser console at `https://localhost`
2. Trigger a test error:
```javascript
throw new Error('Test frontend error from browser');
```
3. Check Bugsink Frontend (Dev) project for the error
4. Verify browser console shows Sentry SDK activity (if VITE_SENTRY_DEBUG=true)
---
## Logstash Integration
Logstash aggregates logs from multiple sources and forwards error patterns to Bugsink.
**Note:** See [ADR-015](../adr/0015-application-performance-monitoring-and-error-tracking.md) for the full architecture.
### 3-Project Architecture
Logstash routes errors to different Bugsink projects based on log source:
| Project | ID | Receives |
| -------------------- | --- | --------------------------------------------- |
| Backend API (Dev) | 1 | Pino app errors, PostgreSQL errors |
| Frontend (Dev) | 2 | Browser errors (via Sentry SDK, not Logstash) |
| Infrastructure (Dev) | 4 | Redis warnings, NGINX errors, Vite errors |
### Log Sources
| Source | Log Path | Project Destination | Error Detection |
| ---------- | --------------------------- | ------------------- | ------------------------- |
| PM2 API | `/var/log/pm2/api-*.log` | Backend (1) | level >= 50 (error/fatal) |
| PM2 Worker | `/var/log/pm2/worker-*.log` | Backend (1) | level >= 50 (error/fatal) |
| PM2 Vite | `/var/log/pm2/vite-*.log` | Infrastructure (4) | error keyword patterns |
| PostgreSQL | `/var/log/postgresql/*.log` | Backend (1) | ERROR/FATAL log levels |
| Redis | `/var/log/redis/*.log` | Infrastructure (4) | WARNING level (`#`) |
| NGINX | `/var/log/nginx/error.log` | Infrastructure (4) | error/crit/alert/emerg |
### Pipeline Configuration
**Location:** `/etc/logstash/conf.d/bugsink.conf` (or `docker/logstash/bugsink.conf` in project)
The configuration:
1. **Inputs**: Reads from PM2 logs, PostgreSQL logs, Redis logs, NGINX logs
2. **Filters**: Detects errors and assigns tags based on log type
3. **Outputs**: Routes to appropriate Bugsink project based on log source
**Key Routing Logic:**
```ruby
# Infrastructure logs -> Project 4
if "error" in [tags] and ([type] == "redis" or [type] == "nginx_error" or [type] == "pm2_vite") {
http { url => "http://localhost:8000/api/4/store/" ... }
}
# Backend logs -> Project 1
else if "error" in [tags] and ([type] in ["pm2_api", "pm2_worker", "pino", "postgres"]) {
http { url => "http://localhost:8000/api/1/store/" ... }
}
```
### Benefits
1. **Separation of Concerns**: Application errors separate from infrastructure issues
2. **Secondary Capture Path**: Catches errors before SDK initialization
3. **Log-Based Errors**: Captures errors that don't throw exceptions
4. **Infrastructure Monitoring**: Redis, NGINX, build tooling issues
5. **Historical Analysis**: Process existing log files
---
## Using Bugsink
### Accessing the Web UI
**Dev Container:**
1. Open `https://localhost:8443` in your browser
2. Accept the self-signed certificate warning
3. Login with `admin@localhost` / `admin`
**Production:**
1. Open `https://bugsink.projectium.com`
2. Login with your credentials
### Projects and Teams
Bugsink organizes errors into projects:
| Concept | Description |
| ------- | ---------------------------------------------- |
| Team | Group of projects (e.g., "Flyer Crawler") |
| Project | Single application/service |
| DSN | Data Source Name - unique key for each project |
To view projects:
1. Click the project dropdown in the top navigation
2. Or use MCP: `mcp__bugsink__list_projects()`
### Viewing Issues
**Issues** represent grouped error occurrences. Multiple identical errors are deduplicated into a single issue.
**Issue List View:**
- Navigate to a project
- Issues are sorted by last occurrence
- Each issue shows: title, count, first/last seen
**Issue Detail View:**
- Click an issue to see full details
- View aggregated statistics
- See list of individual events
- Access full stacktrace
### Viewing Events
**Events** are individual error occurrences.
**Event Information:**
- Full stacktrace
- Request context (URL, method, headers)
- User context (if set)
- Breadcrumbs (actions leading to error)
- Tags and extra data
**Via MCP:**
```typescript
// List events for an issue
mcp__bugsink__list_events({ issue_id: 'uuid-here' });
// Get full event details
mcp__bugsink__get_event({ event_id: 'uuid-here' });
// Get readable stacktrace
mcp__bugsink__get_stacktrace({ event_id: 'uuid-here' });
```
### Stacktraces and Context
Stacktraces show the call stack at the time of error:
**Via Web UI:**
- Open an event
- Expand the "Exception" section
- Click frames to see source code context
**Via MCP:**
- `get_stacktrace` returns pre-rendered Markdown
- Includes file paths, line numbers, function names
### Filtering and Searching
**Web UI Filters:**
- By status: unresolved, resolved, muted
- By date range
- By release version
- By environment
**MCP Filtering:**
```typescript
// Filter by status
mcp__bugsink__list_issues({
project_id: 1,
status: 'unresolved',
limit: 25,
});
// Sort options
mcp__bugsink__list_issues({
project_id: 1,
sort: 'last_seen', // or "digest_order"
order: 'desc', // or "asc"
});
```
### Release Tracking
Releases help identify which version introduced or fixed issues.
**Creating Releases:**
```typescript
mcp__bugsink__create_release({
project_id: 1,
version: '1.2.3',
});
```
**Viewing Releases:**
```typescript
mcp__bugsink__list_releases({ project_id: 1 });
```
---
## Common Workflows
### Investigating Production Errors
1. **Check for new errors** (via MCP):
```typescript
mcp__bugsink__list_issues({
project_id: 1,
status: 'unresolved',
sort: 'last_seen',
limit: 10,
});
```
2. **Get issue details**:
```typescript
mcp__bugsink__get_issue({ issue_id: 'uuid' });
```
3. **View stacktrace**:
```typescript
mcp__bugsink__list_events({ issue_id: 'uuid', limit: 1 });
mcp__bugsink__get_stacktrace({ event_id: 'event-uuid' });
```
4. **Examine the code**: Use the file path and line numbers from the stacktrace to locate the issue in the codebase.
### Tracking Down Bugs
1. **Identify error patterns**:
- Group similar errors by message or location
- Check occurrence counts and frequency
2. **Examine request context**:
```typescript
mcp__bugsink__get_event({ event_id: 'uuid' });
```
Look for: URL, HTTP method, request body, user info
3. **Review breadcrumbs**: Understand the sequence of actions leading to the error.
4. **Correlate with logs**: Use the request ID from the event to search application logs.
### Monitoring Error Rates
1. **Check issue counts**: Compare event counts over time
2. **Watch for regressions**: Resolved issues that reopen
3. **Track new issues**: Filter by "first seen" date
### Dev Container Debugging
1. **Access local Bugsink**: `https://localhost:8443`
2. **Trigger a test error**:
```bash
curl -X POST http://localhost:3001/api/test/error
```
3. **View in Bugsink**: Check the dev project for the captured error
4. **Query via MCP**:
```typescript
mcp__localerrors__list_issues({ project_id: 1 });
```
---
## Troubleshooting
### MCP Server Not Available
**Symptoms:**
- `mcp__localerrors__*` tools return "No such tool available"
- `mcp__bugsink__*` works but `mcp__localerrors__*` fails
**Solutions:**
1. **Check configuration location**: Localhost servers must use project-level `.mcp.json`, not global settings.json
2. **Verify token variable name**: Use `BUGSINK_TOKEN`, not `BUGSINK_API_TOKEN`
3. **Test manually**:
```bash
cd d:\gitea\bugsink-mcp
set BUGSINK_URL=http://localhost:8000
set BUGSINK_TOKEN=<your-token>
node dist/index.js
```
Expected: `Bugsink MCP server started`
4. **Full restart**: Close VS Code completely, restart
See [BUGSINK-MCP-TROUBLESHOOTING.md](../BUGSINK-MCP-TROUBLESHOOTING.md) for detailed troubleshooting.
### Connection Refused to localhost:8000
**Cause:** Dev container Bugsink service not running
**Solutions:**
1. **Check container status**:
```bash
podman exec flyer-crawler-dev systemctl status bugsink
```
2. **Start the service**:
```bash
podman exec flyer-crawler-dev systemctl start bugsink
```
3. **Check logs**:
```bash
podman exec flyer-crawler-dev journalctl -u bugsink -n 50
```
### Errors Not Appearing in Bugsink
**Backend:**
1. **Check DSN**: Verify `SENTRY_DSN` environment variable is set
2. **Check enabled flag**: `SENTRY_ENABLED` should be `true`
3. **Check test environment**: Sentry is disabled in `NODE_ENV=test`
**Frontend:**
1. **Check Vite env**: `VITE_SENTRY_DSN` must be set
2. **Verify initialization**: Check browser console for Sentry init message
3. **Check filtering**: `beforeSend` may be filtering the error
### HTTPS Certificate Warnings
**Dev Container:** Self-signed certificates are expected. Accept the warning.
**Production:** Should use valid certificates. If warnings appear, check certificate expiration.
### Token Invalid or Expired
**Symptoms:** MCP returns authentication errors
**Solutions:**
1. **Regenerate token**: Use Django management command (see [Token Creation](#token-creation))
2. **Update configuration**: Put new token in `.mcp.json` or `settings.json`
3. **Restart Claude Code**: Required after config changes
### Bugsink Database Issues
**Symptoms:** 500 errors in Bugsink UI, connection refused
**Dev Container:**
```bash
# Check PostgreSQL
podman exec flyer-crawler-dev pg_isready -U bugsink -d bugsink -h postgres
# Check database exists
podman exec flyer-crawler-dev psql -U postgres -h postgres -c "\l" | grep bugsink
```
**Production** (user executes on server):
```bash
cd /opt/bugsink && bugsink-manage check
```
### PostgreSQL Sequence Out of Sync (Duplicate Key Errors)
**Symptoms:**
- Bugsink throws `duplicate key value violates unique constraint "projects_project_pkey"`
- Error detail shows: `Key (id)=(1) already exists`
- New projects or other entities fail to create
**Root Cause:**
PostgreSQL sequences can become out of sync with actual data after:
- Manual data insertion or database seeding
- Restoring from backup
- Copying data between environments
The sequence generates IDs that already exist in the table.
**Diagnosis:**
```bash
# Dev Container - Check sequence vs max ID
podman exec flyer-crawler-dev psql -U bugsink -h postgres -d bugsink -c "
SELECT
(SELECT MAX(id) FROM projects_project) as max_id,
(SELECT last_value FROM projects_project_id_seq) as seq_last_value,
CASE
WHEN (SELECT MAX(id) FROM projects_project) <= (SELECT last_value FROM projects_project_id_seq)
THEN 'OK'
ELSE 'OUT OF SYNC - Needs reset'
END as status;
"
# Production (user executes on server)
cd /opt/bugsink && bugsink-manage dbshell
# Then run: SELECT MAX(id) as max_id, (SELECT last_value FROM projects_project_id_seq) as seq_value FROM projects_project;
```
**Solution:**
Reset the sequence to the maximum existing ID:
```bash
# Dev Container
podman exec flyer-crawler-dev psql -U bugsink -h postgres -d bugsink -c "
SELECT setval('projects_project_id_seq', COALESCE((SELECT MAX(id) FROM projects_project), 1), true);
"
# Production (user executes on server)
cd /opt/bugsink && bugsink-manage dbshell
# Then run: SELECT setval('projects_project_id_seq', COALESCE((SELECT MAX(id) FROM projects_project), 1), true);
```
**Verification:**
After running the fix, verify:
```bash
# Next ID should be max_id + 1
podman exec flyer-crawler-dev psql -U bugsink -h postgres -d bugsink -c "
SELECT nextval('projects_project_id_seq') - 1 as current_seq_value;
"
```
**Prevention:**
When manually inserting data or restoring backups, always reset sequences:
```sql
-- Generic pattern for any table/sequence
SELECT setval('SEQUENCE_NAME', COALESCE((SELECT MAX(id) FROM TABLE_NAME), 1), true);
-- Common Bugsink sequences that may need reset:
SELECT setval('projects_project_id_seq', COALESCE((SELECT MAX(id) FROM projects_project), 1), true);
SELECT setval('teams_team_id_seq', COALESCE((SELECT MAX(id) FROM teams_team), 1), true);
SELECT setval('releases_release_id_seq', COALESCE((SELECT MAX(id) FROM releases_release), 1), true);
```
### Logstash Level Field Constraint Violation
**Symptoms:**
- Bugsink errors: `value too long for type character varying(7)`
- Errors in Backend API project from Logstash
- Log shows `%{sentry_level}` literal string being sent
**Root Cause:**
Logstash sends the literal placeholder `%{sentry_level}` (16 characters) to Bugsink when:
- No error pattern is detected in the log message
- The `sentry_level` field is not properly initialized
- Bugsink's `level` column has a `varchar(7)` constraint
Valid Sentry levels are: `fatal`, `error`, `warning`, `info`, `debug` (all <= 7 characters).
**Diagnosis:**
```bash
# Check for recent level constraint errors in Bugsink
# Via MCP:
mcp__localerrors__list_issues({ project_id: 1, status: 'unresolved' })
# Or check Logstash logs for HTTP 500 responses
podman exec flyer-crawler-dev cat /var/log/logstash/logstash.log | grep "500"
```
**Solution:**
The fix requires updating the Logstash configuration (`docker/logstash/bugsink.conf`) to:
1. Validate `sentry_level` is not nil, empty, or contains placeholder text
2. Set a default value of "error" for any error-tagged event without a valid level
3. Normalize levels to lowercase
**Key filter block (Ruby):**
```ruby
ruby {
code => '
level = event.get("sentry_level")
# Check if level is invalid (nil, empty, contains placeholder, or invalid value)
if level.nil? || level.to_s.empty? || level.to_s.include?("%{") || level.to_s.length > 7
# Default to "error" for error-tagged events, "info" otherwise
if event.get("tags")&.include?("error")
event.set("sentry_level", "error")
else
event.set("sentry_level", "info")
end
else
# Normalize to lowercase and validate
normalized = level.to_s.downcase
valid_levels = ["fatal", "error", "warning", "info", "debug"]
unless valid_levels.include?(normalized)
normalized = "error"
end
event.set("sentry_level", normalized)
end
'
}
```
**Verification:**
After applying the fix:
1. Restart Logstash: `podman exec flyer-crawler-dev systemctl restart logstash`
2. Generate a test error and verify it appears in Bugsink without level errors
3. Check no new "value too long" errors appear in the project
### CSRF Verification Failed
**Symptoms:** "CSRF verification failed. Request aborted." error when performing actions in Bugsink UI (resolving issues, changing settings, etc.)
**Root Cause:**
Django 4.0+ requires `CSRF_TRUSTED_ORIGINS` to be explicitly configured for HTTPS POST requests. The error occurs because:
1. Bugsink is accessed via `https://localhost:8443` (nginx HTTPS proxy)
2. Django's CSRF protection validates the `Origin` header against `CSRF_TRUSTED_ORIGINS`
3. Without explicit configuration, Django rejects POST requests from HTTPS origins
**Why localhost vs 127.0.0.1 Matters:**
- `localhost` and `127.0.0.1` are treated as DIFFERENT origins by browsers
- If you access Bugsink via `https://localhost:8443`, Django must trust `https://localhost:8443`
- If you access via `https://127.0.0.1:8443`, Django must trust `https://127.0.0.1:8443`
- The fix includes BOTH to allow either access pattern
**Configuration (Already Applied):**
The Bugsink Django configuration in `Dockerfile.dev` includes:
```python
# CSRF Trusted Origins (Django 4.0+ requires full origin for HTTPS POST requests)
CSRF_TRUSTED_ORIGINS = [
"https://localhost:8443",
"https://127.0.0.1:8443",
"http://localhost:8000",
"http://127.0.0.1:8000",
]
# HTTPS proxy support (nginx reverse proxy on port 8443)
SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https")
```
**Verification:**
```bash
# Verify CSRF_TRUSTED_ORIGINS is configured
podman exec flyer-crawler-dev sh -c 'cat /opt/bugsink/conf/bugsink_conf.py | grep -A 6 CSRF_TRUSTED'
# Expected output:
# CSRF_TRUSTED_ORIGINS = [
# "https://localhost:8443",
# "https://127.0.0.1:8443",
# "http://localhost:8000",
# "http://127.0.0.1:8000",
# ]
```
**If Issue Persists After Fix:**
1. **Rebuild the container image** (configuration is baked into the image):
```bash
podman-compose -f compose.dev.yml down
podman build -f Dockerfile.dev -t localhost/flyer-crawler-dev:latest .
podman-compose -f compose.dev.yml up -d
```
2. **Clear browser cookies** for localhost:8443
3. **Check nginx X-Forwarded-Proto header** - the nginx config must set this header for Django to recognize HTTPS:
```bash
podman exec flyer-crawler-dev cat /etc/nginx/sites-available/bugsink | grep X-Forwarded-Proto
# Should show: proxy_set_header X-Forwarded-Proto $scheme;
```
---
## Related Documentation
- [ADR-015: Application Performance Monitoring and Error Tracking](../adr/0015-application-performance-monitoring-and-error-tracking.md)
- [BUGSINK-MCP-TROUBLESHOOTING.md](../BUGSINK-MCP-TROUBLESHOOTING.md)
- [DEV-CONTAINER-BUGSINK.md](../DEV-CONTAINER-BUGSINK.md)
- [BUGSINK-SYNC.md](../BUGSINK-SYNC.md) - Bugsink to Gitea issue synchronization
- [bugsink-mcp Repository](https://github.com/j-shelfwood/bugsink-mcp)
- [Bugsink Documentation](https://www.bugsink.com/docs/)
- [@sentry/node Documentation](https://docs.sentry.io/platforms/javascript/guides/node/)
- [@sentry/react Documentation](https://docs.sentry.io/platforms/javascript/guides/react/)