# The Alloy log-collector agent. Runs on EACH node (vps1, vps2) — one per node
# — reading that node's Docker containers, Caddy logs, and the app's JSON logs,
# and shipping them to the central Loki on vps1 over the mesh.
#
# Per-node config comes from the environment (an .env file next to this, or
# exported before `up`):
#   ALLOY_NODE   the MACHINE:  vps1 | vps2 | desktop
#   ALLOY_ENV    the default ENVIRONMENT label for logs on this node that
#                aren't attributable to a specific stack (Forgejo, Grafana,
#                the portfolio site): vps1 -> dev, vps2 -> prod
#   APPLOGS_VOLUME  this node's primary applogs volume
#   LOKI_URL     push endpoint. All nodes push over the mesh:
#                http://10.10.0.2:3100/loki/api/v1/push
#
# Deploy on vps1 (dev + Forgejo + the monitoring stack itself):
#   ALLOY_NODE=vps1 ALLOY_ENV=dev APPLOGS_VOLUME=thermograph-dev_applogs \
#   LOKI_URL=http://10.10.0.2:3100/loki/api/v1/push \
#     docker compose -f docker-compose.agent.yml up -d
#
# Deploy on vps2 (prod + beta) — note the SECOND file, which adds beta's log
# volume:
#   ALLOY_NODE=vps2 ALLOY_ENV=prod APPLOGS_VOLUME=thermograph_applogs \
#   BETA_APPLOGS_VOLUME=thermograph-beta_applogs \
#   LOKI_URL=http://10.10.0.2:3100/loki/api/v1/push \
#     docker compose -f docker-compose.agent.yml -f docker-compose.agent.beta.yml up -d
#
# WHY THE VOLUME NAME IS A VARIABLE NOW, AND WHY BETA IS AN OVERLAY. The name
# used to be the literal `thermograph_applogs`, with a comment telling you to
# hand-edit two lines on the dev node. That was survivable while one node ran
# one environment. vps2 runs two, each with its own applogs volume, and a single
# hardcoded mount there would ship one environment's structured logs and
# silently drop the other's.
#
# Beta's mount is a separate overlay file rather than a second variable in this
# one because the second mount is labelled host="beta" unconditionally. Pointing
# it at dev's volume on vps1 just to satisfy compose would ship every dev log
# line a second time labelled as beta — inventing an environment's worth of
# fake data on a box beta does not run on.

services:
  alloy:
    image: grafana/alloy:v1.9.1
    command:
      - run
      - /etc/alloy/config.alloy
      - --storage.path=/var/lib/alloy/data
      - --server.http.listen-addr=0.0.0.0:12345
    environment:
      ALLOY_NODE: ${ALLOY_NODE:?set ALLOY_NODE (vps1|vps2|desktop) — the MACHINE}
      ALLOY_ENV: ${ALLOY_ENV:?set ALLOY_ENV (dev|beta|prod) — this node's default environment label}
      LOKI_URL: ${LOKI_URL:?set LOKI_URL}
    volumes:
      - ./config.alloy:/etc/alloy/config.alloy:ro
      # Read-only Docker socket: discover + tail every container's stdout/stderr.
      - /var/run/docker.sock:/var/run/docker.sock:ro
      # Caddy's host access logs (runs on the host, not a container).
      - /var/log/caddy:/var/log/caddy:ro
      # The app's structured JSON logs, straight off its named volume.
      - applogs:/applogs:ro
      - alloy_data:/var/lib/alloy/data
    restart: unless-stopped

volumes:
  # The app's existing log volume (created by the app's own stack). external:true
  # means compose references it, never creates or deletes it. The NAME varies by
  # node — see the header — while the mount path stays /applogs, which is what
  # lets one config.alloy serve every node.
  applogs:
    external: true
    name: ${APPLOGS_VOLUME:?set APPLOGS_VOLUME (e.g. thermograph_applogs on vps2, thermograph-dev_applogs on vps1)}
  alloy_data: {}
