#!/usr/bin/env bash
set -euo pipefail

ROOT=$(CDPATH='' cd -- "$(dirname -- "$0")/.." && pwd)
ENV_FILE="$ROOT/.env.load"
LABEL=${1:-"observability-$(date -u +%Y%m%dT%H%M%SZ)"}

if [[ ! -f "$ENV_FILE" ]]; then
  echo "Missing $ENV_FILE. Run scripts/ensure-local-load-env.sh first." >&2
  exit 1
fi

set -a
# shellcheck source=/dev/null
. "$ENV_FILE"
set +a

for name in LOAD_PROJECT LOAD_WEB_REPLICAS LOAD_WORKER_REPLICAS POSTGRES_DB METRICS_TOKEN \
  OBSERVABILITY_PROMETHEUS_PORT OBSERVABILITY_ALERTMANAGER_PORT \
  OBSERVABILITY_GRAFANA_PORT OBSERVABILITY_SCRAPE_INTERVAL \
  OBSERVABILITY_EVALUATION_INTERVAL OBSERVABILITY_TIMEOUT_SECONDS \
  OBSERVABILITY_GRAFANA_ADMIN_USER OBSERVABILITY_GRAFANA_ADMIN_PASSWORD; do
  if [[ -z "${!name:-}" ]]; then
    echo "$name is missing from .env.load" >&2
    exit 1
  fi
done

if [[ "$LOAD_PROJECT" == "who_need_help" ]]; then
  echo "The observability drill must not use the staging Compose project." >&2
  exit 1
fi

if [[ ! "$LABEL" =~ ^[A-Za-z0-9._-]+$ ]]; then
  echo "Run label may contain only letters, numbers, dot, underscore, and dash." >&2
  exit 1
fi

for name in LOAD_WEB_REPLICAS LOAD_WORKER_REPLICAS; do
  if [[ ! "${!name}" =~ ^[1-9][0-9]*$ ]]; then
    echo "$name must be a positive integer." >&2
    exit 1
  fi
done

