Skip to content

Repository files navigation

Errflow Server

A production-quality error tracking and monitoring server for JavaScript and React applications. Receives error events over HTTP, groups them into issues using fingerprinting, and stores them in PostgreSQL.

Features

  • Event Ingestion: Receive JavaScript/React error events via REST API
  • Smart Grouping: Automatically group similar errors using fingerprint algorithm
  • Issue Management: Track, resolve, and ignore issues
  • Rate Limiting: Per-project rate limiting (in-memory for v1)
  • Authentication: Project-based auth with hashed secrets
  • CORS Support: Configured for frontend integration
  • Structured Logging: JSON logging with request tracing

Prerequisites

  • Docker - Required for PostgreSQL database
  • Python 3.12+ - For local development

Quick Start

Option 1: Local Development

# 1. Clone and setup
git clone <repository-url>
cd errflow-server

# 2. Bootstrap Python environment
./scripts/bootstrap.sh

# 3. Activate virtual environment
source .venv/bin/activate

# 4. Start PostgreSQL
./infrastructure/up.sh

# 5. Run database migrations
alembic upgrade head

# 6. Seed demo project
python -m scripts.seed

# 7. Start the API server
uvicorn app.main:app --reload

API available at: http://localhost:8000 API docs at: http://localhost:8000/docs

Option 2: Docker Compose (Full Stack)

# Start everything
docker compose up -d

# Run migrations
docker compose --profile migrate up migrate

# Seed demo project
docker compose --profile seed up seed

Configuration

All configuration via environment variables. Copy env.example to .env and customize:

Variable Default Description
ERRFLOW_DB_HOST localhost PostgreSQL host
ERRFLOW_DB_PORT 5432 PostgreSQL port
ERRFLOW_DB_NAME errflow Database name
ERRFLOW_DB_USER errflow Database user
ERRFLOW_DB_PASSWORD errflow_secret Database password
ERRFLOW_CORS_ORIGINS http://localhost:5173 Allowed CORS origins (comma-separated)
ERRFLOW_RATE_LIMIT_REQUESTS 100 Max requests per window
ERRFLOW_RATE_LIMIT_WINDOW_SECONDS 60 Rate limit window
ERRFLOW_LOG_LEVEL INFO Logging level
ERRFLOW_LOG_FORMAT json Log format (json/text)

API Usage

Authentication

All API endpoints (except /health) require authentication headers:

X-Project-Key: <project_key>
Authorization: Bearer <project_secret>

Demo credentials:

  • Project Key: demo-web
  • Project Secret: demo-secret

Endpoints

Method Endpoint Description
GET /health Health check
POST /api/v1/events Ingest error event
GET /api/v1/issues List issues
GET /api/v1/issues/{id} Get issue details
PATCH /api/v1/issues/{id} Update issue status
GET /api/v1/issues/{id}/events List events for issue

Example: Send Error Event (errflow-js format)

The API accepts exception.stack as a string (standard JS Error.stack):

curl -X POST http://localhost:8000/api/v1/events \
  -H "Content-Type: application/json" \
  -H "X-Project-Key: demo-web" \
  -H "Authorization: Bearer demo-secret" \
  -d '{
    "exception": {
      "name": "TypeError",
      "message": "Cannot read properties of undefined (reading '\''map'\'')",
      "stack": "TypeError: Cannot read properties of undefined\n    at UserList.render (http://localhost:5173/src/UserList.tsx:42:15)\n    at renderWithHooks (react-dom.js:1234:22)"
    },
    "level": "error",
    "url": "http://localhost:5173/users",
    "user_agent": "Mozilla/5.0 Chrome/120.0.0.0",
    "timestamp": null,
    "tags": {"version": "1.0.0"},
    "breadcrumbs": [
      {"type": "navigation", "category": "route", "message": "/users"}
    ],
    "user": {"id": "user-123", "email": null},
    "environment": "production"
  }'

Response:

{
  "event_id": 1,
  "issue_id": 1,
  "is_new_issue": true
}

Accepted stack formats:

  • String (recommended): raw JS Error.stack
  • List of strings: joined with \n
  • List of objects: {filename, function, lineno, colno} (backward compat)

Accepted timestamp formats:

  • ISO 8601 string: "2025-01-01T12:00:00Z"
  • Unix timestamp (seconds): 1735689600
  • Unix timestamp (milliseconds): 1735689600000
  • null or missing: uses server time

Example: List Issues

curl http://localhost:8000/api/v1/issues \
  -H "X-Project-Key: demo-web" \
  -H "Authorization: Bearer demo-secret"

Example: Update Issue Status

curl -X PATCH http://localhost:8000/api/v1/issues/1 \
  -H "Content-Type: application/json" \
  -H "X-Project-Key: demo-web" \
  -H "Authorization: Bearer demo-secret" \
  -d '{"status": "resolved"}'

Infrastructure Scripts

# Start PostgreSQL
./infrastructure/up.sh

# Stop PostgreSQL (preserves data)
./infrastructure/down.sh

# Reset database (deletes all data)
./infrastructure/reset.sh

# View PostgreSQL logs
./infrastructure/logs.sh

Frontend Viewer

A simple React viewer for browsing errors:

cd frontend
npm install
npm run dev

Opens at http://localhost:5175

Features:

  • View all issues with status filter
  • Click issue to see details and stack traces
  • Auto-refresh every 10 seconds
  • Dark theme with Tailwind CSS

Project Structure

errflow-server/
├── app/                     # FastAPI backend
│   ├── main.py              # Application entry
│   ├── settings.py          # Configuration
│   ├── db.py                # Database connection
│   ├── models.py            # SQLAlchemy models
│   ├── schemas.py           # Pydantic schemas
│   ├── auth.py              # Authentication
│   ├── rate_limit.py        # Rate limiting
│   ├── fingerprinting.py    # Error grouping
│   ├── routers/             # API endpoints
│   └── middleware/          # Request middleware
├── frontend/                # React viewer (Vite + Tailwind)
│   ├── src/
│   │   ├── App.jsx          # Main component
│   │   └── api.js           # API client
│   └── package.json
├── alembic/                 # Database migrations
├── infrastructure/          # Docker/DB scripts
├── scripts/                 # Dev scripts
├── docker-compose.yml       # Full stack deployment
├── Dockerfile               # API container
└── requirements.txt         # Python dependencies

CORS Configuration

The server is configured to accept requests from http://localhost:5173 by default (Vite dev server). For production, set the ERRFLOW_CORS_ORIGINS environment variable:

ERRFLOW_CORS_ORIGINS=https://app.example.com,https://staging.example.com

Fingerprinting Algorithm

Events are grouped into issues using a fingerprint computed from:

  1. Exception name - e.g., TypeError
  2. Exception message - normalized to remove dynamic values
  3. Stack trace - normalized to remove line numbers, bundle hashes, and query strings

This ensures similar errors are grouped together even if they occur at different times or with slightly different stack traces.

Database Schema

projects
├── id (pk)
├── project_key (unique)
├── project_secret_hash
├── name
└── created_at

issues
├── id (pk)
├── project_id (fk)
├── fingerprint (indexed)
├── title
├── level (error/fatal/warn)
├── first_seen
├── last_seen
├── count
└── status (open/ignored/resolved)

events
├── id (pk)
├── issue_id (fk)
├── received_at
├── client_timestamp
├── payload_json (jsonb)
└── normalized_stack

CI/CD Future Notes

This project is structured to support CI/CD pipelines:

  1. Testing: Add pytest tests and run with pytest --cov
  2. Linting: Use ruff check . and mypy .
  3. Docker Build: Multi-stage Dockerfile for efficient builds
  4. Migrations: Use alembic upgrade head in deployment
  5. Health Checks: /health endpoint for readiness probes
  6. Secrets: Use environment variables or secret managers

Example GitHub Actions workflow:

jobs:
  test:
    runs-on: ubuntu-latest
    services:
      postgres:
        image: postgres:16-alpine
        env:
          POSTGRES_USER: test
          POSTGRES_PASSWORD: test
          POSTGRES_DB: test
        ports:
          - 5432:5432
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with:
          python-version: '3.12'
      - run: pip install -r requirements-dev.txt
      - run: ruff check .
      - run: mypy .
      - run: pytest --cov

License

MIT

About

errflow-server

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages