Logister is a Rails + PostgreSQL service for collecting application errors and metrics from other Rails apps.
PostgreSQL is the control-plane database (users/projects/api keys). Event analytics can be dual-written to ClickHouse for high-scale querying.
- Open source and self-hosting
- Project documentation
- Core flow
- Runtime stack
- Prerequisites
- Self-host quickstart (local)
- Local development setup
- Development seed data
- What operators must provide
- Production self-hosting checklist
- Provider-specific config files
- Local infrastructure with Docker
- Cloudflare Turnstile
- Ingest API
- Check-in API
- ClickHouse (optional, recommended for scale)
- Companion gem
This repository is open source and can be self-hosted.
- Source: https://github.com/taimoorq/logister
- Companion gem: https://github.com/taimoorq/logister-ruby
- RubyGems: https://rubygems.org/gems/logister-ruby
| Document | Description |
|---|---|
| TESTING.md | Running tests with RSpec, test layout, and system specs |
| CONTRIBUTING.md | How to contribute, report bugs, and submit changes |
| CODE_OF_CONDUCT.md | Community standards and expected behavior |
| SECURITY.md | Security policy and how to report vulnerabilities |
| AGENTS.md | Architecture and conventions for AI agents and contributors |
| docs/RAILS_ARCHITECTURE_REVIEW.md | Rails/DHH-style architecture review of the app |
- Users sign up at
logister.org(Devise authentication). - Users create one or more projects (each project maps to a monitored app).
- Users generate API keys per project.
- Client apps send events to
POST /api/v1/ingest_eventsusing an API token. - Events are stored and visible in the dashboard.
Logister runs as a Rails web app with these components:
- Web/API: Ruby on Rails (Puma)
- Primary database: PostgreSQL
- Cache + job backend: Redis
- Background processing: Sidekiq
- Optional analytics store: ClickHouse
- Optional bot protection: Cloudflare Turnstile
- Optional transactional email: SendGrid API
- Ruby
4.0.1 - PostgreSQL
>= 14 - Redis
>= 7 - (Optional) ClickHouse for analytics
git clone https://github.com/taimoorq/logister.git
cd logister
cp .env.sample .env
bundle installbin/rails db:preparebin/devbin/dev attempts to ensure local Redis is running (via docker compose up -d redis) so cache and Sidekiq-backed features work locally.
- Start ClickHouse + Redis:
bin/dev-infra- Start ClickHouse + Redis + Postgres in Docker:
bin/dev-infra --with-postgres- Initialize ClickHouse schema (if enabled):
cat docs/clickhouse_schema.sql | curl "http://127.0.0.1:8123" --data-binary @-cp .env.sample .env
bundle install
bin/rails db:prepare
bin/devbin/dev now attempts to ensure a local Redis instance is running (via docker compose up -d redis) so cache + Sidekiq-backed features can run locally.
Or start infra + app together:
bin/dev-infraLOGISTER_EMAIL_FROM defaults to support@logister.org and is used by both app mailers and Devise emails.
For confirmation emails in production, configure SendGrid API key:
SENDGRID_API_KEY=<sendgrid_api_key>The app ships with idempotent sample seeds for development only.
Run:
bin/rails db:seedWhat gets seeded:
- 3 confirmed users (
alice,bob,carol) - 3 projects with shared memberships
- Active and revoked API keys
- Sample events across
error,metric,transaction,log, andcheck_in - Error groups in multiple states (
unresolved,resolved,ignored,archived) - Check-in monitor scenarios (
ok,missed,error)
Demo sign-in credentials:
alice@example.com / password123bob@example.com / password123carol@example.com / password123
At minimum (production):
RAILS_MASTER_KEY(Rails credentials decryption)DATABASE_URL(PostgreSQL connection)REDIS_URL(Redis/Redis Cloud connection)LOGISTER_ADMIN_EMAILS(bootstrap admin access, comma-separated emails)
Typically also provided:
LOGISTER_EMAIL_FROM(sender for auth/system emails)SENDGRID_API_KEY(if sending email via SendGrid)
Optional integrations:
- ClickHouse:
LOGISTER_CLICKHOUSE_ENABLED,LOGISTER_CLICKHOUSE_URL,LOGISTER_CLICKHOUSE_DATABASE,LOGISTER_CLICKHOUSE_EVENTS_TABLE,LOGISTER_CLICKHOUSE_USERNAME,LOGISTER_CLICKHOUSE_PASSWORD - Turnstile:
LOGISTER_TURNSTILE_ENABLED,LOGISTER_TURNSTILE_SITE_KEY,LOGISTER_TURNSTILE_SECRET_KEY - TermsFeed Cookie Consent + Google Analytics:
LOGISTER_COOKIE_CONSENT_ENABLED,LOGISTER_ANALYTICS_ENABLED,COOKIECONSENT_SCRIPT_URL,COOKIECONSENT_WEBSITE_NAME,COOKIECONSENT_PRIVACY_POLICY_URL,GOOGLE_TAG_ID
Google Analytics is consent-gated in the app and only enabled when both
LOGISTER_COOKIE_CONSENT_ENABLED=true and GOOGLE_TAG_ID are set.
Analytics tags render automatically in production. For local/staging verification,
set LOGISTER_ANALYTICS_ENABLED=true.
- Set required secrets:
RAILS_MASTER_KEYDATABASE_URLREDIS_URL(Redis Cloud example:rediss://default:<password>@<host>:<port>/0)
- Configure outbound email:
SENDGRID_API_KEYLOGISTER_EMAIL_FROM
- Choose deployment method:
- Use included
Dockerfile, or - Use Kamal config in
config/deploy.yml
- Use included
- Run migrations on deploy:
bin/rails db:migrate
- Enable background jobs in production:
- Sidekiq already configured to use
REDIS_URL
- Sidekiq already configured to use
- Optional: enable ClickHouse dual-write with
LOGISTER_CLICKHOUSE_ENABLED=true - Set at least one admin email:
LOGISTER_ADMIN_EMAILS=you@example.com
- Optional security hardening:
- Turn on Turnstile (
LOGISTER_TURNSTILE_ENABLED=true) - Enable SSL/host authorization in
config/environments/production.rb
- Turn on Turnstile (
- Optional consent + analytics setup:
- Configure TermsFeed consent banner:
LOGISTER_COOKIE_CONSENT_ENABLED=trueCOOKIECONSENT_WEBSITE_NAME=<your_website_name>COOKIECONSENT_PRIVACY_POLICY_URL=https://your-domain.example/privacy
- Configure your Google tag ID:
GOOGLE_TAG_ID=G-XXXXXXXXXX - For non-production testing, set:
LOGISTER_ANALYTICS_ENABLED=true - In self-hosted/open-source deployments, always use your own IDs
- Configure TermsFeed consent banner:
This repo keeps safe provider config in git and avoids committing secrets.
- Fly.io config:
fly.toml(tracked, non-secret deployment config) - Fly.io template:
fly.toml.example(reference copy) - Keep secrets in GitHub Actions/Fly secrets, not in repo files.
If you use Postgres.app locally, run only ClickHouse and Redis:
docker compose up -d clickhouse redis
bin/rails db:prepareEquivalent one-command startup (infra + Rails): bin/dev-infra
If you want Postgres in Docker too:
docker compose --profile docker-db up -d
bin/rails db:prepareEquivalent one-command startup with Docker Postgres: bin/dev-infra --with-postgres
Then initialize ClickHouse schema:
cat docs/clickhouse_schema.sql | curl "http://127.0.0.1:8123" --data-binary @-This app uses the rails_cloudflare_turnstile gem with Devise custom controllers.
Turnstile is enabled on Devise sign-in and sign-up when these env vars are set:
LOGISTER_TURNSTILE_ENABLED=true
LOGISTER_TURNSTILE_SITE_KEY=
LOGISTER_TURNSTILE_SECRET_KEY=The widget is rendered in the Devise forms via cloudflare_turnstile, and tokens are verified server-side via validate_cloudflare_turnstile.
- Endpoint:
POST /api/v1/ingest_events - Auth header:
Authorization: Bearer <api_token> - Alternate auth:
X-Api-Key: <api_token>
Example payload:
{
"event": {
"event_type": "error",
"level": "error",
"message": "NoMethodError in CheckoutService",
"fingerprint": "checkout-nomethoderror",
"occurred_at": "2026-02-14T12:00:00Z",
"context": {
"environment": "production",
"request_id": "abc123",
"metadata": {
"user_id": 42
}
}
}
}Supported event_type values: error, metric, transaction, log, check_in.
For database load metrics from the companion gem, metric events use message: "db.query" and context fields like duration_ms, name, and sql.
Transaction events should include transaction_name, duration_ms, and correlation fields (trace_id, request_id) in context.
Log events should include correlation identifiers in context when available (trace_id, request_id, session_id, user_id) so error views can pivot to surrounding logs.
- Endpoint:
POST /api/v1/check_ins - Auth header:
Authorization: Bearer <api_token>
Example payload:
{
"check_in": {
"slug": "nightly-reconcile",
"status": "ok",
"expected_interval_seconds": 900,
"environment": "production",
"release": "2026.03.02"
}
}LOGISTER_CLICKHOUSE_ENABLED=true
LOGISTER_CLICKHOUSE_URL=http://127.0.0.1:8123
LOGISTER_CLICKHOUSE_DATABASE=logister
LOGISTER_CLICKHOUSE_EVENTS_TABLE=events_raw
LOGISTER_CLICKHOUSE_USERNAME=default
LOGISTER_CLICKHOUSE_PASSWORD=
REDIS_URL=redis://127.0.0.1:6379/0
# For Redis Cloud / redis.io in production:
# REDIS_URL=rediss://default:<password>@<host>:<port>/0LOGISTER_CLICKHOUSE_URL supports both:
- native ClickHouse HTTP endpoint (for example
https://<host>:8443) - ClickHouse Query API endpoint (for example
https://queries.clickhouse.cloud/service/<id>/run?format=JSONEachRow)
- Schema and materialized view:
docs/clickhouse_schema.sql - Starter dashboard queries:
docs/clickhouse_dashboard_queries.sql
GET /health/clickhouse- Returns
200when disabled or healthy;503when enabled but unreachable.
project_id<- authenticated API key's projectapi_key_id<- authenticated API key idoccurred_at<-event.occurred_at(fallback set in Rails)event_type<-event.event_typelevel<-event.levelfingerprint<-event.fingerprint(or generated fallback)message<-event.messageenvironment<-event.context.environment(fallbackRails.env)service<-event.context.service(fallback project slug)release<-event.context.releaseexception_class<-event.context.exception_classorevent.context.exception.classtransaction_name<-event.context.transaction_nametags<-event.context.tagscontext_json<- fullevent.context
logister-ruby is released at 0.1.2 and provides error + metric reporting for Rails apps.
To upgrade a client app:
gem "logister-ruby", "~> 0.1.2"Enable database timing metrics in the client initializer:
Logister.configure do |config|
config.capture_db_metrics = true
config.db_metric_min_duration_ms = 10.0
config.db_metric_sample_rate = 1.0
end