Beacon reference
Multi-tenant observability with deploy DNA.
Beacon ingests gzip-compressed JSON log batches, indexes them in D1, and serves real-time search, auto-grouped issues, and alert rules — with every line tagged by the deploy revision that produced it.
Log ingest
Beacon accepts logs via a single HTTP endpoint. The path is /v1/logs/ingest on beacon.repoless.com (or any of your tenant subdomains).
- Auth: bearer host token
lwh_*. Mint one from Admin → Hosts. - Body: newline-delimited JSON (NDJSON), gzipped. One log line per JSON object.
- Size cap: decompression is capped at 32 MiB to prevent gzip bombs. Batch your sends below that.
- Content-Encoding: must be
gzip.
$ printf '{"service":"api","msg":"hi","level":"info"}\n' \
| gzip \
| curl -X POST https://beacon.repoless.com/v1/logs/ingest \
-H "Authorization: Bearer lwh_•••••" \
-H "Content-Encoding: gzip" \
-H "Content-Type: application/x-ndjson" \
--data-binary @-Recognized fields
service— required. The service identity (see below).project— optional but recommended. Groups services in the UI.resource— optional. Container name or host name; helps when one service has multiple replicas.service_type— optional. Annotates asapp,db, or other.level— info / warn / error / debug. Drives the issue grouping pipeline.msg— the log line.deploywatch.revision— set automatically by the Pier agent. Manually settable for non-Pier deploys.- Any additional fields are stored and searchable as facets.
Drop-in Vector config
Most teams use Vector to tail Docker logs and forward them to Beacon. The provided deploy/vector/vector.yaml tags every container based on Compose labels and container-name role prefix:
service = <coolify.serviceName>[-<role>][-pr-<id>]
# web-bgyb… → narmypayroll-web
# worker-bgyb… → narmypayroll-worker
# web-bgyb…-pr-163 → narmypayroll-web-pr-163
# i85ic49zy14c… → platform-redis (fallback)Service identity
Services are derived, not enrolled. The first log line from a new service value creates a service row automatically; nothing to pre-configure. This means Pier can spin up an app, deploy it, and have its logs streaming in Beacon within ~1 second of the first stdout.
Search
Full-text search lives at /search. Filter by project, service, level, and time range. Beacon uses D1 FTS indexes — sub-second for the typical query.
- Free text: matches against
msgand structured fields. - Facet filters: click any value in a result to add it to the filter set.
- Revision filter:
rev:c0a3f02isolates logs from a single deploy — typically deep-linked from a Pier revision card.
Saved queries
Promote any search to a saved query for quick recall. Saved queries carry their filter set, time window, and grouping. They live under Account → Saved searches and can be referenced from alert rules.
Collections
Collections are user-defined groupings of services that often need to be watched together — a domain (auth flow, checkout, search), a microservice family, a customer-specific subset. Each collection appears on the dashboard with rollup line counts and the most recent activity. CRUD from /collections.
Aliases & display names
Raw container names are useful for debugging but ugly in dashboards. Beacon supports two layers of friendlier naming:
- App aliases: map raw container names to a stable service identifier (handles renames during container churn).
- Display names: a human-friendly label shown across the UI without changing the underlying service identity.
Admins configure both at /admin/labels. Changes are instant — no log re-ingest needed.
Auto-grouped issues
Error-level logs are normalized and grouped into issues automatically. Beacon strips noisy variants (timestamps, request IDs, memory addresses) before computing a signature so semantically identical errors collapse into one row.
Each issue tracks:
- Total occurrence count and last-seen time
- The deploy revision it first appeared in
- A frequency sparkline over the last 24h
- A few representative log lines for context
Click an issue to open its detail page with full occurrence history and quick links to the revision that introduced it.
Alert rules
Alerts fire when a search query crosses a threshold. Rule types:
- Error pattern: a new issue appears that matches a regex on
msg. - Log volume: count of matching lines in a rolling window crosses a threshold.
- Uptime: no logs from a service in N minutes (proxy for "the service is dead").
Each rule routes to one or more channels — Slack, Discord, email, or HTTP webhook — defined in the shared notification channels table. Per-rule cooldowns prevent floods.
Retention
Logs live in D1 until the retention worker deletes them. Default is 30 days. Configure under /admin/settings; the retention worker runs on a cron and prunes by ingested_at.
Manual cleanup
Team & RBAC
- Members: admins add or remove people who can sign in. Members start with no log access.
- Project access: deny-by-default. Grant a member access to a specific project; they see only that project's services, issues, and alerts.
- Roles:
adminmanages team + settings;membersees logs they have access to.
Same RBAC table (user_project_access) is shared with Pier — invite once, both products honor it.
Devices & sessions
Every sign-in mints a session with device metadata (browser, OS, IP prefix). Manage active sessions from Account → Devices. Sign out a device remotely; it will need to log in again.
Personal settings
- Timezone: per-user. Drives every timestamp display across the app.
- Default time window: when you open search, this is the default range.
Rate limits
Auth endpoints (/api/auth/*) are per-IP rate-limited to prevent OTP brute-forcing. Ingest endpoints rely on bearer-token validation and don't per-IP limit; instead the 32 MiB body cap and gzip-bomb guards constrain throughput.
Multi-tenancy
Beacon is multi-tenant from the ground up. Every row in every table carries a tenant_id and queries scope through a withTenant() wrapper that enforces it. Tenants get a wildcard subdomain (<slug>.beacon.repoless.com); Universal SSL on the proxied wildcard covers all of them.