Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 16 additions & 1 deletion .env.observability.example
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,30 @@ GRAFANA_ROOT_URL=

# ── Web server logs (Promtail) ───────────────────────────────────────────────────
# Directory Promtail scans (recursively) for *access*.log / *error*.log files.
# Must be a real, literal directory — this is a Docker bind-mount source, so
# shell globs (e.g. a trailing `/*/log`) do NOT work; Docker creates an empty
# directory with that literal name instead of expanding it.
# Examples:
# /var/log ← default; covers /var/log/virtualmin,
# /var/log/nginx, /var/log/apache2, etc.
# /home/rubricmaker/web/*/log ← HestiaCP per-domain logs
# /home/rubricmaker/web ← HestiaCP per-domain logs (Promtail's
# own ** glob recurses into each
# domain's logs/ subfolder)
# /var/log/virtualmin ← Virtualmin vhost logs
# Combined docker-compose.yml stack: leave as default — Promtail's Docker scrape
# job picks up the `app` container's stdout logs directly (see nginx.prod.conf).
RUBRICMAKER_LOG_DIR=/var/log

# HestiaCP only: web/<domain>/logs/*.log under RUBRICMAKER_LOG_DIR are usually
# symlinks to the panel's real webserver log dir, e.g. /var/log/apache2/domains
# (Apache) or /var/log/nginx/domains (Nginx) — check with
# `ls -la /home/<user>/web/<domain>/logs/`. Set this to that real target dir so
# the symlinks resolve inside the container; it's mounted at the same absolute
# path. Leave unset/blank on non-HestiaCP setups — when blank, the compose
# file falls back to mounting `/var/log` read-only at the same path, which
# is harmless since Promtail only scrapes `/var/host-logs`.
# RUBRICMAKER_WEBSERVER_LOG_DIR=/var/log/apache2/domains


# ── client_logs (Part 1 app-level diagnostics) ───────────────────────────────────
# Optional: lets Grafana query the `client_logs` table (see README → "Stress-test
Expand Down
5 changes: 5 additions & 0 deletions .github/workflows/deploy-hestiacp.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@ jobs:
VITE_SUPABASE_URL: ${{ secrets.VITE_SUPABASE_URL }}
VITE_SUPABASE_ANON_KEY: ${{ secrets.VITE_SUPABASE_ANON_KEY }}
SUPABASE_PUBLIC_URL: ${{ secrets.SUPABASE_PUBLIC_URL }}
# Optional diagnostic event stream to `client_logs` — see README →
# "Stress-test logging". Toggle via repo Settings → Secrets and
# variables → Actions → Variables (not a secret: it's a feature
# flag, not sensitive data).
VITE_STRESS_TEST_LOGGING: ${{ vars.VITE_STRESS_TEST_LOGGING }}

- name: Deploy via rsync
uses: burnett01/rsync-deployments@9.0.0
Expand Down
24 changes: 20 additions & 4 deletions docker-compose.observability.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,14 @@ services:
# Host log directory for traditional Apache/Nginx + HestiaCP/Virtualmin
# deployments (set RUBRICMAKER_LOG_DIR to the panel's log path).
- ${RUBRICMAKER_LOG_DIR:-/var/log}:/var/host-logs:ro
# HestiaCP's per-domain web/<domain>/logs/*.log files are symlinks to
# the panel's real webserver log dir (e.g. /var/log/apache2/domains) —
# mount that dir too, at the *same* path, so the symlinks resolve
# inside the container instead of "no such file or directory". Falls
# back to /var/log (already guaranteed to exist, unlike an Apache-only
# path) so leaving RUBRICMAKER_WEBSERVER_LOG_DIR unset on non-HestiaCP
# setups is a harmless no-op rather than creating a bogus empty dir.
- ${RUBRICMAKER_WEBSERVER_LOG_DIR:-/var/log}:${RUBRICMAKER_WEBSERVER_LOG_DIR:-/var/log}:ro
# Optional: only relevant if the combined docker-compose.yml stack also
# runs on this host — harmless if these paths don't exist.
- /var/lib/docker/containers:/var/lib/docker/containers:ro
Expand Down Expand Up @@ -76,13 +84,21 @@ volumes:
grafana-data: # persists Grafana dashboards/users

