Sitemap
collynes

collynes

Building GlanceWatch: A Lightweight Bridge Between Glances and Uptime Kuma

8 min readNov 12, 2025

How I Built a Zero-Configuration System Monitor That Just Works

— -

TL;DR: I created GlanceWatch, a lightweight Python tool that bridges Glances system metrics with Uptime Kuma monitoring. One command to install, automatic background service, and dead-simple HTTP health checks. Available on PyPI at https://pypi.org/project/glancewatch/

— -

The Problem: Monitoring Should Be Simple

If you’re running servers (production, homelab, or just a Raspberry Pi), you know the drill:

1. Install monitoring tools
2. Configure them (lots of YAML)
3. Set up alerting
4. Hope it works when SSH disconnects
5. Debug why it stopped running

I was using Glances (fantastic system monitor) and Uptime Kuma (beautiful uptime dashboard), but they didn’t talk to each other. I needed a bridge that would:

• Return HTTP 200 when system is healthy
• Return HTTP 503 when CPU/RAM/Disk exceeds thresholds
• Run in the background without babysitting
• Install with a single command
• Just. Freaking. Work.

So I built GlanceWatch.

— -

The Design Philosophy: Zero Configuration

I hate configuration files. I hate services that die when you close your terminal. I hate tools that require 10 steps to get started.

GlanceWatch’s Philosophy:

pip install glancewatch
# Done. It’s running. Forever.

No Docker. No docker-compose.yml. No systemd unit files to debug. Just Python.

— -

The Architecture: Stupid Simple

┌─────────────┐
│ Glances │ ← System metrics (CPU, RAM, Disk)
└──────┬──────┘
│
▼
┌─────────────┐
│ GlanceWatch │ ← Threshold checks + HTTP endpoints
└──────┬──────┘
│
▼
┌─────────────┐
│ Uptime Kuma │ ← Monitors HTTP status codes
└─────────────┘

How it works:

1. Glances collects system metrics (auto-installed, auto-started)
2. GlanceWatch queries Glances API, compares against thresholds
3. Returns HTTP 200 if healthy, HTTP 503 if unhealthy
4. Uptime Kuma monitors the endpoint and sends alerts

— -

The Tech Stack

• FastAPI — Modern, fast Python web framework
• Uvicorn — Lightning-fast ASGI server
• Glances — Cross-platform system monitoring
• Pydantic — Data validation that actually makes sense

Why FastAPI? Because I wanted automatic OpenAPI docs, async support, and Python type hints. No Flask boilerplate.

— -

The Features: What You Get

1. One-Command Background Service

The installer script detects your system and does the right thing:

curl -sSL https://raw.githubusercontent.com/collynes/glancewatch/main/scripts/install-pip.sh | bash

On systemd systems:
• Creates systemd service
• Enables auto-start on boot
• Restarts on crashes
• Logs to journald

On non-systemd systems:
• Uses nohup
• Survives terminal disconnect
• Reports PID for management

No manual intervention. Just works.

2. Router-Style Web UI

Clean, modern interface at http://localhost:8000:

• Real-time metrics dashboard
• Live threshold configuration
• Auto-refresh every 5 seconds
• Dark/light mode toggle
• No JavaScript framework bloat (vanilla JS)

3. Simple HTTP Health Checks

# Check system health
curl http://localhost:8000/status
# Returns 200 if healthy, 503 if any threshold exceeded

# Individual checks
curl http://localhost:8000/ram
curl http://localhost:8000/cpu
curl http://localhost:8000/disk

Uptime Kuma monitors these endpoints. When you get a 503, you get an alert. Simple.

4. Configurable Thresholds

Default thresholds (80% RAM, 80% CPU, 85% disk), but change them via:

• Web UI (pretty sliders)
• REST API (PUT /config)
• Config file (~/.config/glancewatch/config.yaml)

Changes persist. No restart required.

5. Auto-Everything

• Auto-installs Glances if missing
• Auto-starts Glances if not running
• Auto-detects mount points
• Auto-saves config changes
• Auto-restarts on crashes (systemd mode)

You shouldn’t have to think about any of this.

— -

The Journey: From “Works on My Machine” to PyPI

Version 1.0.0–1.0.3: The MVP
• Basic FastAPI app
• Manual Glances management
• Console-only interface
• “Just install it manually”

Version 1.0.4: The Documentation Phase
• Added /docs page with Uptime Kuma setup guide
• Realized users actually read docs (who knew?)

Version 1.0.5: The Production Incident

User report: “UI shows JSON in production”

The bug: UI files weren’t included in the pip package. Local dev worked fine because files were in the repo. Production? Just API responses.

The fix: Moved UI files to app/ui/ package, updated pyproject.toml:

