Skip to content

ops: ship docker logs to Better Stack via Vector sidecar#23

Merged
rainxchzed merged 3 commits into
mainfrom
ops/betterstack-logging
May 26, 2026
Merged

ops: ship docker logs to Better Stack via Vector sidecar#23
rainxchzed merged 3 commits into
mainfrom
ops/betterstack-logging

Conversation

@rainxchzed
Copy link
Copy Markdown
Member

@rainxchzed rainxchzed commented May 25, 2026

Adds a Vector container that scrapes the host's docker socket (read-only) and ships every container's stdout/stderr to Better Stack as NDJSON. One agent covers both the free-tier stack and paid-backend stack because the socket sees every container regardless of which compose file launched them.

Files

  • `ops/vector.toml` — source/transform/sink config; bearer token via env
  • `docker-compose.prod.yml` — new `vector` service with read-only `docker.sock` mount
  • `.env.example` — `BETTERSTACK_SOURCE_TOKEN` + `BETTERSTACK_INGEST_HOST` placeholders

Operator steps before deploy

  1. Append to `/opt/github-store-backend/.env` on VPS:
    ```
    BETTERSTACK_SOURCE_TOKEN=
    BETTERSTACK_INGEST_HOST=<sNNNNNNN.eu-fsn-3.betterstackdata.com>
    ```
  2. `./deploy.sh` → `docker compose up -d --build vector` will start the agent.
  3. Verify in Better Stack → Logs that events arrive within ~30s.

Post-merge alert wiring

Create in Better Stack UI → Logs → Alerts:

  • Trigger: message matches `Flyway repair: \d+ entries modified` AND captured N > 0
  • Channel: Email (or Slack if integrated)
  • Description: "Migration checksum drift — operator must verify the repair matches a known migration content edit. Unexpected fires indicate manual DB tampering or a deploy gone wrong."

Also worth adding (low-effort follow-ups):

  • Alert on any `ERROR` level log from `app` or `paid-app` containers
  • Alert on `OAuth` 5xx spikes

Summary by CodeRabbit

  • Chores
    • Added centralized log collection in production via a new log-shipping service to send container logs to Better Stack for improved monitoring.
    • Introduced environment configuration variables to enable Better Stack ingestion; leaving them blank preserves local development behavior.
    • Configured the shipper with buffering, retry, and limited local logging to prevent self-logging and ensure reliable delivery.

Review Change Stack

Vector scrapes the host docker socket read-only so a single agent covers
both the free-tier stack (this compose) and the paid-backend stack
(separate compose at /opt/paid-backend). Logs go to Better Stack via
their HTTPS NDJSON ingest with a bearer token sourced from .env.

The config tags each event with the originating container name so
dashboard filters can split free-tier from paid-backend traffic, and
explicitly excludes Vector's own logs from the source to prevent the
agent from billing itself for its own chatter.

Operator step: paste BETTERSTACK_SOURCE_TOKEN and BETTERSTACK_INGEST_HOST
into /opt/github-store-backend/.env on the VPS before redeploying.
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 25, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: e4511ea1-6861-4a3e-82b4-eff3c0d6de9b

📥 Commits

Reviewing files that changed from the base of the PR and between dc2613c and 35320fe.

📒 Files selected for processing (1)
  • ops/vector.toml

📝 Walkthrough

Walkthrough

This PR adds Better Stack env vars, a Vector service to production docker-compose, and a Vector config to collect, tag, and forward container logs to Better Stack.

Changes

Better Stack Centralized Logging Infrastructure

Layer / File(s) Summary
Environment configuration for Better Stack
./.env.example
Introduces BETTERSTACK_SOURCE_TOKEN and BETTERSTACK_INGEST_HOST variables with documentation noting they are intended blank for local development while the Vector sidecar is prod-only.
Vector service deployment
docker-compose.prod.yml
Adds a vector service running Timber.io Vector v0.45.0-alpine with read-only Docker socket and ops/vector.toml config mount, environment credentials, and local json-file logging rotation to limit self-logging.
Vector log pipeline configuration
ops/vector.toml
Defines Vector pipeline: sources.docker collects container logs (excluding Vector), a remap transform derives .service and sets .host, and an HTTP sink posts gzip-compressed newline-delimited JSON to Better Stack using bearer-token auth with buffering and retry/drop settings.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 I hop through logs at break of day,
Gathering stdout on my way,
I tag each service, tuck host in a stack,
Then knead the JSON and send it back,
To Better Stack they leap—hip, hop, hooray!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: adding a Vector sidecar service to ship Docker logs to Better Stack in production.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch ops/betterstack-logging

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented May 25, 2026

Greptile Summary

This PR introduces a Vector sidecar container that attaches to the host Docker socket and ships structured logs from every container on the VPS to Better Stack over HTTPS, using a bearer token injected via environment variables.

  • ops/vector.toml defines the source (all Docker containers, with Vector self-excluded via prefix patterns), a remap transform that tags each event with a service and host field, and an HTTP sink with gzip + NDJSON encoding, a 5 000-event memory buffer, and 5 retry attempts.
  • docker-compose.prod.yml adds the vector service (pinned to timberio/vector:0.45.0-alpine) with a read-only docker.sock mount and its own json-file logging to avoid self-ingestion loops.
  • .env.example documents the two new required variables (BETTERSTACK_SOURCE_TOKEN, BETTERSTACK_INGEST_HOST) with clear operator guidance.

Confidence Score: 4/5

Safe to deploy, but two concerns flagged in earlier review threads — the buffer overflow behaviour (drop_newest discards the most recent events) and the unrestricted Docker API access via the socket mount — remain unaddressed in this version of the code.

The Vector sidecar is correctly wired: auth is injected via environment variables and never committed, the image is pinned to an exact tag, Vector's own logs are excluded from the shipping pipeline, and the .env.example guidance is clear. The open questions about buffer drop policy and Docker API scope noted in earlier review threads still exist in the code as written.

ops/vector.toml — buffer configuration and the self-exclusion comment around matching semantics are worth a final read; docker-compose.prod.yml — Vector service is the only one without a Docker healthcheck.

Important Files Changed

Filename Overview
ops/vector.toml New Vector configuration: scrapes all Docker containers via host socket, transforms with a hardcoded VPS hostname, and ships NDJSON to Better Stack. Buffer policy (drop_newest) and docker.sock scope were flagged in earlier review threads and remain unresolved.
docker-compose.prod.yml Adds the Vector sidecar service with a read-only docker.sock mount and env-var auth injection. No healthcheck configured, unlike all other services; docker.sock write-access concern acknowledged but not yet mitigated.
.env.example Adds two new placeholder variables (BETTERSTACK_SOURCE_TOKEN, BETTERSTACK_INGEST_HOST) with clear guidance; no issues found.

Sequence Diagram

sequenceDiagram
    participant DC as Docker Daemon
    participant V as Vector (sidecar)
    participant BS as Better Stack

    DC->>V: stdout/stderr streams (via /var/run/docker.sock)
    Note over V: docker_logs source excludes vector-* containers
    V->>V: remap transform — adds .service + .host fields
    V->>V: buffer (memory, 5 000 events)
    V->>BS: POST NDJSON (gzip) Authorization: Bearer $TOKEN
    BS-->>V: 2xx OK
    Note over V: On failure: retry x5 — buffer full drop_newest
Loading

Fix All in Claude Code

Reviews (3): Last reviewed commit: "Merge branch 'main' into ops/betterstack..." | Re-trigger Greptile

Comment thread docker-compose.prod.yml
Comment thread ops/vector.toml
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@ops/vector.toml`:
- Line 15: The current exclusion exclude_containers = ["vector"] is brittle
because Docker Compose prefixes container names, so update the Vector source
configuration to exclude by a stable identifier instead of exact name: change
the exclusion to use container labels (e.g., exclude containers with the label
com.docker.compose.service=vector) or to a pattern match that covers Compose
prefixes (e.g., a wildcard/regex matching "vector" if the config supports it).
Locate the exclude_containers setting in vector.toml and replace or augment it
with label-based exclusion (or a supported glob/regex) so any Compose-prefixed
container like github-store-backend-vector-1 is reliably excluded.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: dc92b8e4-3dd4-422d-9198-8f763651fa82

📥 Commits

Reviewing files that changed from the base of the PR and between 15f62a4 and dc2613c.

📒 Files selected for processing (3)
  • .env.example
  • docker-compose.prod.yml
  • ops/vector.toml

Comment thread ops/vector.toml Outdated
CodeRabbit: exclude_containers = ["vector"] doesn't fire under Docker
Compose because Compose prefixes container names with the project +
index (github-store-backend-vector-1). Added all the prefixed variants
so Vector consistently skips its own logs regardless of which Compose
stack launches it.

Greptile: documented the docker.sock :ro caveat — the read-only flag
restricts the socket FILE, not the Docker API operations. A Vector
compromise would have full container management privileges on the
host. Mitigated by image pinning + single-tenant VPS; upgrade path
via tecnativa/docker-socket-proxy documented in the header.
@rainxchzed rainxchzed merged commit 3f9880f into main May 26, 2026
2 checks passed
@rainxchzed rainxchzed deleted the ops/betterstack-logging branch May 26, 2026 09:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant