#!/bin/bash # Collect server metrics every minute — called by cron # Appends JSON lines to analytics.jsonl ANALYTICS_FILE="/home/minecraft/server/analytics.jsonl" RCON_PASS="23991818cc169249f181436f2a29a013" # Check if server is running if ! systemctl is-active --quiet minecraft.service; then exit 0 fi # Get MC server PID MC_PID=$(pgrep -f 'minecraft.*server' | head -1) if [ -z "$MC_PID" ]; then MC_PID=$(pgrep -f 'java.*forge' | head -1) fi # TPS via RCON TPS="0" TPS_RAW=$(echo -e "\x00" | timeout 3 python3 -c " from rcon.source import Client try: with Client('127.0.0.1', 25575, passwd='${RCON_PASS}') as c: r = c.run('forge tps') print(r) except: pass " 2>/dev/null) if echo "$TPS_RAW" | grep -q "Overall"; then TPS=$(echo "$TPS_RAW" | grep "Overall" | grep -oP '[\d.]+(?= TPS)' | head -1) elif echo "$TPS_RAW" | grep -q "Dim 0"; then TPS=$(echo "$TPS_RAW" | grep "Dim 0\|overworld" | grep -oP '[\d.]+(?= TPS)' | head -1) fi [ -z "$TPS" ] && TPS="0" # RAM from /proc RAM_USED=0 RAM_TOTAL=8192 if [ -n "$MC_PID" ] && [ -f "/proc/$MC_PID/status" ]; then RAM_KB=$(grep VmRSS "/proc/$MC_PID/status" 2>/dev/null | awk '{print $2}') [ -n "$RAM_KB" ] && RAM_USED=$((RAM_KB / 1024)) fi # CPU CPU="0" if [ -n "$MC_PID" ]; then CPU=$(ps -p "$MC_PID" -o %cpu --no-headers 2>/dev/null | tr -d ' ') fi [ -z "$CPU" ] && CPU="0" # Players via RCON PLAYERS_JSON="[]" PLAYERS_ONLINE=0 PLAYERS_RAW=$(timeout 3 python3 -c " from rcon.source import Client try: with Client('127.0.0.1', 25575, passwd='${RCON_PASS}') as c: r = c.run('list') print(r) except: pass " 2>/dev/null) if echo "$PLAYERS_RAW" | grep -q "players online"; then PLAYERS_ONLINE=$(echo "$PLAYERS_RAW" | grep -oP '\d+(?= of)' | head -1) NAMES=$(echo "$PLAYERS_RAW" | sed 's/.*: //') if [ "$PLAYERS_ONLINE" -gt 0 ] 2>/dev/null && [ -n "$NAMES" ]; then PLAYERS_JSON=$(echo "$NAMES" | python3 -c "import sys,json; print(json.dumps([n.strip() for n in sys.stdin.read().split(',') if n.strip()]))") fi fi [ -z "$PLAYERS_ONLINE" ] && PLAYERS_ONLINE=0 # Timestamp TS=$(date -u +%Y-%m-%dT%H:%M:%SZ) # Write JSON line echo "{\"ts\":\"$TS\",\"tps\":$TPS,\"ramUsedMB\":$RAM_USED,\"ramTotalMB\":$RAM_TOTAL,\"cpuPercent\":$CPU,\"playersOnline\":$PLAYERS_ONLINE,\"players\":$PLAYERS_JSON}" >> "$ANALYTICS_FILE" # Keep only last 48 hours of data (2880 lines at 1/min) if [ $(wc -l < "$ANALYTICS_FILE") -gt 3000 ]; then tail -n 2880 "$ANALYTICS_FILE" > "$ANALYTICS_FILE.tmp" mv "$ANALYTICS_FILE.tmp" "$ANALYTICS_FILE" fi