# ── Optional: self-hosted db on the same host ────────────────────────────────
# If the combined docker-compose.yml stack (db, auth, rest, ...) also runs on
# this host and you want Grafana to reach its `db` container by name, join its
# network and set SUPABASE_DB_HOST=db:
# If a self-hosted Supabase stack also runs on this host and you want Grafana
# to reach its db container by name, join its Docker network. The network and
# container names depend on which self-hosted stack this is:
# - This repo's combined docker-compose.yml (`name: rubricmaker`):
# network rubricmaker_default, SUPABASE_DB_HOST=db:5432
# - The official Supabase CLI / self-hosted compose stack:
# network supabase_default, SUPABASE_DB_HOST=supabase-db:5432
# (connect to the `supabase-db` container directly, not the
# `supabase-pooler`/Supavisor container also on 5432/6543)
# Confirm with `docker network ls` / `docker ps` on the host — names can be
# customized in either stack's own compose file.
#
# networks:
# default:
# name: rubricmaker_default
# name: supabase_default
# external: true
#
# Otherwise (managed Supabase, or Supabase on another host), leave this
Expand Down
37 changes: 29 additions & 8 deletions docs/OBSERVABILITY_HESTIACP.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,14 +102,29 @@ Edit `.env.observability`:
GRAFANA_ADMIN_PASSWORD=<choose a strong password>

# HestiaCP per-domain log layout (see .env.observability.example for the
# Virtualmin equivalent). Promtail recurses into this path looking for
# *access*.log / *error*.log files.
RUBRICMAKER_LOG_DIR=/home/rubricmaker/web/*/log
# Virtualmin equivalent). This is a Docker bind-mount source, so it must be a
# real, literal directory — no shell globs (Docker won't expand a `*` in a
# host path; it just creates an empty dir with that literal name and mounts
# that). Point at the parent `web` dir; Promtail's own `**` glob in
# promtail-config.yml recurses into each domain's log/ folder from there.
RUBRICMAKER_LOG_DIR=/home/rubricmaker/web

# Set in step 7, once the subdomain is live.
GRAFANA_DOMAIN=observability.rubricmaker.example.com
GRAFANA_ROOT_URL=https://observability.rubricmaker.example.com/

# HestiaCP's web/<domain>/logs/*.log files are usually symlinks to the
# panel's real webserver log dir — check with
# `ls -la /home/rubricmaker/web/<any-domain>/logs/`. Mount that real target
# dir too (same absolute path) so the symlinks resolve inside the container.
# This doesn't cause duplicate log ingestion: Promtail's only webserver scrape
# path is RUBRICMAKER_LOG_DIR (`/var/host-logs/**` in promtail-config.yml) —
# this second mount isn't separately scraped, it just makes the symlink
# targets resolvable when Promtail follows them.
# Apache (most HestiaCP installs):
RUBRICMAKER_WEBSERVER_LOG_DIR=/var/log/apache2/domains
# Nginx-only HestiaCP installs would instead use /var/log/nginx/domains.

Comment thread
coderabbitai[bot] marked this conversation as resolved.
# Optional — only if you also want client_logs queryable from Grafana
# (see README → "Stress-test logging").
# SUPABASE_DB_HOST=
Expand All @@ -118,11 +133,17 @@ GRAFANA_ROOT_URL=https://observability.rubricmaker.example.com/
# SUPABASE_DB_PASSWORD=
```

> **`RUBRICMAKER_LOG_DIR=/home/rubricmaker/web/*/log` vs `/var/log`:**
> HestiaCP writes per-domain logs to `/home/<user>/web/<domain>/log/` *and*
> aggregates them under `/var/log/$WEB_SYSTEM/domains/`. Either path works;
> the `/home/.../web/*/log` glob is narrower if this HestiaCP user hosts
> multiple unrelated domains and you only want RubricMaker's logs.
> **`RUBRICMAKER_LOG_DIR=/home/rubricmaker/web` vs `/var/log`:**
> HestiaCP writes per-domain logs to `/home/<user>/web/<domain>/logs/` *and*
> aggregates them under `/var/log/$WEB_SYSTEM/domains/`. Either parent path
> works as `RUBRICMAKER_LOG_DIR`, but the per-domain `logs/` entries are
> typically symlinks pointing at the latter — see `RUBRICMAKER_WEBSERVER_LOG_DIR`
> above, which mounts that real target dir so the symlinks don't dangle inside
> the container. To narrow to a single domain if this HestiaCP user hosts
> multiple unrelated ones, point `RUBRICMAKER_LOG_DIR` directly at that
> domain's own `logs/` dir (e.g.
> `/home/rubricmaker/web/rubricmaker.example.com/logs`) — but it must be a
> literal, existing path; wildcards don't work in a bind-mount source.

---

Expand Down
Loading