A self-hosted, Sentry-SDK-compatible error & performance tracker. Point any Sentry SDK at it — just change the DSN — and get issues, stack traces, distributed traces, profiling, release health, cron/uptime monitors, and alerting. All from a single Go service backed by one SQLite file.
Sentry's self-hosted stack is heavy — Kafka, ClickHouse, Redis, ~20 containers. go-bug-tracker delivers the same day-to-day developer experience for small and medium teams from one container and one SQLite file. Your data stays on your infrastructure, and any existing Sentry SDK works unchanged: you only swap the DSN.
- Drop-in compatible — implements Sentry's envelope ingestion protocol (
/api/{id}/envelope/plus the legacy/store/). Errors, transactions, sessions, check-ins, profiles, attachments, client reports and user feedback all flow through the SDKs you already use. - Lightweight — cgo-free SQLite (WAL), a streaming envelope parser, and an async digest worker. No external services required.
- Complete surface — issues, performance, profiling, releases, source maps, monitors, alerts, feedback, dashboards, teams and scoped API tokens all ship.
| Issue alert email — exception, in-app frames, tags, user | Weekly report email — totals, charts, top issues & transactions |
- Error tracking — server-side grouping into issues, full stack traces, breadcrumbs, tags, contexts and user. Resolve / archive / mute, regression detection, priority, assignment, comments, subscriptions, and merge.
- Performance — transactions, distributed tracing with a span waterfall, p50–p99 latency and throughput per transaction.
- Profiling — flamegraphs from sampled profiles, tied to their transactions, with aggregate views.
- Release health — sessions, crash-free sessions/users, adoption, per-release issues, plus deploys and commits via the CI-friendly API.
- Source maps — upload minified bundles and their
.mapfiles per release (single artifact or zip bundle) so JavaScript stack traces resolve to original source, with inline code context. - Monitors — cron check-ins (missed / late / errored, auto-created on first check-in) and HTTP uptime checks.
- Alerting — rules (new issue, regression, …) routed to channels: email, outbound webhook, Slack. Alert emails include the exception, key in-app stack frames, tags and the affected user.
- Weekly report — an org-wide email digest of the past week (errors, transactions, issue breakdown, top issues, slowest transactions) with CSS-only charts; configurable first day of the week, skipped when the week had no events.
- User feedback — collected via the SDK or the
user-feedbackendpoint, linked to events. - Dashboards — org-wide and per-project: event volume, crash-free trend, top issues, slowest transactions, and a per-project breakdown.
- Org & access — first-run setup, teams, members & invitations, and scoped API tokens
(Sentry-style
event:*/project:*/org:*scopes) for automation. - i18n — English and Vietnamese out of the box (paraglide-js).
| Layer | Tech |
|---|---|
| HTTP / API | Go + Fiber v2 — internal/transport/http is the only package that imports Fiber |
| Ingestion | Streaming Sentry envelope parser with compressed and decompressed size caps (decompression-bomb guard) → durable job queue |
| Digest | Async worker: grouping, storage, source-map resolution, alerting — never inline on the ingest request |
| Storage | SQLite (modernc.org/sqlite, cgo-free, WAL) + a content-addressed blob store for large payloads |
| Frontend | React 19 + Vite + TanStack Router, Tailwind v4, shadcn/ui (ui/) |
| Serving | SPA served as static files from DIST_DIR (never go:embed-ed); runtime env injected at container boot |
| Migrations | golang-migrate (migrations/) |
Requirements: Go 1.26+, Bun (frontend), Docker (optional, for deployment).
cp .env.example .env # set SESSION_SECRET (32+ bytes) at minimum
bun --cwd=ui install
make dev # backend (:8080, live reload) + frontend (:3000, Vite)In dev, Vite serves the SPA on :3000 and proxies /api → http://localhost:8080. On an empty
database the app shows a first-run setup wizard to create the admin (or pre-seed with
BOOTSTRAP_ADMIN_EMAIL / BOOTSTRAP_ADMIN_PASSWORD).
make build # builds ui/dist + the `server` and `run` binaries
docker build -t go-bug-tracker . # or build the container imageEvery push to main that touches app code publishes a nightly image (doc-only commits are
skipped). Create a semver git tag (v1.0.0) to publish latest and the version tag (1.0.0):
docker pull ghcr.io/mertek-dev/go-bug-tracker:nightly # tip of main
docker pull ghcr.io/mertek-dev/go-bug-tracker:latest # latest release tag
docker pull ghcr.io/mertek-dev/go-bug-tracker:1.0.0 # specific release
docker run --rm -p 8080:8080 \
-e SESSION_SECRET='change-me-please-32-bytes-minimum-required' \
-e BASE_URL='http://localhost:8080' \
-v gobugtracker-data:/app/data \
ghcr.io/mertek-dev/go-bug-tracker:nightlyRelease: git tag v1.0.0 && git push origin v1.0.0. For a private repo, docker login ghcr.io
with a GitHub PAT that has read:packages.
server serves the built SPA from DIST_DIR (default ./dist) as static files. In a container the
run entrypoint injects VITE_* env into dist/env.js (window.__ENV__) at boot — runtime
reconfiguration without a rebuild — then execs server.
Create a project in the UI, then copy its DSN from Project settings. Point any Sentry SDK at it.
JavaScript / Next.js (instrumentation-client.ts):
import * as Sentry from "@sentry/nextjs";
Sentry.init({
dsn: "http://<public_key>@localhost:8080/<project_number>",
tracesSampleRate: 1.0, // performance + release-health sessions
release: "my-app@1.0.0",
environment: "production",
});Mounted under /api/{project_number}/ and authenticated by sentry_key (no session/CSRF):
| Method | Path | Purpose |
|---|---|---|
| POST | /api/{id}/envelope/ |
Primary — newline-delimited envelope (events, transactions, sessions, check-ins, profiles, attachments, client reports) |
| POST | /api/{id}/store/ |
Legacy — a single bare event JSON body |
| POST | /api/{id}/user-feedback/ |
User feedback linked to an event |
Handled envelope item types: event, transaction, session, sessions, check_in, profile,
attachment, client_report. Unknown types are skipped gracefully. See
docs/steering/ingestion-protocol.md for the full contract
(DSN format, auth resolution, size limits, rate limiting).
Management endpoints under /api/_/ accept either a session cookie (+ CSRF) or a Bearer API
token minted in Settings → API tokens with fine-grained scopes. Bearer tokens skip CSRF, so
they're ideal for CI:
# Upload a source map for a release (project:releases scope)
curl -X POST "http://localhost:8080/api/_/projects/<project_id>/artifacts" \
-H "Authorization: Bearer <token>" -H "Content-Type: application/json" \
-d '{"release":"my-app@1.0.0","name":"app.min.js.map","type":"sourcemap","content_base64":"..."}'
# Record a deploy for a release
curl -X POST "http://localhost:8080/api/_/releases/<release_id>/deploys" \
-H "Authorization: Bearer <token>" -H "Content-Type: application/json" \
-d '{"environment":"production","name":"v1.0.0"}'The full HTTP surface is documented in docs/openapi.yaml.
Key environment variables (see .env.example for the complete list):
| Variable | Description |
|---|---|
PORT |
HTTP port (default 8080) |
BASE_URL |
Public URL; DSNs handed to SDKs are built from this |
DATABASE_URL |
SQLite DSN (WAL, busy_timeout) |
SESSION_SECRET |
Required, 32+ bytes; rotating it invalidates all sessions |
BOOTSTRAP_ADMIN_EMAIL / _PASSWORD |
Pre-seed the first admin on an empty DB |
MAX_ENVELOPE_COMPRESSED_BYTES / MAX_ENVELOPE_BYTES |
Decompression-bomb caps (on-wire + decoded) |
RETENTION_MAX_EVENTS_PER_PROJECT |
Error retention cap (eviction by age + relevance) |
PERF_RETENTION_DAYS |
Performance (transactions/spans/profiles) retention |
SMTP_HOST / SMTP_PORT / SMTP_FROM |
Email alerts |
SOURCEMAPS_ENABLED |
Enable JS de-minification |
go build ./... && go vet ./... && go test ./... # backend gates (add -race for concurrency)
bun --cwd=ui run format && bunx --cwd ui biome check && bun --cwd=ui run test && bunx --cwd ui tsc --noEmit
bunx @redocly/cli lint docs/openapi.yaml # when the API changesdocs/openapi.yaml is the API contract — handler changes ship with the matching spec change.
Tests ship with code.
cmd/ server + run (container entrypoint) binaries
internal/ domain packages (issues, performance, profiles, releases, monitors,
alerts, sourcemaps, sessions, digest, retention…) + transport/http
migrations/ golang-migrate SQL
ui/ React 19 + Vite SPA (TanStack Router, Tailwind v4, shadcn/ui)
docs/ steering docs, OpenAPI contract, roadmap, UI style spec
docs/steering/product-vision.md— goals, scope, non-goalsdocs/steering/ingestion-protocol.md— Sentry-compat contractdocs/steering/scalability.md— scaling model & operational knobsdocs/roadmap.md/docs/tasks.md— phased plan + progressdocs/openapi.yaml— API contract
MIT © mertek.dev