Developer Docs

๐Ÿ› Error Tracking (GlitchTip) โ€” Developer Guide

Overview

Mallnline uses GlitchTip โ€” a self-hosted, open-source error tracking platform โ€” to capture unhandled errors, uncaught promise rejections, and performance traces from Visitors' and Buyers' browsers. GlitchTip is fully compatible with the Sentry SDK, so the frontend uses @sentry/sveltekit under the hood.

Component Purpose Technology
GlitchTip Web Dashboard for viewing errors, stack traces, and breadcrumbs Docker (glitchtip/glitchtip)
GlitchTip Worker Background processing (event ingestion, cleanup) Celery beat + Redis
Frontend SDK Client-side error capture and performance tracing @sentry/sveltekit
User Context Associates errors with authenticated Visitors/Buyers sentryContext.ts utility

Why GlitchTip?

  • Self-hosted โ€” all error data stays on your infrastructure. No third-party data processing.
  • Sentry SDK compatible โ€” drop-in DSN swap if you ever want to migrate to Sentry cloud or back.
  • Lightweight โ€” runs on ~1 GB RAM alongside existing Postgres and Redis.
  • Free at any scale โ€” no per-event pricing, no seat limits.

Architecture

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚    Browser (Visitor)       โ”‚
โ”‚                            โ”‚
โ”‚    @sentry/sveltekit SDK   โ”‚
โ”‚    hooks.client.ts         โ”‚
โ”‚                            โ”‚
โ”‚    DSN โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜       โ”‚
                                     โ–ผ
                          โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
                          โ”‚   GlitchTip :8000    โ”‚
                          โ”‚                      โ”‚
                          โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”‚
                          โ”‚  โ”‚ Web Dashboard  โ”‚  โ”‚ โ—„โ”€โ”€ Developers view errors here
                          โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ”‚
                          โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”‚
                          โ”‚  โ”‚ Celery Worker  โ”‚  โ”‚ โ—„โ”€โ”€ Background event processing
                          โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ”‚
                          โ”‚         โ”‚            โ”‚
                          โ”‚    โ”Œโ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”       โ”‚
                          โ”‚    โ–ผ         โ–ผ       โ”‚
                          โ”‚  Postgres   Redis    โ”‚ โ—„โ”€โ”€ Shared with federation stack
                          โ”‚  (DB 0)    (DB 1)    โ”‚
                          โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

GlitchTip reuses the existing ngwenya-postgres instance (separate ngwenya_glitchtip database) and Redis (database index 1, to avoid conflicts with the gateway cache on DB 0).

Production note: In production, GlitchTip should run as a fully separate deployment with its own dedicated Postgres and Redis instances โ€” no shared resources with the application databases.


Quick Start

1. Start GlitchTip

# From ngwenya-federation/
make glitchtip-up

This single command:

  1. Starts Postgres, Redis, GlitchTip web, and the Celery worker
  2. Waits for the health check
  3. Auto-runs make glitchtip-setup which:
    • Creates the ngwenya_glitchtip database (idempotent)
    • Runs Django migrations
    • Creates the admin account (mallnline.dev@gmail.com / admin123)
    • Generates an API token via Django ORM
    • Injects the token into apps/tower/.env

Dashboard: http://localhost:8000

2. Configure the Frontend

Set the DSN in ngwenya-front/.env:

PUBLIC_SENTRY_DSN=http://73b493b8de6049d4b08cdce5aa5a4c4f@localhost:8000/1
PUBLIC_SENTRY_ENVIRONMENT=beta

Finding your DSN: Log in at http://localhost:8000 โ†’ open your project โ†’ Settings โ†’ Client Keys (DSN)

Restart the dev server (pnpm run dev). Errors will now appear in the GlitchTip dashboard.

3. Start the Tower Subgraph

make restart-tower

Tower reads the auto-injected GLITCHTIP_API_TOKEN from apps/tower/.env and connects to the GlitchTip REST API. The Tower admin dashboard Error Tracking widgets will now show live data.

4. Verify

Send a test error directly to GlitchTip to confirm the ingestion pipeline works:

# From ngwenya-federation/
make glitchtip-test

This sends a curl request to the Sentry store API using your project's DSN key. If you see โœ… Event accepted, check http://localhost:8000 โ€” the error should appear under Issues.

You can also verify from the browser by opening DevTools Console on your running frontend and running:

// setTimeout wrapper ensures Sentry's global handler catches it
// (a bare throw in the console is caught by DevTools, not the SDK)
setTimeout(() => { throw new Error('GlitchTip browser test'); }, 0);

Tip: If browser errors aren't showing up, make sure you restarted the dev server after setting PUBLIC_SENTRY_DSN โ€” env vars are only read at startup.


Make Targets

The backend Makefile provides six GlitchTip targets:

Command Description
make glitchtip-up Start GlitchTip + dependencies, wait for health check
make glitchtip-setup First-time setup: create DB, run migrations, create admin account
make glitchtip-test Send a test error via curl to verify event ingestion
make glitchtip-down Stop GlitchTip containers (leaves DBs running)
make glitchtip-logs Tail GlitchTip web + worker logs
make glitchtip-status Show container status + health check

Frontend SDK Integration

Initialization (`hooks.client.ts`)

The SDK is initialized in src/hooks.client.ts โ€” the SvelteKit client-side error hook. Key behaviors:

import * as Sentry from '@sentry/sveltekit';

if (browser) {
    const dsn = import.meta.env.PUBLIC_SENTRY_DSN;
    if (dsn) {
        Sentry.init({
            dsn,
            environment: import.meta.env.PUBLIC_SENTRY_ENVIRONMENT || 'beta',
            sendDefaultPii: false,      // GDPR-safe
            tracesSampleRate: 0.2,      // 20% of navigations traced
        });
    }
}

export const handleError = Sentry.handleErrorWithSentry(ngwenyaErrorHandler);

Design decisions:

  • No-op without DSN โ€” if PUBLIC_SENTRY_DSN is not set, no Sentry code runs. Safe for local dev without Docker.
  • sendDefaultPii: false โ€” no IP addresses, user-agent strings, or cookies are sent automatically. GDPR-compliant by default.
  • tracesSampleRate: 0.2 โ€” only 20% of page navigations generate performance traces. Keeps volume manageable.
  • Header scrubbing โ€” authorization, x-org-id, x-guest-id, and cookie headers are stripped from all transaction payloads via beforeSendTransaction.

User Context (`sentryContext.ts`)

When a Visitor logs in, their identity is synced to GlitchTip so that error reports show who was affected:

import { setSentryUser } from '$lib/services/sentryContext';

// On login
setSentryUser({ handle: 'v|meekdenzo', email: 'user@example.com', id: '...' });

// On logout
setSentryUser(null);

The +layout.svelte root layout subscribes to authStore changes and calls setSentryUser automatically โ€” no manual wiring needed in individual pages.

Security: User context uses the handle (e.g., v|meekdenzo) as the identifier, not raw UUIDs. This complies with the platform's identity security guardrails.

Vite Plugin

The sentrySvelteKit() Vite plugin is configured in vite.config.ts with source map upload disabled (GlitchTip doesn't support the Sentry source map upload API):

import { sentrySvelteKit } from '@sentry/sveltekit';

plugins: [
    sentrySvelteKit({
        autoUploadSourceMaps: false
    }),
    sveltekit(),
    // ...
]

The plugin must appear before sveltekit() in the plugins array.


Manual Error Capture

Beyond automatic unhandled error capture, you can manually report errors anywhere in the frontend:

import * as Sentry from '@sentry/sveltekit';

try {
    await riskyOperation();
} catch (error) {
    Sentry.captureException(error, {
        tags: { component: 'ucart-checkout', maletId: 'm|luminara' },
        extra: { cartItemCount: 3, totalAmount: 'R150.00' }
    });
}

Adding Breadcrumbs

Breadcrumbs provide a trail of events leading up to an error โ€” clicks, navigations, and network requests are captured automatically. You can add custom breadcrumbs for domain-specific actions:

Sentry.addBreadcrumb({
    category: 'ucart',
    message: 'Added item to uCart',
    data: { productId: 'prod_123', maletHandle: 'm|luminara' },
    level: 'info'
});

Environment Variables

Frontend (`ngwenya-front/.env`)

Variable Required Default Description
PUBLIC_SENTRY_DSN No โ€” GlitchTip project DSN. Error tracking is disabled when unset.
PUBLIC_SENTRY_ENVIRONMENT No beta Environment tag attached to all events

Backend (`docker-compose-dev.yaml`)

Variable Default Description
DATABASE_URL postgres://...ngwenya_glitchtip GlitchTip's PostgreSQL database
REDIS_URL redis://redis:6379/1 Redis on database 1 (avoids gateway conflicts)
SECRET_KEY Dev placeholder Django secret key โ€” change in production
GLITCHTIP_DOMAIN http://localhost:8000 Public URL for the dashboard
ENABLE_OPEN_USER_REGISTRATION true Allow anyone to register (dev only)
GLITCHTIP_MAX_EVENT_LIFE_DAYS 90 Auto-prune events older than 90 days

Docker Infrastructure

GlitchTip runs as two containers in docker-compose-dev.yaml:

# Web dashboard + event ingestion API
glitchtip:
    image: glitchtip/glitchtip:latest
    ports:
        - "8000:8000"     # Dashboard + DSN endpoint
    depends_on:
        - postgres
        - redis

# Background worker (Celery beat)
glitchtip-worker:
    image: glitchtip/glitchtip:latest
    command: bin/run-celery-with-beat.sh
    depends_on:
        - postgres
        - redis

The ngwenya_glitchtip PostgreSQL database is auto-created by infra/postgres/init-uchat-db.sh alongside the existing ngwenya_uchat database.


What Gets Captured

Event Type Automatic? Details
Unhandled errors โœ… JavaScript runtime errors, uncaught promise rejections
Console errors โœ… console.error() calls captured as breadcrumbs
Network requests โœ… XHR/fetch requests + responses captured as breadcrumbs
User clicks โœ… DOM click events captured as breadcrumbs
Page navigations โœ… SvelteKit route changes captured as breadcrumbs
Performance traces โœ… (sampled) 20% of navigations generate full timing traces
Custom errors Manual Use Sentry.captureException() or Sentry.captureMessage()
Session replays โŒ Not supported by GlitchTip

What Is NOT Captured

  • PII โ€” sendDefaultPii: false prevents automatic capture of IP addresses and cookies
  • Auth tokens โ€” authorization, x-org-id, x-guest-id, and cookie headers are scrubbed from traces
  • Raw UUIDs โ€” user context uses handles, not database IDs
  • Server-side errors โ€” this integration is client-side only; server errors go through the Alerts pipeline

Migrating to Sentry Cloud

Because the frontend uses @sentry/sveltekit (the standard Sentry SDK), migration to Sentry's hosted cloud is a one-line change:

- PUBLIC_SENTRY_DSN=http://abc123@localhost:8000/1
+ PUBLIC_SENTRY_DSN=https://abc123@o123456.ingest.sentry.io/456789

No code changes needed. You'll also gain access to Sentry-exclusive features:

  • Session Replay (video-like error reproductions)
  • Source map upload (readable stack traces)
  • Advanced alerting rules and dashboards