Monitoring
Server monitoring en alerting setup.
Monitoring Stack
┌─────────────────────────────────────────────────────────────┐
│ Monitoring │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Uptime Kuma │ │ Grafana │ │ Loki │ │
│ │ (Health) │ │ (Metrics) │ │ (Logs) │ │
│ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ │
│ │ │ │ │
│ └────────────────┼────────────────┘ │
│ │ │
│ ┌─────▼─────┐ │
│ │ Alerts │ │
│ │ (Discord) │ │
│ └───────────┘ │
└─────────────────────────────────────────────────────────────┘
│
┌────────────────┼────────────────┐
│ │ │
▼ ▼ ▼
┌───────────┐ ┌───────────┐ ┌───────────┐
│SpacetimeDB│ │ Nginx │ │ R2 │
└───────────┘ └───────────┘ └───────────┘
Uptime Kuma
Simpele uptime monitoring.
Installatie
# Docker
docker run -d \
--name uptime-kuma \
-p 3001:3001 \
-v uptime-kuma:/app/data \
louislam/uptime-kuma:1
Monitors Configureren
-
SpacetimeDB WebSocket
- Type: TCP Port
- Hostname: localhost
- Port: 3000
- Interval: 60s
-
HTTP Health Check
- Type: HTTP(s)
- URL: http://localhost:3000/health
- Interval: 60s
-
Admin Panel
- Type: HTTP(s)
- URL: https://admin.yourdomain.com
- Interval: 300s
Discord Alerts
- Create Discord webhook in server settings
- In Uptime Kuma: Settings → Notifications → Add → Discord
- Paste webhook URL
- Assign to monitors
SpacetimeDB Metrics
Ingebouwde Metrics
# Via CLI
spacetime metrics milenas-treehouse
Output:
- Connected clients
- Reducer calls/sec
- Database size
- Memory usage
Custom Metrics Endpoint
// In lib.rs - custom health endpoint
#[reducer]
pub fn get_server_stats(ctx: &ReducerContext) -> Result<String, String> {
if !is_admin(ctx) {
return Err("Admin only".to_string());
}
let stats = serde_json::json!({
"online_players": ctx.db.player_online().iter().count(),
"total_players": ctx.db.player().iter().count(),
"timestamp": ctx.timestamp,
});
Ok(stats.to_string())
}
Log Management
Loki + Promtail
# docker-compose.yml
services:
loki:
image: grafana/loki:2.9.0
ports:
- "3100:3100"
volumes:
- loki-data:/loki
promtail:
image: grafana/promtail:2.9.0
volumes:
- /var/log:/var/log
- ./promtail-config.yml:/etc/promtail/config.yml
command: -config.file=/etc/promtail/config.yml
Promtail Config
# promtail-config.yml
server:
http_listen_port: 9080
positions:
filename: /tmp/positions.yaml
clients:
- url: http://loki:3100/loki/api/v1/push
scrape_configs:
- job_name: spacetimedb
static_configs:
- targets:
- localhost
labels:
job: spacetimedb
__path__: /var/log/spacetimedb/*.log
Grafana Dashboard
Installatie
docker run -d \
--name grafana \
-p 3002:3000 \
-v grafana-data:/var/lib/grafana \
grafana/grafana
Dashboard JSON
{
"title": "Milena's Treehouse",
"panels": [
{
"title": "Online Players",
"type": "stat",
"datasource": "SpacetimeDB",
"query": "SELECT COUNT(*) FROM player_online"
},
{
"title": "Players Over Time",
"type": "timeseries",
"datasource": "SpacetimeDB",
"query": "..."
}
]
}
Alerts
Alert Regels
| Alert | Conditie | Actie |
|---|---|---|
| Server Down | No response 2min | Discord + SMS |
| High Memory | >80% RAM | Discord |
| Slow Queries | >1s response | Discord |
| Error Spike | >10 errors/min | Discord |
Discord Webhook Script
#!/bin/bash
# alert.sh
WEBHOOK_URL="https://discord.com/api/webhooks/..."
send_alert() {
local title="$1"
local message="$2"
local color="$3"
curl -X POST "$WEBHOOK_URL" \
-H "Content-Type: application/json" \
-d "{
\"embeds\": [{
\"title\": \"$title\",
\"description\": \"$message\",
\"color\": $color
}]
}"
}
# Usage
send_alert "Server Alert" "SpacetimeDB is down!" 16711680
Health Check Script
#!/bin/bash
# healthcheck.sh
SPACETIME_HOST="localhost:3000"
DISCORD_WEBHOOK="..."
check_spacetime() {
nc -z localhost 3000
return $?
}
if ! check_spacetime; then
./alert.sh "SpacetimeDB Down" "Server is not responding" 16711680
# Attempt restart
sudo systemctl restart spacetimedb
sleep 30
if check_spacetime; then
./alert.sh "SpacetimeDB Recovered" "Server is back online" 65280
fi
fi
Cron Job
# Check every minute
* * * * * /home/spacetime/healthcheck.sh
Daily Report
#!/bin/bash
# daily_report.sh
WEBHOOK_URL="..."
# Get stats
ONLINE=$(spacetime sql milenas-treehouse "SELECT COUNT(*) FROM player_online")
TOTAL=$(spacetime sql milenas-treehouse "SELECT COUNT(*) FROM player")
NEW_TODAY=$(spacetime sql milenas-treehouse "SELECT COUNT(*) FROM player WHERE created_at > datetime('now', '-1 day')")
curl -X POST "$WEBHOOK_URL" \
-H "Content-Type: application/json" \
-d "{
\"embeds\": [{
\"title\": \"Daily Report\",
\"fields\": [
{\"name\": \"Online Now\", \"value\": \"$ONLINE\", \"inline\": true},
{\"name\": \"Total Players\", \"value\": \"$TOTAL\", \"inline\": true},
{\"name\": \"New Today\", \"value\": \"$NEW_TODAY\", \"inline\": true}
],
\"color\": 3447003
}]
}"
Best Practices
- Monitor alles - WebSocket, HTTP, database
- Alert slim - Niet te veel, niet te weinig
- Log centraal - Alles naar Loki
- Daily reports - Overzicht houden
- Backups testen - Regelmatig restore test