[tool.setuptools]
packages = [“app”, “app.api”, “app.ui”]
include-package-data = true

Lesson learned: Test pip installs in clean environments.

Version 1.0.6: The Professional Polish

User feedback: “is this a professional really” (referring to noisy console logs)

Fair point. Changed default log level from INFO to WARNING:

# Before: Every request logged
INFO: 127.0.0.1:52342 — “GET /status HTTP/1.1” 200
INFO: 127.0.0.1:52343 — “GET /ram HTTP/1.1” 200
# Annoying.

# After: Clean by default
# (use — verbose for debugging, — quiet for silence)

Lesson learned: Users notice the small things.

Version 1.0.7: The Background Service Saga

User report: “once i close terminal it fails”

Of course it does. It’s running in the foreground. But users shouldn’t have to figure out nohup/systemd/screen/tmux.

The solution: Created install-service.sh that:
• Detects systemd availability
• Creates systemd service OR uses nohup
• Verifies startup
• Shows appropriate management commands

Also shipped helper scripts:
• start.sh — Start with nohup
• stop.sh — Kill process
• restart.sh — Restart service

Version 1.0.8: The Version Display Bug

User report: “shows version 1.0.0 but I installed 1.0.7”

The bug: Hardcoded version in app/__init__.py:

__version__ = “1.0.0” # Oops

The fix: Actually update it during releases. Also updated all UI version displays.

Lesson learned: Version strings are easy to forget.

Version 1.0.9: The Full Automation

User request: “can we add nohup glancewatch > /dev/null 2>&1 & to script i want user to install only rest fo setup is automated”

Translation: “I don’t want to type that manual nohup command.”

The solution: Made install-service.sh fully automated:

# Detects system capabilities
if has_systemd; then
install_systemd_service
else
start_with_nohup_automatically # New!
fi

Now it’s truly zero-config. Install and forget.

— -

Get collynes’s stories in your inbox

Join Medium for free to get updates from this writer.

The Real-World Usage

Here’s how I use it on my production Ubuntu server:

# One-time setup
curl -sSL https://raw.githubusercontent.com/collynes/glancewatch/main/scripts/install-pip.sh | bash

# Done. Close terminal. Go to bed.

In Uptime Kuma:
• Monitor type: HTTP(s)
• URL: http://18.209.250.77:8000/status
• Accepted status codes: 200
• Check interval: 60 seconds

When CPU spikes or RAM fills up, Uptime Kuma sends Slack/Discord/Email alerts. Simple.

— -

The Code Quality Journey

Testing

Started with “it works on my machine.” Now:
• 78% code coverage
• 63+ test cases
• Tests for all endpoints
• CLI tests
• Error handling tests
• Integration tests

pytest tests/ — cov=app — cov-report=html

CI/CD

Every push runs:
• Tests on Python 3.8, 3.9, 3.10, 3.11, 3.12
• Linting (ruff)
• Type checking (mypy)
• Coverage checks (minimum 75%)

GitHub Actions badge shows green. Feels good.

Code Quality Tools
• Black — No more formatting debates
• Ruff — Fast linting
• mypy — Type safety
• pytest — Comprehensive testing

— -

The Lessons Learned

1. Users Want Simple

Not “simple for developers.” Simple for humans.

# Too complex
docker-compose up -d
kubectl apply -f deployment.yaml
systemctl enable myservice

# Just right
pip install glancewatch

2. Automatic Is Better Than Manual

Don’t tell users to run nohup … manually. Do it for them.

3. Test in Production Environments

Your local dev setup lies to you. Test pip installs in fresh VMs.

4. Documentation Matters

Users will read docs if they’re clear and concise. Examples > Walls of text.

5. Logging Is a Feature

Default should be quiet. Add — verbose for debugging. Respect the terminal.

6. Version Everything

Code, UI, docs. Keep them in sync. Automate it.

— -

The Technical Deep Dives

How Auto-Glances Works

def ensure_glances_running():
“””Auto-install and start Glances if needed”””

# Check if Glances is installed
if not shutil.which(“glances”):
logger.info(“ Glances not found. Installing…”)
subprocess.run([sys.executable, “-m”, “pip”, “install”, “glances”])