for name in OBSERVABILITY_PROMETHEUS_PORT OBSERVABILITY_ALERTMANAGER_PORT \
  OBSERVABILITY_GRAFANA_PORT; do
  if [[ ! "${!name}" =~ ^[0-9]+$ ]] || ((10#${!name} > 65535)); then
    echo "$name must be a TCP port number from 0 through 65535." >&2
    exit 1
  fi
done

for name in OBSERVABILITY_SCRAPE_INTERVAL OBSERVABILITY_EVALUATION_INTERVAL; do
  if [[ ! "${!name}" =~ ^[1-9][0-9]*(ms|s|m|h)$ ]]; then
    echo "$name must be a positive Prometheus duration using ms, s, m, or h." >&2
    exit 1
  fi
done

if [[ ! "$OBSERVABILITY_TIMEOUT_SECONDS" =~ ^[1-9][0-9]*$ ]]; then
  echo "OBSERVABILITY_TIMEOUT_SECONDS must be a positive integer." >&2
  exit 1
fi

for command in curl docker jq sed; do
  if ! command -v "$command" >/dev/null 2>&1; then
    echo "Required command is unavailable: $command" >&2
    exit 1
  fi
done

runtime_dir="$ROOT/tmp/observability/$LOAD_PROJECT"
output_dir="$ROOT/output/observability/$LABEL"
prometheus_runtime="$runtime_dir/prometheus"
grafana_runtime="$runtime_dir/grafana"

if [[ -e "$output_dir" ]]; then
  echo "Output already exists: $output_dir" >&2
  exit 1
fi

mkdir -p "$prometheus_runtime" "$grafana_runtime" "$output_dir"
chmod 700 "$ROOT/tmp" "$ROOT/tmp/observability" "$runtime_dir" \
  "$ROOT/output" "$ROOT/output/observability" "$output_dir"

export OBSERVABILITY_RUNTIME_DIR="$runtime_dir"

set_runtime_owner() {
  local directory=$1
  local owner=$2

  docker run --rm \
    --user 0:0 \
    --volume "$directory:/runtime" \
    --entrypoint /bin/sh \
    python:3.14.6-alpine3.23@sha256:b165067c5afc37fa5608a3c05609cc3d51aafd808a30fbfd822ee594fef55ad4 \
    -euc "chown -R $owner /runtime; chmod 700 /runtime"
}

host_owner="$(id -u):$(id -g)"
set_runtime_owner "$prometheus_runtime" "$host_owner"
set_runtime_owner "$grafana_runtime" "$host_owner"

compose=(
  docker compose
  --env-file "$ENV_FILE"
  -p "$LOAD_PROJECT"
  -f compose.yaml
  -f compose.load.yaml
  -f compose.observability.yaml
  --profile observability
)

service_ids() {
  "${compose[@]}" ps --all -q "$1"
}

assert_scope() {
  local container_id=$1
  local expected_service=$2
  local observed_project observed_service

  observed_project=$(
    docker inspect --format '{{index .Config.Labels "com.docker.compose.project"}}' \
      "$container_id"
  )
  observed_service=$(
    docker inspect --format '{{index .Config.Labels "com.docker.compose.service"}}' \
      "$container_id"
  )

  if [[ "$observed_project" != "$LOAD_PROJECT" ||
    "$observed_service" != "$expected_service" ]]; then
    echo "Container scope mismatch for $container_id." >&2
    exit 1
  fi
}

wait_for_web() {
  local container_id=$1
  local deadline=$((SECONDS + OBSERVABILITY_TIMEOUT_SECONDS))

  while ((SECONDS < deadline)); do
    local state health
    state=$(docker inspect --format '{{.State.Status}}' "$container_id")
    health=$(docker inspect --format '{{if .State.Health}}{{.State.Health.Status}}{{end}}' \
      "$container_id")

    if [[ "$state" == "running" && "$health" == "healthy" ]]; then
      return 0
    fi

    sleep 1
  done

  echo "Timed out waiting for web container $container_id to become healthy." >&2
  return 1
}

database_snapshot() {
  # Variables are intentionally expanded inside the isolated PostGIS container.
  # shellcheck disable=SC2016
  "${compose[@]}" exec -T db sh -c \
    'psql --no-psqlrc --tuples-only --no-align --set ON_ERROR_STOP=1 \
      --username "$POSTGRES_USER" --dbname "$POSTGRES_DB"' >"$1" <<'SQL'
BEGIN READ ONLY;
SELECT 'users' AS table_name, count(*) AS row_count FROM users
UNION ALL SELECT 'users_tokens', count(*) FROM users_tokens
UNION ALL SELECT 'help_requests', count(*) FROM help_requests
UNION ALL SELECT 'messages', count(*) FROM messages
UNION ALL SELECT 'categories', count(*) FROM categories
UNION ALL SELECT 'help_assignments', count(*) FROM help_assignments
UNION ALL SELECT 'activities', count(*) FROM activities
UNION ALL SELECT 'reports', count(*) FROM reports
UNION ALL SELECT 'social_identities', count(*) FROM social_identities
UNION ALL SELECT 'tracking_sessions', count(*) FROM tracking_sessions
UNION ALL SELECT 'tracking_positions', count(*) FROM tracking_positions
UNION ALL SELECT 'schema_migrations', count(*) FROM schema_migrations
ORDER BY table_name;
COMMIT;
SQL
}

published_url() {
  local service=$1
  local target_port=$2
  local published

  published=$("${compose[@]}" port "$service" "$target_port" | head -n 1)

  if [[ ! "$published" =~ ^127[.]0[.]0[.]1:([1-9][0-9]*)$ ]]; then
    echo "The $service port is not bound to an observed loopback port." >&2
    return 1
  fi

  printf 'http://%s' "$published"
}

wait_for_http() {
  local url=$1
  shift
  local deadline=$((SECONDS + OBSERVABILITY_TIMEOUT_SECONDS))

  while ((SECONDS < deadline)); do
    if curl --fail --silent --show-error "$@" "$url" >/dev/null 2>&1; then
      return 0
    fi

    sleep 1
  done

  echo "Timed out waiting for $url." >&2
  return 1
}

fetch_receiver_events() {
  local receiver_id
  receiver_id=$(service_ids alert-receiver | head -n 1)
  assert_scope "$receiver_id" alert-receiver
  docker exec "$receiver_id" \
    python -c \
    'import urllib.request; print(urllib.request.urlopen("http://127.0.0.1:8080/events", timeout=2).read().decode())'
}

wait_for_targets_up() {
  local expected_web=$1
  local expected_worker=$2
  local deadline=$((SECONDS + OBSERVABILITY_TIMEOUT_SECONDS))

  while ((SECONDS < deadline)); do
    if curl --fail --silent --show-error \
      "$prometheus_url/api/v1/targets?state=active" \
      >"$output_dir/targets-current.json" 2>/dev/null &&
      jq -e \
        --argjson expected_web "$expected_web" \
        --argjson expected_worker "$expected_worker" \
        --arg run_id "$LABEL" '
        [
          .data.activeTargets[]
          | select(
              .labels.job == "who-need-help-web" and
              .labels.run_id == $run_id
            )
        ] as $web_targets
        | [
            .data.activeTargets[]
            | select(
                .labels.job == "who-need-help-worker" and
                .labels.run_id == $run_id
              )
          ] as $worker_targets
        | ($web_targets | length) == $expected_web
          and ($worker_targets | length) == $expected_worker
          and all($web_targets[]; .health == "up")
          and all($worker_targets[]; .health == "up")
      ' "$output_dir/targets-current.json" >/dev/null; then
      return 0
    fi

    sleep 1
  done

  echo "Timed out waiting for every direct web and worker metrics target." >&2
  return 1
}

wait_for_firing_alert() {
  local instance=$1
  local deadline=$((SECONDS + OBSERVABILITY_TIMEOUT_SECONDS))

  while ((SECONDS < deadline)); do
    if curl --fail --silent --show-error "$prometheus_url/api/v1/alerts" \
      >"$output_dir/prometheus-alerts-firing.json" 2>/dev/null &&
      jq -e --arg instance "$instance" --arg run_id "$LABEL" '
        any(
          .data.alerts[];
          .state == "firing" and
          .labels.alertname == "WhoNeedHelpWebReplicaUnavailable" and
          .labels.instance == $instance and
          .labels.run_id == $run_id
        )
      ' "$output_dir/prometheus-alerts-firing.json" >/dev/null; then
      return 0
    fi

    sleep 1
  done

  echo "Timed out waiting for the induced Prometheus alert." >&2
  return 1
}

wait_for_webhook_status() {
  local instance=$1
  local expected_status=$2
  local destination=$3
  local deadline=$((SECONDS + OBSERVABILITY_TIMEOUT_SECONDS))

  while ((SECONDS < deadline)); do
    if fetch_receiver_events >"$destination" 2>/dev/null &&
      jq -e \
        --arg instance "$instance" \
        --arg run_id "$LABEL" \
        --arg expected_status "$expected_status" '
          any(
            .[].payload.alerts[];
            .status == $expected_status and
            .labels.alertname == "WhoNeedHelpWebReplicaUnavailable" and
            .labels.instance == $instance and
            .labels.run_id == $run_id
          )
        ' "$destination" >/dev/null; then
      return 0
    fi

    sleep 1
  done

  echo "Timed out waiting for the $expected_status Alertmanager webhook." >&2
  return 1
}

wait_for_alert_clear() {
  local instance=$1
  local deadline=$((SECONDS + OBSERVABILITY_TIMEOUT_SECONDS))

  while ((SECONDS < deadline)); do
    if curl --fail --silent --show-error "$prometheus_url/api/v1/alerts" \
      >"$output_dir/prometheus-alerts-resolved.json" 2>/dev/null &&
      jq -e --arg instance "$instance" --arg run_id "$LABEL" '
        all(
          .data.alerts[];
          .labels.alertname != "WhoNeedHelpWebReplicaUnavailable" or
          .labels.instance != $instance or
          .labels.run_id != $run_id or
          .state != "firing"
        )
      ' "$output_dir/prometheus-alerts-resolved.json" >/dev/null; then
      return 0
    fi

    sleep 1
  done

  echo "Timed out waiting for the induced Prometheus alert to resolve." >&2
  return 1
}

restore_web() {
  if [[ -n "${drill_web_id:-}" ]]; then
    local state
    state=$(docker inspect --format '{{.State.Status}}' "$drill_web_id" 2>/dev/null || true)

    if [[ "$state" != "running" ]]; then
      docker start "$drill_web_id" >/dev/null 2>&1 || true
    fi

    wait_for_web "$drill_web_id" >/dev/null 2>&1 || true
  fi
}

cleanup() {
  local status=$?
  trap - EXIT HUP INT TERM
  restore_web
  exit "$status"
}

trap cleanup EXIT HUP INT TERM

mapfile -t web_ids < <(service_ids web)
mapfile -t worker_ids < <(service_ids worker)

if [[ "${#web_ids[@]}" -ne "$LOAD_WEB_REPLICAS" ]]; then
  echo "Expected $LOAD_WEB_REPLICAS running load web replicas; observed ${#web_ids[@]}." >&2
  exit 1
fi

if [[ "${#worker_ids[@]}" -ne "$LOAD_WORKER_REPLICAS" ]]; then
  echo "Expected $LOAD_WORKER_REPLICAS running load worker replicas; observed ${#worker_ids[@]}." >&2
  exit 1
fi

internal_network=$(
  docker network ls \
    --filter "label=com.docker.compose.project=$LOAD_PROJECT" \
    --filter "label=com.docker.compose.network=internal" \
    --format '{{.Name}}'
)

if [[ -z "$internal_network" || "$internal_network" == *$'\n'* ]]; then
  echo "Expected exactly one observed Compose internal network." >&2
  exit 1
fi

target_lines="$prometheus_runtime/web-targets.jsonl"
: >"$target_lines"

for web_id in "${web_ids[@]}"; do
  assert_scope "$web_id" web
  wait_for_web "$web_id"
  web_name=$(docker inspect --format '{{.Name}}' "$web_id")
  web_name=${web_name#/}
  web_ip=$(
    docker inspect \
      --format "{{with index .NetworkSettings.Networks \"$internal_network\"}}{{.IPAddress}}{{end}}" \
      "$web_id"
  )

  if [[ ! "$web_ip" =~ ^[0-9]+([.][0-9]+){3}$ ]]; then
    echo "No observed IPv4 address for $web_name on $internal_network." >&2
    exit 1
  fi

  jq -cn \
    --arg target "$web_ip:4000" \
    --arg instance "$web_name" \
    --arg compose_project "$LOAD_PROJECT" \
    --arg run_id "$LABEL" \
    '{
      targets: [$target],
      labels: {
        instance: $instance,
        compose_project: $compose_project,
        run_id: $run_id
      }
    }' >>"$target_lines"
done

jq -s '.' "$target_lines" >"$prometheus_runtime/web-targets.json"
unlink "$target_lines"

target_lines="$prometheus_runtime/worker-targets.jsonl"
: >"$target_lines"

for worker_id in "${worker_ids[@]}"; do
  assert_scope "$worker_id" worker
  wait_for_web "$worker_id"
  worker_name=$(docker inspect --format '{{.Name}}' "$worker_id")
  worker_name=${worker_name#/}
  worker_ip=$(
    docker inspect \
      --format "{{with index .NetworkSettings.Networks \"$internal_network\"}}{{.IPAddress}}{{end}}" \
      "$worker_id"
  )

  if [[ ! "$worker_ip" =~ ^[0-9]+([.][0-9]+){3}$ ]]; then
    echo "No observed IPv4 address for $worker_name on $internal_network." >&2
    exit 1
  fi

  jq -cn \
    --arg target "$worker_ip:4000" \
    --arg instance "$worker_name" \
    --arg compose_project "$LOAD_PROJECT" \
    --arg run_id "$LABEL" \
    '{
      targets: [$target],
      labels: {
        instance: $instance,
        compose_project: $compose_project,
        run_id: $run_id
      }
    }' >>"$target_lines"
done

jq -s '.' "$target_lines" >"$prometheus_runtime/worker-targets.json"
unlink "$target_lines"

sed \
  -e "s/__SCRAPE_INTERVAL__/$OBSERVABILITY_SCRAPE_INTERVAL/g" \
  -e "s/__EVALUATION_INTERVAL__/$OBSERVABILITY_EVALUATION_INTERVAL/g" \
  "$ROOT/ops/observability/prometheus.template.yml" \
  >"$prometheus_runtime/prometheus.yml"
printf '%s' "$METRICS_TOKEN" >"$prometheus_runtime/metrics-token"
printf '%s' "$OBSERVABILITY_GRAFANA_ADMIN_PASSWORD" \
  >"$grafana_runtime/admin-password"
cp "$prometheus_runtime/web-targets.json" "$output_dir/generated-targets.json"
cp "$prometheus_runtime/worker-targets.json" "$output_dir/generated-worker-targets.json"
chmod 600 "$prometheus_runtime/prometheus.yml" \
  "$prometheus_runtime/web-targets.json" \
  "$prometheus_runtime/worker-targets.json" \
  "$prometheus_runtime/metrics-token" \
  "$grafana_runtime/admin-password" \
  "$output_dir/generated-targets.json" \
  "$output_dir/generated-worker-targets.json"
set_runtime_owner "$prometheus_runtime" "65534:65534"
set_runtime_owner "$grafana_runtime" "472:0"

docker run --rm \
  --volume "$prometheus_runtime:/runtime:ro" \
  --volume "$ROOT/ops/observability/rules.yml:/etc/prometheus/rules.yml:ro" \
  --entrypoint /bin/promtool \
  quay.io/prometheus/prometheus:v3.13.1@sha256:3c42b892cf723fa54d2f262c37a0e1f80aa8c8ddb1da7b9b0df9455a35a7f893 \
  check config /runtime/prometheus.yml \
  >"$output_dir/promtool-check.txt"

docker run --rm \
  --volume "$ROOT/ops/observability/alertmanager.yml:/etc/alertmanager/alertmanager.yml:ro" \
  --entrypoint /bin/amtool \
  quay.io/prometheus/alertmanager:v0.33.1@sha256:9e082985f56f4c8c9f724e18f2288c6708f472e56a5286b8863d080434ea065d \
  check-config /etc/alertmanager/alertmanager.yml \
  >"$output_dir/amtool-check.txt"

jq --exit-status 'type == "object" and .uid == "wnh-overview"' \
  "$ROOT/ops/observability/grafana/dashboards/who-need-help-overview.json" \
  >/dev/null

for service in alert-receiver alertmanager prometheus grafana; do
  while IFS= read -r existing_id; do
    [[ -n "$existing_id" ]] && assert_scope "$existing_id" "$service"
  done < <(service_ids "$service")
done

database_snapshot "$output_dir/database-before.txt"

"${compose[@]}" up -d --force-recreate --wait \
  alert-receiver alertmanager prometheus grafana \
  >"$output_dir/compose-up.txt"

for service in alert-receiver alertmanager prometheus grafana; do
  service_id=$(service_ids "$service" | head -n 1)
  assert_scope "$service_id" "$service"
done

prometheus_url=$(published_url prometheus 9090)
alertmanager_url=$(published_url alertmanager 9093)
grafana_url=$(published_url grafana 3000)

wait_for_http "$prometheus_url/-/ready"
wait_for_http "$alertmanager_url/-/ready"
wait_for_http "$grafana_url/api/health"
wait_for_http "$grafana_url/api/datasources/uid/wnh-prometheus/health" \
  --user "$OBSERVABILITY_GRAFANA_ADMIN_USER:$OBSERVABILITY_GRAFANA_ADMIN_PASSWORD"

curl --fail --silent --show-error \
  --user "$OBSERVABILITY_GRAFANA_ADMIN_USER:$OBSERVABILITY_GRAFANA_ADMIN_PASSWORD" \
  "$grafana_url/api/health" >"$output_dir/grafana-health.json"
curl --fail --silent --show-error \
  --user "$OBSERVABILITY_GRAFANA_ADMIN_USER:$OBSERVABILITY_GRAFANA_ADMIN_PASSWORD" \
  "$grafana_url/api/datasources/uid/wnh-prometheus/health" \
  >"$output_dir/grafana-datasource-health.json"
curl --fail --silent --show-error \
  --user "$OBSERVABILITY_GRAFANA_ADMIN_USER:$OBSERVABILITY_GRAFANA_ADMIN_PASSWORD" \
  "$grafana_url/api/dashboards/uid/wnh-overview" \
  >"$output_dir/grafana-dashboard.json"

if ! jq -e '
  .dashboard.uid == "wnh-overview" and
  .meta.provisioned == true and
  (.dashboard.panels | length) == 10
' "$output_dir/grafana-dashboard.json" >/dev/null; then
  echo "The provisioned Grafana dashboard did not match the tracked dashboard." >&2
  exit 1
fi

wait_for_targets_up "$LOAD_WEB_REPLICAS" "$LOAD_WORKER_REPLICAS"
mv "$output_dir/targets-current.json" "$output_dir/targets-before-drill.json"

jq -n \
  --slurpfile expected_web "$output_dir/generated-targets.json" \
  --slurpfile expected_worker "$output_dir/generated-worker-targets.json" \
  --slurpfile observed "$output_dir/targets-before-drill.json" '
    {
      expected_web_instances: ($expected_web[0] | map(.labels.instance) | sort),
      observed_web_instances: (
        $observed[0].data.activeTargets
        | map(select(.labels.job == "who-need-help-web") | .labels.instance)
        | sort
      ),
      expected_worker_instances: ($expected_worker[0] | map(.labels.instance) | sort),
      observed_worker_instances: (
        $observed[0].data.activeTargets
        | map(select(.labels.job == "who-need-help-worker") | .labels.instance)
        | sort
      )
    }
    | . + {
        exact_instance_match:
          (.expected_web_instances == .observed_web_instances and
           .expected_worker_instances == .observed_worker_instances)
      }
  ' >"$output_dir/target-summary.json"

if ! jq -e '.exact_instance_match' "$output_dir/target-summary.json" >/dev/null; then
  echo "Prometheus did not preserve every direct web and worker instance target." >&2
  exit 1
fi

drill_web_id=${web_ids[0]}
assert_scope "$drill_web_id" web
drill_instance=$(docker inspect --format '{{.Name}}' "$drill_web_id")
drill_instance=${drill_instance#/}
docker stop --time 30 "$drill_web_id" >"$output_dir/stopped-web.txt"

wait_for_firing_alert "$drill_instance"
wait_for_webhook_status \
  "$drill_instance" firing "$output_dir/alert-webhooks-firing.json"

docker start "$drill_web_id" >"$output_dir/started-web.txt"
wait_for_web "$drill_web_id"
wait_for_targets_up "$LOAD_WEB_REPLICAS" "$LOAD_WORKER_REPLICAS"
mv "$output_dir/targets-current.json" "$output_dir/targets-after-recovery.json"
wait_for_alert_clear "$drill_instance"
wait_for_webhook_status \
  "$drill_instance" resolved "$output_dir/alert-webhooks-complete.json"

curl --fail --silent --show-error "$alertmanager_url/api/v2/alerts" \
  >"$output_dir/alertmanager-alerts-after-recovery.json"
database_snapshot "$output_dir/database-after.txt"

if ! diff -u "$output_dir/database-before.txt" "$output_dir/database-after.txt" \
  >"$output_dir/database-diff.txt"; then
  echo "The observability drill changed tracked database counts." >&2
  exit 1
fi

"${compose[@]}" ps -a >"$output_dir/compose-after.txt"
mapfile -t compose_container_ids < <("${compose[@]}" ps --all --quiet)
docker inspect "${compose_container_ids[@]}" |
  jq '[
    .[] |
    {
      container: (.Name | ltrimstr("/")),
      configured_image: .Config.Image,
      image_id: .Image,
      service: .Config.Labels["com.docker.compose.service"],
      state: .State.Status
    }
  ]' >"$output_dir/images.json"

jq -n \
  --arg run_id "$LABEL" \
  --arg drill_instance "$drill_instance" \
  --arg prometheus_url "$prometheus_url" \
  --arg alertmanager_url "$alertmanager_url" \
  --arg grafana_url "$grafana_url" \
  --argjson web_replicas "$LOAD_WEB_REPLICAS" \
  --argjson worker_replicas "$LOAD_WORKER_REPLICAS" \
  '{
    run_id: $run_id,
    web_replicas: $web_replicas,
    worker_replicas: $worker_replicas,
    direct_targets_up_before_and_after: true,
    induced_instance: $drill_instance,
    firing_webhook_observed: true,
    resolved_webhook_observed: true,
    database_count_diff_bytes: 0,
    prometheus_url: $prometheus_url,
    alertmanager_url: $alertmanager_url,
    grafana_url: $grafana_url,
    grafana_dashboard_path: "/d/wnh-overview/overview"
  }' >"$output_dir/summary.json"

trap - EXIT HUP INT TERM

printf 'Observability evidence: %s\n' "$output_dir"
printf 'Prometheus: %s\nAlertmanager: %s\nGrafana: %s/d/wnh-overview/overview\n' \
  "$prometheus_url" "$alertmanager_url" "$grafana_url"
printf 'Grafana user: %s; its random password remains only in ignored .env.load.\n' \
  "$OBSERVABILITY_GRAFANA_ADMIN_USER"
