Monitoring Your Beaver Habits Instance with Vigilmon
Beaver Habits is a self-hosted habit tracker and journal application — track daily habits, build streaks, add notes, and visualize your progress over time. It runs on Python/FastAPI with a Vue.js frontend, typically on port 8080.
The app is deceptively critical infrastructure for its users: streaks break if the reminder scheduler stops firing, and habit completion data is the kind of thing people revisit months later. A silent database failure or a crashed API can mean lost records and broken streaks that can't be reconstructed.
This tutorial sets up production monitoring for Beaver Habits using Vigilmon:
- Web server and API availability
- Database connectivity (PostgreSQL or SQLite)
- Habit API endpoint response times
- Streak calculation service health
- Authentication service monitoring
- Heartbeat monitoring for the daily reminder scheduler
- Data export health
- TLS certificate expiry
- Slack alerting
Step 1: Add a health check endpoint
Beaver Habits runs on FastAPI, which makes adding a health endpoint straightforward.
# app/routes/health.py
from fastapi import APIRouter
from fastapi.responses import JSONResponse
from app.database import get_db_session
from sqlalchemy import text
import os
router = APIRouter()
@router.get("/health")
async def health_check():
checks = {}
# Database connectivity
try:
async with get_db_session() as session:
await session.execute(text("SELECT 1"))
checks["database"] = "ok"
except Exception as e:
checks["database"] = f"error: {str(e)}"
# Check that habit data directory exists (for SQLite setups)
data_dir = os.getenv("DATA_DIR", "/data")
checks["storage"] = "ok" if os.path.isdir(data_dir) else "error"
all_ok = all(v == "ok" for v in checks.values())
return JSONResponse(
content={"status": "ok" if all_ok else "degraded", "checks": checks},
status_code=200 if all_ok else 503,
)
Register the router in your main app:
# app/main.py
from app.routes.health import router as health_router
app.include_router(health_router)
Test it:
curl http://localhost:8080/health
# {"status":"ok","checks":{"database":"ok","storage":"ok"}}
Step 2: Monitor web server availability
Point Vigilmon at your health endpoint:
- Sign up at vigilmon.online
- Click New Monitor → HTTP
- URL:
https://habits.yourdomain.com/health - Check interval: 1 minute
- Expected status: 200
- Save
This catches the most common failure mode: the Python process crashes or the container stops, making the service completely unavailable.
Step 3: Monitor the habits API endpoint
The /api/habits endpoint is the core read path — it powers the main habit list and dashboard.
In Vigilmon, create an HTTP monitor:
- URL:
https://habits.yourdomain.com/api/habits - Expected status: 200 or 401 (depending on whether the endpoint requires auth for listing)
- Response time alert: 2000ms (habits list should be fast; a slow response indicates a database query problem)
If the endpoint requires authentication, monitor the response status from an unauthenticated request:
- Expected status: 401 — a 401 means the server processed the request and auth middleware responded. Any 502, 503, or timeout indicates a real failure.
Step 4: Monitor the habit completion recording endpoint
Habit completion recording (/api/records) is the most write-sensitive endpoint. Users complete habits on their phone and expect the data to be saved. Monitor it with a HEAD or OPTIONS request:
- URL:
https://habits.yourdomain.com/api/records - Method: OPTIONS
- Expected status: 200 or 405
For a deeper functional check, add a synthetic probe:
#!/bin/bash
# probe-habit-record.sh
RESPONSE=$(curl -s -o /dev/null -w "%{http_code}" \
-X POST https://habits.yourdomain.com/api/records \
-H "Authorization: Bearer $PROBE_TOKEN" \
-H "Content-Type: application/json" \
-d '{"habit_id":"probe-habit","date":"2000-01-01","completed":false}')
# Expect 200 (created), 409 (already exists), or 404 (probe habit not found) — all indicate API is alive
if [[ "$RESPONSE" =~ ^(200|409|404)$ ]]; then
curl -s "$VIGILMON_RECORDS_HEARTBEAT_URL" > /dev/null
fi
Step 5: Database connectivity monitoring
Database failures are the most common cause of data loss in self-hosted apps. The health check in Step 1 already tests database connectivity, so your Vigilmon HTTP monitor on /health covers this.
For deeper database monitoring — particularly if you're running PostgreSQL — add a direct TCP port monitor:
In Vigilmon:
- Click New Monitor → TCP
- Host:
localhost(or your DB host) - Port:
5432(PostgreSQL) or leave unconfigured for SQLite (file-based) - Save
A TCP monitor catches cases where PostgreSQL is unreachable even before application-level errors surface.
Step 6: Streak calculation service health
Streak calculation is typically computed on read from the completion records. If the streak calculation is producing wrong results, it won't surface as an HTTP error — users will see incorrect streak counts.
Monitor streak correctness with a functional probe:
#!/usr/bin/env python3
# probe-streak-calculation.py
import requests
import os
import sys
base_url = os.environ["BEAVER_HABITS_URL"]
token = os.environ["PROBE_TOKEN"]
heartbeat_url = os.environ["VIGILMON_STREAK_HEARTBEAT_URL"]
headers = {"Authorization": f"Bearer {token}"}
# Fetch habits and verify streak field is present and numeric
response = requests.get(f"{base_url}/api/habits", headers=headers, timeout=10)
if response.status_code != 200:
sys.exit(1)
habits = response.json()
for habit in habits[:3]: # spot-check first 3 habits
if "streak" not in habit or not isinstance(habit["streak"], int):
sys.exit(1)
# Ping heartbeat — streak calculation is working
requests.get(heartbeat_url, timeout=5)
Schedule this script every 30 minutes and pair it with a Vigilmon heartbeat monitor.
Step 7: Heartbeat monitoring for the daily reminder scheduler
Daily reminders are a core Beaver Habits feature — they're what keeps users coming back to complete their habits. If the reminder scheduler stops, users silently stop getting notifications and streaks break.
Add a heartbeat ping to your reminder job. If you're using APScheduler inside the app:
# app/scheduler.py
import httpx
import os
import logging
logger = logging.getLogger(__name__)
VIGILMON_REMINDER_HEARTBEAT_URL = os.getenv("VIGILMON_REMINDER_HEARTBEAT_URL")
async def send_daily_reminders():
"""Send daily habit reminders to all users."""
try:
# Your existing reminder logic here
await _dispatch_reminders()
# Ping heartbeat on success
if VIGILMON_REMINDER_HEARTBEAT_URL:
async with httpx.AsyncClient() as client:
await client.get(VIGILMON_REMINDER_HEARTBEAT_URL, timeout=5)
except Exception as e:
logger.error(f"Daily reminder dispatch failed: {e}")
# No ping → Vigilmon alerts after the window expires
In Vigilmon:
- Click New Monitor → Heartbeat
- Name:
Beaver Habits Daily Reminder Scheduler - Expected interval: 24 hours
- Grace period: 30 minutes
- Copy the ping URL → set as
VIGILMON_REMINDER_HEARTBEAT_URLenv variable - Save
If the scheduler crashes, users will miss their reminders but won't know why — this heartbeat makes that failure visible to you before it affects them.
Step 8: User authentication service monitoring
JWT-based authentication is the gatekeeper for all user data. Monitor it specifically:
- URL:
https://habits.yourdomain.com/api/auth/login - Method: POST
- Body:
{"username":"probe@example.com","password":"wrongpassword"} - Expected status: 401
A 401 confirms the auth endpoint is alive and processing requests. Any 500, 502, or timeout indicates the authentication layer has failed.
Step 9: Data export service health
Habit history export (CSV/JSON) is the user's backup mechanism. If it fails silently, users discover the problem only when they need their data. Monitor the export endpoint:
- URL:
https://habits.yourdomain.com/api/export - Method: HEAD
- Expected status: 200 or 401
For a functional check, run a weekly export probe:
#!/bin/bash
# probe-export.sh
RESPONSE=$(curl -s -o /dev/null -w "%{http_code}" \
-H "Authorization: Bearer $PROBE_TOKEN" \
https://habits.yourdomain.com/api/export?format=json)
if [ "$RESPONSE" = "200" ]; then
curl -s "$VIGILMON_EXPORT_HEARTBEAT_URL" > /dev/null
fi
Step 10: TLS certificate expiry monitoring
In Vigilmon:
- Go to New Monitor → SSL Certificate
- Domain:
habits.yourdomain.com - Alert thresholds: 30 days (warning) and 7 days (critical)
- Save
Habit trackers are often accessed from mobile apps. A TLS error on mobile will show an opaque "Can't connect" message, and users will assume the app is broken rather than suspecting a certificate issue.
Step 11: Slack alerts
In Vigilmon, go to Notifications → New Channel → Slack and paste your Slack incoming webhook URL.
Enable Slack on all Beaver Habits monitors. Critical alert patterns to watch for:
🔴 DOWN: habits.yourdomain.com/health
Status: 503 Service Unavailable
Detected: 5 minutes ago
🔴 MISSED HEARTBEAT: Beaver Habits Daily Reminder Scheduler
Last ping: 26h 10m ago (expected every 24h)
⚠️ SLOW: habits.yourdomain.com/api/habits
Response time: 3,421ms (threshold: 2,000ms)
The heartbeat miss for the reminder scheduler is the most important — it's the alert that saves your users' streaks.
What you've built
| What | How |
|------|-----|
| Web server health | Vigilmon HTTP monitor → /health |
| Database connectivity | Health endpoint DB check + TCP monitor on port 5432 |
| Habits API response time | HTTP monitor with 2s alert threshold |
| Habit completion API | Synthetic probe + heartbeat |
| Streak calculation | Functional probe every 30 minutes |
| Daily reminder scheduler | Heartbeat monitor, 24-hour expected interval |
| Authentication service | HTTP monitor → /api/auth/login expecting 401 |
| Data export | Probe script + weekly heartbeat |
| TLS certificate | SSL monitor, 30-day + 7-day alert |
| Slack alerts | Vigilmon Slack notification channel |
Your habit tracker keeps your users accountable. Vigilmon keeps your habit tracker accountable.
Next steps
- Add response time history monitoring to catch slow habit queries before they cause timeout errors
- Set up a Vigilmon status page so users know where to check during outages
- If you run Beaver Habits in Docker, add a container health check that feeds into your Vigilmon heartbeat
- Monitor disk usage if you're storing habit data on an SQLite file — file growth can be slow and silent
Get started free at vigilmon.online.