# Check if Glances is running
try:
response = httpx.get(“http://localhost:61208/api/4/system”)
if response.status_code == 200:
logger.info("✓ Glances is already running”)
return
except:
pass

# Start Glances
logger.info(“ Starting Glances in background…”)
subprocess.Popen(
[“glances”, “-w”, “ — disable-plugin”, “now”],
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL
)

# Wait for startup
for _ in range(10):
try:
if httpx.get(“http://localhost:61208/api/4/system”).status_code == 200:
logger.info(“✓ Glances started successfully”)
return
except:
time.sleep(1)

It just works. Install if missing, start if stopped, verify it’s up.

How Threshold Checking Works

@app.get(“/status”)
async def check_status():
“””Combined health check — returns 503 if any threshold exceeded”””

ram = await check_ram()
cpu = await check_cpu()
disk = await check_disk()

# Any check failed? Return 503
if any(check[“status”] != “ok” for check in [ram, cpu, disk]):
return JSONResponse(
status_code=503,
content={
“status”: “unhealthy”,
“ram”: ram,
“cpu”: cpu,
“disk”: disk
}
)

# All good? Return 200
return {
“status”: “healthy”,
“ram”: ram,
“cpu”: cpu,
“disk”: disk
}

Simple logic: Any threshold exceeded? 503. All good? 200. Uptime Kuma handles the rest.

How Config Persistence Works

class Config(BaseSettings):
“””Pydantic settings with YAML persistence”””

glances_base_url: str = “http://localhost:61208/api/4"
port: int = 8000
thresholds: ThresholdConfig = ThresholdConfig()

class Config:
env_prefix = “GLANCEWATCH_”

@classmethod
def load(cls):
“””Load from YAML or create default”””
config_file = Path.home() / “.config/glancewatch/config.yaml”

if config_file.exists():
with open(config_file) as f:
data = yaml.safe_load(f)
return cls(**data)

return cls()

def save(self):
“””Save to YAML”””
config_file = Path.home() / “.config/glancewatch/config.yaml”
config_file.parent.mkdir(parents=True, exist_ok=True)

with open(config_file, ‘w’) as f:
yaml.dump(self.dict(), f)

Pydantic handles validation. YAML handles storage. Users can edit either way.

— -

The Future: What’s Next

Ideas I’m Considering

1. Plugin System
• Custom metrics (GPU, network, temperature)
• Custom alerting logic
• Community plugins

2. Historical Data
• SQLite storage
• Graphs in UI
• Trend analysis

3. Alert Webhooks
• Direct Discord/Slack integration
• No need for Uptime Kuma for simple setups

4. Docker Support
• Official Docker image
• docker-compose example
• Health checks built-in

5. Multi-Server Dashboard
• Monitor multiple servers from one UI
• Centralized alerting
• Fleet management

What I’m NOT Adding

• Complex configuration files (goes against the philosophy)
• Database requirements (SQLite only if historical data)
• Microservices architecture (one process, one purpose)
• JavaScript framework rewrites (vanilla JS is fine)

— -

The Takeaway

Building GlanceWatch taught me that simplicity is hard. It’s easy to build complex tools with lots of features. It’s hard to build tools that “just work.”

The best software:
• Installs with one command
• Runs in the background automatically
• Has sensible defaults
• Needs zero configuration
• Actually works in production

If you’re building dev tools, ask yourself:
• Can a user install it in 30 seconds?
• Does it survive terminal disconnect?
• Are logs quiet by default?
• Does it work on a fresh server?
• Would you use it on your production systems?

— -

Try It Yourself

Install GlanceWatch:

# Automated installer (recommended)
curl -sSL https://raw.githubusercontent.com/collynes/glancewatch/main/scripts/install-pip.sh| bash

# Or just pip
pip install glancewatch
glancewatch

Set up Uptime Kuma monitoring:
1. Add HTTP(s) monitor
2. URL: http://your-server:8000/status
3. Accepted status codes: 200
4. Done!

— -

Links

• PyPI: https://pypi.org/project/glancewatch/
• GitHub: https://github.com/collynes/glanceswatch
• Documentation: Included in dashboard at /docs

— -

Final Thoughts

I built GlanceWatch because I was tired of complex monitoring setups. I wanted something that:
• Installs fast
• Configures itself
• Runs forever
• Alerts when needed

If you’re monitoring Linux servers and using Uptime Kuma (or similar), give it a try. It’s free, open-source, and designed to get out of your way.

And if you’re building your own dev tools, remember: The best tool is the one that just works.

— -

Have questions or suggestions? Open an issue on GitHub or reach out!

Made with ❤️ for simple system monitoring

— -

About the Author

Collins Kemboi is a software engineer who believes monitoring shouldn’t require a PhD. When not building dev tools, he’s probably debugging why his homelab is down (again).

— -

Tags: #Python #DevOps #Monitoring #FastAPI #OpenSource #SystemAdministration #Automation #Linux #ServerMonitoring #UptimeKuma

— -

Discussion Questions

1. What’s your current server monitoring setup?
2. What’s the most annoying part of setting up monitoring?
3. Would you use a tool like this? Why or why not?
4. What features would you want in a monitoring bridge?

Drop your thoughts in the comments!

--

--