stacks/monitoring/exporters/node-exporter-textfile.sh

#!/usr/bin/env bash
# stacks/monitoring/exporters/node-exporter-textfile.sh
# Emits homelab-specific metrics into node_exporter's textfile collector.
# Run every minute from cron; write atomically via .$$ then mv.
#
# Docs: mercemay.top/src/homelab-compose/

set -euo pipefail

TEXTFILE_DIR="${TEXTFILE_DIR:-/var/lib/node_exporter/textfile}"
OUT="${TEXTFILE_DIR}/homelab.prom"
TMP="${OUT}.$$"

mkdir -p "${TEXTFILE_DIR}"

{
    echo "# HELP homelab_backup_last_success_timestamp_seconds unix ts of last good backup"
    echo "# TYPE homelab_backup_last_success_timestamp_seconds gauge"
    if [[ -f /var/lib/homelab/backup.stamp ]]; then
        ts=$(stat -c %Y /var/lib/homelab/backup.stamp)
        printf 'homelab_backup_last_success_timestamp_seconds %s\n' "${ts}"
    else
        printf 'homelab_backup_last_success_timestamp_seconds 0\n'
    fi

    echo "# HELP homelab_snapshot_count number of btrfs snapshots retained"
    echo "# TYPE homelab_snapshot_count gauge"
    count=$(find /mnt/tank/.snapshots -maxdepth 1 -mindepth 1 -type d 2>/dev/null | wc -l)
    printf 'homelab_snapshot_count %s\n' "${count}"

    echo "# HELP homelab_compose_services running compose services by stack"
    echo "# TYPE homelab_compose_services gauge"
    for stack in monitoring media auth utility; do
        if [[ -d "/srv/homelab/stacks/${stack}" ]]; then
            running=$(docker compose -f "/srv/homelab/stacks/${stack}/docker-compose.yml" \
                ps --status running --format '{{.Service}}' 2>/dev/null | wc -l)
            printf 'homelab_compose_services{stack="%s"} %s\n' "${stack}" "${running}"
        fi
    done

    echo "# HELP homelab_zpool_capacity_ratio zfs pool capacity used"
    echo "# TYPE homelab_zpool_capacity_ratio gauge"
    if command -v zpool >/dev/null 2>&1; then
        while read -r pool cap; do
            cap="${cap%\%}"
            printf 'homelab_zpool_capacity_ratio{pool="%s"} %s\n' "${pool}" "$(awk "BEGIN {print ${cap}/100}")"
        done < <(zpool list -H -o name,capacity 2>/dev/null)
    fi

    echo "# HELP homelab_ups_battery_charge battery percentage reported by apcaccess"
    echo "# TYPE homelab_ups_battery_charge gauge"
    if command -v apcaccess >/dev/null 2>&1; then
        charge=$(apcaccess status 2>/dev/null \
            | awk -F: '/^BCHARGE/ {gsub(/[^0-9.]/,"",$2); print $2; exit}')
        if [[ -n "${charge:-}" ]]; then
            printf 'homelab_ups_battery_charge %s\n' "${charge}"
        fi
    fi
} > "${TMP}"

mv -f "${TMP}" "${OUT}"
chmod 0644 "${OUT}"