Files
vesti/scripts/vesti-metrics.sh
T

140 lines
5.9 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/bin/bash
# VESTI — textfile-коллектор для node-exporter (bigbox).
# Пишет /var/lib/node_exporter/textfile_collector/vesti.prom (Prometheus-формат).
# Метрики:
# vesti_web_up 1 = веб :8400 отвечает 200
# vesti_publisher_health 1 = publisher :8410 /healthz ок, 0 = нет
# vesti_publisher_bot 1 = publisher отвечает, объект bot задан
# vesti_publisher_proxy 1 = publisher отвечает, proxy задан
# vesti_publisher_channels N = число каналов из healthz
# vesti_telegram_tunnel 1 = SOCKS5-туннель :1080 слушает
# vesti_publisher_docker 1 = контейнер vesti-publisher running
# vesti_web_systemd 1 = юнит vesti-web.active
# vesti_db_ok 1 = БД vesti.db открывается
# vesti_db_posts_total N = постов в БД
# vesti_db_new_total N = постов со статусом 'new'
# vesti_db_published_total N = постов 'published'
# vesti_db_last_run_ts unix-ts последнего run (0, если нет)
#
# Помечено label'ом component="vesti". Скрипт тихий: всегда успех, файл пишется
# атомарно (tmp+mv). Периодичность — systemd timer (vesti-metrics.timer) каждые 30с.
set -u
OUT=/var/lib/node_exporter/textfile_collector/vesti.prom
TMP="${OUT}.tmp"
# --- безопасные подстановки: число или 0, строка без кавычек/переводов ---
clean() { tr -cd '0-9' <<<"$1"; }
cleanstr() { tr -d '\n\r"' <<<"$1"; }
web_up=0; pub_health=0; pub_bot=0; pub_proxy=0; pub_channels=0
tunnel=0; pub_docker=0; web_sys=0; db_ok=0
posts=0; new=0; published=0; last_run=0
# 1) веб :8400 — достаточно login-страницы (200)
if curl -sf --max-time 5 -o /dev/null http://127.0.0.1:8400/login; then
web_up=1
fi
# 2) publisher :8410 /healthz — JSON
HEALTH=$(curl -sf --max-time 5 http://127.0.0.1:8410/healthz 2>/dev/null) && pub_health=1
if [ -n "$HEALTH" ]; then
# {"status":"ok","bot":"...","token_set":true,"proxy":"...","channels":[...]}
case "$HEALTH" in
*'"bot"'*'"'*) pub_bot=1 ;;
esac
case "$HEALTH" in
*'"proxy"'*'"'*) pub_proxy=1 ;;
esac
# число каналов
CH=$(grep -o '\[[^]]*\]' <<<"$HEALTH" | head -1 | tr -cd ',"@0-9a-zA-Z_.-' | grep -o '@' | wc -l)
# если нет массива — нет каналов
pub_channels=$(clean "$CH")
fi
# 3) SOCKS5-туннель :1080 (tcp connect)
if timeout 5 bash -c 'exec 3<>/dev/tcp/127.0.0.1/1080' 2>/dev/null; then
tunnel=1
fi
# 4) контейнер vesti-publisher
if docker ps --filter name=^vesti-publisher$ --filter status=running --format '{{.Names}}' 2>/dev/null | grep -q vesti-publisher; then
pub_docker=1
fi
# 5) systemd vesti-web
if systemctl is-active --quiet vesti-web; then
web_sys=1
fi
# 6) БД vesti.db
if DB=$(/opt/vesti/.venv/bin/python - <<'PY' 2>/dev/null
import sqlite3
c = sqlite3.connect('/opt/vesti/db/vesti.db', timeout=5)
def one(q):
try:
return c.execute(q).fetchone()[0]
except Exception:
return None
posts = one('SELECT count(*) FROM posts') or 0
new = one("SELECT count(*) FROM posts WHERE status='new'") or 0
pub = one("SELECT count(*) FROM posts WHERE status='published'") or 0
run = one('SELECT max(started_at) FROM runs')
import datetime as dt
ts = 0
if run:
try:
ts = int(dt.datetime.fromisoformat(run).timestamp())
except Exception:
ts = 0
print(posts, new, pub, ts)
PY
); then
db_ok=1
set -- $DB
posts=$(clean "${1:-0}"); new=$(clean "${2:-0}"); published=$(clean "${3:-0}"); last_run=$(clean "${4:-0}")
fi
# --- запись (атомарно) ---
{
echo '# HELP vesti_web_up VESTI web :8400 responds'
echo '# TYPE vesti_web_up gauge'
echo "vesti_web_up{component=\"vesti\"} $web_up"
echo '# HELP vesti_publisher_health VESTI publisher :8410 /healthz ok'
echo '# TYPE vesti_publisher_health gauge'
echo "vesti_publisher_health{component=\"vesti\"} $pub_health"
echo '# HELP vesti_publisher_bot publisher reports bot identity'
echo '# TYPE vesti_publisher_bot gauge'
echo "vesti_publisher_bot{component=\"vesti\"} $pub_bot"
echo '# HELP vesti_publisher_proxy publisher reports SOCKS5 proxy'
echo '# TYPE vesti_publisher_proxy gauge'
echo "vesti_publisher_proxy{component=\"vesti\"} $pub_proxy"
echo '# HELP vesti_publisher_channels number of channels in publisher healthz'
echo '# TYPE vesti_publisher_channels gauge'
echo "vesti_publisher_channels{component=\"vesti\"} $pub_channels"
echo '# HELP vesti_telegram_tunnel SOCKS5 tunnel :1080 listening'
echo '# TYPE vesti_telegram_tunnel gauge'
echo "vesti_telegram_tunnel{component=\"vesti\"} $tunnel"
echo '# HELP vesti_publisher_docker vesti-publisher container running'
echo '# TYPE vesti_publisher_docker gauge'
echo "vesti_publisher_docker{component=\"vesti\"} $pub_docker"
echo '# HELP vesti_web_systemd vesti-web systemd unit active'
echo '# TYPE vesti_web_systemd gauge'
echo "vesti_web_systemd{component=\"vesti\"} $web_sys"
echo '# HELP vesti_db_ok vesti.db accessible'
echo '# TYPE vesti_db_ok gauge'
echo "vesti_db_ok{component=\"vesti\"} $db_ok"
echo '# HELP vesti_db_posts_total posts in DB'
echo '# TYPE vesti_db_posts_total gauge'
echo "vesti_db_posts_total{component=\"vesti\"} $posts"
echo '# HELP vesti_db_new_total posts with status=new'
echo '# TYPE vesti_db_new_total gauge'
echo "vesti_db_new_total{component=\"vesti\"} $new"
echo '# HELP vesti_db_published_total posts with status=published'
echo '# TYPE vesti_db_published_total gauge'
echo "vesti_db_published_total{component=\"vesti\"} $published"
echo '# HELP vesti_db_last_run_ts unix ts of last crawler run'
echo '# TYPE vesti_db_last_run_ts gauge'
echo "vesti_db_last_run_ts{component=\"vesti\"} $last_run"
} > "$TMP" && chown prometheus:prometheus "$TMP" && chmod 644 "$TMP" && mv -f "$TMP" "$OUT"
exit 0